Perfect the stop controller for http download

v4
laoyuyu 2 years ago
parent e2d706fbc6
commit e80f2904e1
  1. 20
      Http/src/main/java/com/arialyy/aria/http/ConnectionHelp.java
  2. 4
      Http/src/main/java/com/arialyy/aria/http/HttpBaseStartController.kt
  3. 6
      Http/src/main/java/com/arialyy/aria/http/HttpComponent.kt
  4. 14
      Http/src/main/java/com/arialyy/aria/http/HttpUtil.kt
  5. 2
      Http/src/main/java/com/arialyy/aria/http/download/HttpBlockThreadInterceptor.kt
  6. 5
      Http/src/main/java/com/arialyy/aria/http/download/HttpDBTaskAdapter.kt
  7. 4
      Http/src/main/java/com/arialyy/aria/http/download/HttpDBlockInterceptor.kt
  8. 3
      Http/src/main/java/com/arialyy/aria/http/download/HttpDCTTaskAdapter.kt
  9. 2
      Http/src/main/java/com/arialyy/aria/http/download/HttpDEventListener.kt
  10. 434
      Http/src/main/java/com/arialyy/aria/http/download/HttpDFileInfoTask.java
  11. 51
      Http/src/main/java/com/arialyy/aria/http/download/HttpDLoaderUtil.java
  12. 19
      Http/src/main/java/com/arialyy/aria/http/download/HttpDStartStartController.kt
  13. 47
      Http/src/main/java/com/arialyy/aria/http/download/HttpDStopController.kt
  14. 65
      Http/src/main/java/com/arialyy/aria/http/download/HttpDStopController2.kt
  15. 61
      Http/src/main/java/com/arialyy/aria/http/download/HttpDTTBuilderAdapter.java
  16. 26
      Http/src/main/java/com/arialyy/aria/http/download/HttpDownloader.kt
  17. 3
      PublicComponent/src/main/java/com/arialyy/aria/core/inf/IEntity.java
  18. 46
      PublicComponent/src/main/java/com/arialyy/aria/core/inf/IStopController.kt
  19. 5
      PublicComponent/src/main/java/com/arialyy/aria/core/listener/AbsEventListener.java
  20. 4
      PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsTask.java
  21. 2
      PublicComponent/src/main/java/com/arialyy/aria/core/task/DownloadTask.java
  22. 9
      PublicComponent/src/main/java/com/arialyy/aria/core/task/ITask.java
  23. 36
      PublicComponent/src/main/java/com/arialyy/aria/core/task/TaskCachePool.kt
  24. 37
      PublicComponent/src/main/java/com/arialyy/aria/orm/entity/DEntity.kt
  25. 16
      Queue/src/main/java/com/arialyy/aria/queue/AbsTaskQueue.java
  26. 68
      Schedulers/src/main/java/com/arialyy/aria/schedulers/TaskSchedulers.java

@ -77,26 +77,6 @@ public final class ConnectionHelp {
} }
} }
/**
* 转换HttpUrlConnect的inputStream流
*
* @return {@link GZIPInputStream}{@link InflaterInputStream}
* @throws IOException
*/
public static InputStream convertInputStream(HttpURLConnection connection) throws IOException {
String encoding = connection.getHeaderField("Content-Encoding");
if (TextUtils.isEmpty(encoding)) {
return connection.getInputStream();
}
if (encoding.contains("gzip")) {
return new GZIPInputStream(connection.getInputStream());
} else if (encoding.contains("deflate")) {
return new InflaterInputStream(connection.getInputStream());
} else {
return connection.getInputStream();
}
}
/** /**
* 处理链接 * 处理链接
* *

@ -15,13 +15,11 @@
*/ */
package com.arialyy.aria.http package com.arialyy.aria.http
import com.arialyy.aria.http.download.HttpDownloader
/** /**
* @Author laoyuyu * @Author laoyuyu
* @Description * @Description
* @Date 12:40 PM 2023/1/22 * @Date 12:40 PM 2023/1/22
**/ **/
open class HttpBaseController(val target: Any) { open class HttpBaseStartController(val target: Any) {
} }

@ -1,10 +1,7 @@
package com.arialyy.aria.http package com.arialyy.aria.http
import android.content.Context import android.content.Context
import com.arialyy.aria.core.DuaContext
import com.arialyy.aria.core.inf.IComponentInit import com.arialyy.aria.core.inf.IComponentInit
import com.arialyy.aria.queue.DTaskQueue
import com.arialyy.aria.queue.UTaskQueue
/** /**
* @Author laoyuyu * @Author laoyuyu
@ -13,8 +10,5 @@ import com.arialyy.aria.queue.UTaskQueue
**/ **/
class HttpComponent : IComponentInit { class HttpComponent : IComponentInit {
override fun init(context: Context) { override fun init(context: Context) {
DuaContext.getServiceManager().registerService(DuaContext.D_QUEUE, com.arialyy.aria.queue.DTaskQueue.getInstance())
DuaContext.getServiceManager().registerService(DuaContext.U_QUEUE, com.arialyy.aria.queue.UTaskQueue.getInstance())
} }
} }

@ -15,8 +15,12 @@
*/ */
package com.arialyy.aria.http package com.arialyy.aria.http
import android.net.Uri
import android.text.TextUtils import android.text.TextUtils
import com.arialyy.aria.core.inf.ITaskUtil
import com.arialyy.aria.core.task.TaskCachePool
import com.arialyy.aria.http.download.HttpDTaskOption import com.arialyy.aria.http.download.HttpDTaskOption
import com.arialyy.aria.http.download.HttpDTaskUtil
import com.arialyy.aria.util.FileUtils import com.arialyy.aria.util.FileUtils
import com.arialyy.aria.util.Regular import com.arialyy.aria.util.Regular
import timber.log.Timber import timber.log.Timber
@ -33,6 +37,16 @@ import java.util.zip.InflaterInputStream
* @Date 12:40 PM 2023/1/22 * @Date 12:40 PM 2023/1/22
**/ **/
internal object HttpUtil { internal object HttpUtil {
fun getDTaskUtil(filePath: Uri): ITaskUtil {
var util = TaskCachePool.getTaskUtil(filePath)
if (util == null) {
util = HttpDTaskUtil()
TaskCachePool.putTaskUtil(filePath, util)
}
return util
}
/** /**
* 拦截window.location.replace数据 * 拦截window.location.replace数据
* *

@ -48,7 +48,7 @@ class HttpBlockThreadInterceptor : ITaskInterceptor {
val threadConfig = ThreadConfig(it, option, DuaContext.getDConfig().maxSpeed) val threadConfig = ThreadConfig(it, option, DuaContext.getDConfig().maxSpeed)
threadTaskList.add( threadTaskList.add(
ThreadTask2( ThreadTask2(
adapter = if (option.isChunkTask) HttpDCTTaskAdapter(threadConfig) else HttpDThreadTaskAdapter( adapter = if (option.isChunkTask) HttpDCTTaskAdapter(threadConfig) else HttpDBTaskAdapter(
threadConfig threadConfig
), ),
handler = chain.blockManager.handler, handler = chain.blockManager.handler,

@ -18,6 +18,7 @@ package com.arialyy.aria.http.download
import com.arialyy.aria.core.task.AbsThreadTaskAdapter import com.arialyy.aria.core.task.AbsThreadTaskAdapter
import com.arialyy.aria.core.task.ThreadConfig import com.arialyy.aria.core.task.ThreadConfig
import com.arialyy.aria.http.ConnectionHelp import com.arialyy.aria.http.ConnectionHelp
import com.arialyy.aria.http.HttpUtil
import com.arialyy.aria.http.request.IRequest.Companion.getRequest import com.arialyy.aria.http.request.IRequest.Companion.getRequest
import timber.log.Timber import timber.log.Timber
import java.io.BufferedInputStream import java.io.BufferedInputStream
@ -32,7 +33,7 @@ import java.nio.channels.Channels
* @Description * @Description
* @Date 23:07 PM 2023/2/8 * @Date 23:07 PM 2023/2/8
**/ **/
class HttpDTTaskAdapter(threadConfig: ThreadConfig) : AbsThreadTaskAdapter(threadConfig) { class HttpDBTaskAdapter(threadConfig: ThreadConfig) : AbsThreadTaskAdapter(threadConfig) {
private fun getTaskOption(): HttpDTaskOption { private fun getTaskOption(): HttpDTaskOption {
return threadConfig.option as HttpDTaskOption return threadConfig.option as HttpDTaskOption
@ -54,7 +55,7 @@ class HttpDTTaskAdapter(threadConfig: ThreadConfig) : AbsThreadTaskAdapter(threa
} }
conn.connect() conn.connect()
BufferedInputStream(ConnectionHelp.convertInputStream(conn)).use { BufferedInputStream(HttpUtil.convertInputStream(conn)).use {
readBytes(it) readBytes(it)
} }
} }

@ -92,13 +92,13 @@ internal class HttpDBlockInterceptor : ITaskInterceptor {
*/ */
private suspend fun checkRecord(): Int { private suspend fun checkRecord(): Int {
val recordDao = DuaContext.getServiceManager().getDbService().getDuaDb().getRecordDao() val recordDao = DuaContext.getServiceManager().getDbService().getDuaDb().getRecordDao()
val recordWrapper = recordDao.getTaskRecordByKey(task.taskKey) val recordWrapper = recordDao.getTaskRecordByKey(task.filePath)
if (recordWrapper == null) { if (recordWrapper == null) {
Timber.i("record not found, create record") Timber.i("record not found, create record")
val blockNumInfo = BlockUtil.getBlockNum(task.taskState.fileSize) val blockNumInfo = BlockUtil.getBlockNum(task.taskState.fileSize)
val taskRecord = TaskRecord( val taskRecord = TaskRecord(
taskKey = task.taskKey, taskKey = task.filePath,
filePath = option.savePathUri!!, filePath = option.savePathUri!!,
taskType = ITask.DOWNLOAD, taskType = ITask.DOWNLOAD,
fileLen = task.taskState.fileSize, fileLen = task.taskState.fileSize,

@ -18,6 +18,7 @@ package com.arialyy.aria.http.download
import com.arialyy.aria.core.task.AbsThreadTaskAdapter import com.arialyy.aria.core.task.AbsThreadTaskAdapter
import com.arialyy.aria.core.task.ThreadConfig import com.arialyy.aria.core.task.ThreadConfig
import com.arialyy.aria.http.ConnectionHelp import com.arialyy.aria.http.ConnectionHelp
import com.arialyy.aria.http.HttpUtil
import com.arialyy.aria.http.request.IRequest.Companion.getRequest import com.arialyy.aria.http.request.IRequest.Companion.getRequest
import java.io.BufferedInputStream import java.io.BufferedInputStream
import java.io.FileOutputStream import java.io.FileOutputStream
@ -45,7 +46,7 @@ class HttpDCTTaskAdapter(threadConfig: ThreadConfig) : AbsThreadTaskAdapter(thre
conn.setChunkedStreamingMode(0) conn.setChunkedStreamingMode(0)
conn.connect() conn.connect()
BufferedInputStream(ConnectionHelp.convertInputStream(conn)).use { BufferedInputStream(HttpUtil.convertInputStream(conn)).use {
readBytes(it) readBytes(it)
} }
} }

@ -16,6 +16,7 @@
package com.arialyy.aria.http.download package com.arialyy.aria.http.download
import com.arialyy.aria.core.DuaContext import com.arialyy.aria.core.DuaContext
import com.arialyy.aria.core.inf.IEntity
import com.arialyy.aria.core.listener.AbsEventListener import com.arialyy.aria.core.listener.AbsEventListener
import com.arialyy.aria.core.listener.ISchedulers import com.arialyy.aria.core.listener.ISchedulers
import com.arialyy.aria.core.task.DownloadTask import com.arialyy.aria.core.task.DownloadTask
@ -45,6 +46,7 @@ class HttpDEventListener(task: DownloadTask) : AbsEventListener(task) {
} }
handleSpeed(0) handleSpeed(0)
sendInState2Target(ISchedulers.COMPLETE) sendInState2Target(ISchedulers.COMPLETE)
saveData(IEntity.STATE_COMPLETE, task.taskState.fileSize)
} }
/** /**

@ -1,434 +0,0 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.http.download;
import android.net.TrafficStats;
import android.net.Uri;
import android.os.Process;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.loader.IInfoTask;
import com.arialyy.aria.core.loader.ILoaderVisitor;
import com.arialyy.aria.core.processor.IHttpFileLenAdapter;
import com.arialyy.aria.exception.AriaHTTPException;
import com.arialyy.aria.http.ConnectionHelp;
import com.arialyy.aria.http.HttpTaskOption;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.FileUtils;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.FileUtil;
import com.arialyy.aria.util.RecordUtil;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.CookieManager;
import java.net.HttpCookie;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
* 下载文件信息获取
*/
final class HttpDFileInfoTask implements IInfoTask, Runnable {
private static final String TAG = "HttpDFileInfoTask";
private DownloadEntity mEntity;
private DTaskWrapper mTaskWrapper;
private int mConnectTimeOut;
private Callback callback;
private HttpTaskOption taskOption;
private boolean isStop = false, isCancel = false;
HttpDFileInfoTask(DTaskWrapper taskWrapper) {
this.mTaskWrapper = taskWrapper;
mEntity = taskWrapper.getEntity();
mConnectTimeOut = AriaConfig.getInstance().getDConfig().getConnectTimeOut();
taskOption = (HttpTaskOption) taskWrapper.getTaskOption();
}
@Override public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
TrafficStats.setThreadStatsTag(UUID.randomUUID().toString().hashCode());
HttpURLConnection conn = null;
try {
URL url = ConnectionHelp.handleUrl(mEntity.getUrl(), taskOption);
conn = ConnectionHelp.handleConnection(url, taskOption);
ConnectionHelp.setConnectParam(taskOption, conn);
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
if (AriaConfig.getInstance().getDConfig().isUseHeadRequest()) {
ALog.d(TAG, "head请求");
conn.setRequestMethod("HEAD");
}
conn.setConnectTimeout(mConnectTimeOut);
conn.connect();
handleConnect(conn);
} catch (IOException e) {
failDownload(new AriaHTTPException(
String.format("下载失败,filePath: %s, url: %s", mEntity.getFilePath(), mEntity.getUrl()),
e), true);
} finally {
if (conn != null) {
try {
InputStream is = conn.getInputStream();
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
conn.disconnect();
}
}
}
@Override public void setCallback(Callback callback) {
this.callback = callback;
}
@Override public void stop() {
isStop = true;
}
@Override public void cancel() {
isCancel = true;
}
private void handleConnect(HttpURLConnection conn) throws IOException {
if (taskOption.getRequestEnum() == RequestEnum.POST) {
Map<String, String> params = taskOption.getParams();
if (params != null) {
OutputStreamWriter dos = new OutputStreamWriter(conn.getOutputStream());
Set<String> keys = params.keySet();
StringBuilder sb = new StringBuilder();
for (String key : keys) {
sb.append(key).append("=").append(URLEncoder.encode(params.get(key))).append("&");
}
String url = sb.toString();
url = url.substring(0, url.length() - 1);
dos.write(url);
dos.flush();
dos.close();
}
}
IHttpFileLenAdapter lenAdapter = taskOption.getFileLenAdapter();
if (lenAdapter == null) {
lenAdapter = new FileLenAdapter();
} else {
ALog.d(TAG, "使用自定义adapter");
}
long len = lenAdapter.handleFileLen(conn.getHeaderFields());
if (!FileUtil.checkMemorySpace(mEntity.getFilePath(), len)) {
failDownload(new AriaHTTPException(
String.format("下载失败,内存空间不足;filePath: %s, url: %s", mEntity.getFilePath(),
mEntity.getUrl())), false);
return;
}
int code = conn.getResponseCode();
boolean end = false;
if (TextUtils.isEmpty(mEntity.getMd5Code())) {
String md5Code = conn.getHeaderField("Content-MD5");
mEntity.setMd5Code(md5Code);
}
boolean isChunked = false;
final String str = conn.getHeaderField("Transfer-Encoding");
if (!TextUtils.isEmpty(str) && str.equals("chunked")) {
isChunked = true;
}
Map<String, List<String>> headers = conn.getHeaderFields();
String disposition = conn.getHeaderField("Content-Disposition");
if (taskOption.isUseServerFileName()) {
if (!TextUtils.isEmpty(disposition)) {
mEntity.setDisposition(CommonUtil.encryptBASE64(disposition));
handleContentDisposition(disposition);
} else {
if (taskOption.getFileNameAdapter() != null) {
String newName =
taskOption.getFileNameAdapter().handleFileName(headers, mEntity.getKey());
mEntity.setServerFileName(newName);
renameFile(newName);
}
}
}
CookieManager msCookieManager = new CookieManager();
List<String> cookiesHeader = headers.get("Set-Cookie");
if (cookiesHeader != null) {
for (String cookie : cookiesHeader) {
msCookieManager.getCookieStore().add(null, HttpCookie.parse(cookie).get(0));
}
taskOption.setCookieManager(msCookieManager);
}
mTaskWrapper.setCode(code);
if (code == HttpURLConnection.HTTP_PARTIAL) {
if (!checkLen(len) && !isChunked) {
if (len < 0) {
failDownload(
new AriaHTTPException(String.format("任务下载失败,文件长度小于0, url: %s", mEntity.getUrl())),
false);
}
return;
}
mEntity.setFileSize(len);
mTaskWrapper.setSupportBP(true);
end = true;
} else if (code == HttpURLConnection.HTTP_OK) {
String contentType = conn.getHeaderField("Content-Type");
if (TextUtils.isEmpty(contentType)) {
if (!checkLen(len) && !isChunked) {
if (len < 0) {
failDownload(
new AriaHTTPException(String.format("任务下载失败,文件长度小于0, url: %s", mEntity.getUrl())),
false);
}
return;
}
mEntity.setFileSize(len);
mTaskWrapper.setSupportBP(true);
doNext(code, isChunked);
return;
}
if (contentType.equals("text/html")) {
BufferedReader reader =
new BufferedReader(new InputStreamReader(ConnectionHelp.convertInputStream(conn)));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
reader.close();
handleUrlReTurn(conn, CommonUtil.getWindowReplaceUrl(sb.toString()));
return;
} else if (!checkLen(len) && !isChunked) {
if (len < 0) {
failDownload(
new AriaHTTPException(
String.format("任务下载失败,文件长度小于0, url: %s", mEntity.getUrl())),
false);
}
ALog.d(TAG, "len < 0");
return;
}
mEntity.setFileSize(len);
mTaskWrapper.setNewTask(true);
mTaskWrapper.setSupportBP(false);
end = true;
} else if (code == HttpURLConnection.HTTP_MOVED_TEMP
|| code == HttpURLConnection.HTTP_MOVED_PERM
|| code == HttpURLConnection.HTTP_SEE_OTHER
|| code == HttpURLConnection.HTTP_CREATED // 201 跳转
|| code == 307) {
handleUrlReTurn(conn, conn.getHeaderField("Location"));
} else if (code == 416) { // 处理0k长度的文件的情况
ALog.w(TAG, "文件长度为0,不支持断点");
mTaskWrapper.setSupportBP(false);
mTaskWrapper.setNewTask(true);
end = true;
} else if (code >= HttpURLConnection.HTTP_BAD_REQUEST) {
failDownload(new AriaHTTPException(
String.format("任务下载失败,errorCode:%s, url: %s", code, mEntity.getUrl())), false);
} else {
failDownload(new AriaHTTPException(
String.format("任务下载失败,errorCode:%s, errorMsg: %s, url: %s", code,
conn.getResponseMessage(), mEntity.getUrl())), !FileUtils.httpIsBadRequest(code));
}
if (end) {
doNext(code, isChunked);
}
}
private void doNext(int code, boolean isChunked) {
if (isStop || isCancel) {
return;
}
taskOption.setChunked(isChunked);
CompleteInfo info = new CompleteInfo(code, mTaskWrapper);
callback.onSucceed(mEntity.getUrl(), info);
mEntity.update();
}
/**
* 处理"Content-Disposition"参数
* <a href=https://cloud.tencent.com/developer/section/1189916>Content-Disposition</a></>
*
* @throws UnsupportedEncodingException
*/
private void handleContentDisposition(String disposition) throws UnsupportedEncodingException {
if (disposition.contains(";")) {
String[] infos = disposition.split(";");
if (infos[0].equals("attachment")) {
for (String info : infos) {
if (info.startsWith("filename") && info.contains("=")) {
String[] temp = info.split("=");
if (temp.length > 1) {
String newName = URLDecoder.decode(temp[1], "utf-8").replaceAll("\"", "");
mEntity.setServerFileName(newName);
renameFile(newName);
break;
}
}
}
} else if (infos[0].equals("form-data") && infos.length > 2) {
String[] temp = infos[2].split("=");
if (temp.length > 1) {
String newName = URLDecoder.decode(temp[1], "utf-8").replaceAll("\"", "");
mEntity.setServerFileName(newName);
renameFile(newName);
}
} else {
ALog.w(TAG, "不识别的Content-Disposition参数");
}
}
}
/**
* 重命名文件
*/
private void renameFile(String newName) {
if (TextUtils.isEmpty(newName)) {
ALog.w(TAG, "重命名失败【服务器返回的文件名为空】");
return;
}
ALog.d(TAG, String.format("文件重命名为:%s", newName));
File oldFile = new File(mEntity.getFilePath());
String newPath = oldFile.getParent() + "/" + newName;
if (!FileUtils.checkDPathConflicts(false, newPath, mTaskWrapper.getRequestType())) {
ALog.e(TAG, "文件重命名失败");
return;
}
if (oldFile.exists()) {
boolean b = oldFile.renameTo(new File(newPath));
ALog.d(TAG, String.format("文件重命名%s", b ? "成功" : "失败"));
}
mEntity.setFileName(newName);
mEntity.setFilePath(newPath);
RecordUtil.modifyTaskRecord(oldFile.getPath(), newPath, mEntity.getTaskType());
}
/**
* 处理30x跳转
*/
private void handleUrlReTurn(HttpURLConnection conn, String newUrl) throws IOException {
ALog.d(TAG, "30x跳转,新url为【" + newUrl + "】");
if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null")) {
if (callback != null) {
callback.onFail(mEntity, new AriaHTTPException("获取重定向链接失败"), false);
}
return;
}
if (newUrl.startsWith("/")) {
Uri uri = Uri.parse(mEntity.getUrl());
newUrl = uri.getHost() + newUrl;
}
if (!FileUtils.checkUrl(newUrl)) {
failDownload(new AriaHTTPException("下载失败,重定向url错误"), false);
return;
}
taskOption.setRedirectUrl(newUrl);
mEntity.setRedirect(true);
mEntity.setRedirectUrl(newUrl);
String cookies = conn.getHeaderField("Set-Cookie");
conn.disconnect();
URL url = ConnectionHelp.handleUrl(newUrl, taskOption);
conn = ConnectionHelp.handleConnection(url, taskOption);
ConnectionHelp.setConnectParam(taskOption, conn);
conn.setRequestProperty("Cookie", cookies);
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
if (AriaConfig.getInstance().getDConfig().isUseHeadRequest()) {
conn.setRequestMethod("HEAD");
}
conn.setConnectTimeout(mConnectTimeOut);
conn.connect();
handleConnect(conn);
conn.disconnect();
}
/**
* 检查长度是否合法并且检查新获取的文件长度是否和数据库的文件长度一直如果不一致则表示该任务为新任务
*
* @param len 从服务器获取的文件长度
* @return {@code true}合法
*/
private boolean checkLen(long len) {
if (len != mEntity.getFileSize()) {
ALog.d(TAG, "长度不一致,任务为新任务");
mTaskWrapper.setNewTask(true);
}
return true;
}
private void failDownload(AriaHTTPException e, boolean needRetry) {
if (isStop || isCancel) {
return;
}
if (callback != null) {
callback.onFail(mEntity, e, needRetry);
}
}
@Override public void accept(ILoaderVisitor visitor) {
visitor.addComponent(this);
}
private static class FileLenAdapter implements IHttpFileLenAdapter {
@Override public long handleFileLen(Map<String, List<String>> headers) {
if (headers == null || headers.isEmpty()) {
ALog.e(TAG, "header为空,获取文件长度失败");
return -1;
}
List<String> sLength = headers.get("Content-Length");
if (sLength == null || sLength.isEmpty()) {
return -1;
}
String temp = sLength.get(0);
long len = TextUtils.isEmpty(temp) ? -1 : Long.parseLong(temp);
// 某些服务,如果设置了conn.setRequestProperty("Range", "bytes=" + 0 + "-");
// 会返回 Content-Range: bytes 0-225427911/225427913
if (len < 0) {
List<String> sRange = headers.get("Content-Range");
if (sRange == null || sRange.isEmpty()) {
len = -1;
} else {
int start = temp.indexOf("/");
len = Long.parseLong(temp.substring(start + 1));
}
}
return len;
}
}
}

@ -1,51 +0,0 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.http.download;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.loader.AbsNormalLoader;
import com.arialyy.aria.core.loader.AbsNormalLoaderUtil;
import com.arialyy.aria.core.loader.LoaderStructure;
import com.arialyy.aria.core.loader.NormalLoader;
import com.arialyy.aria.core.loader.NormalTTBuilder;
import com.arialyy.aria.core.loader.TaskThreadStateManager;
import com.arialyy.aria.http.HttpRecordHandler;
import com.arialyy.aria.http.HttpTaskOption;
/**
* @author lyy
* Date: 2019-09-21
*/
public final class HttpDLoaderUtil extends AbsNormalLoaderUtil {
@Override public AbsNormalLoader getLoader() {
if (mLoader == null){
getTaskWrapper().generateTaskOption(HttpTaskOption.class);
mLoader = new NormalLoader(getTaskWrapper(), getListener());
}
return mLoader;
}
public LoaderStructure BuildLoaderStructure() {
LoaderStructure structure = new LoaderStructure();
structure.addComponent(new HttpRecordHandler(getTaskWrapper()))
.addComponent(new TaskThreadStateManager(getListener()))
.addComponent(new HttpDFileInfoTask((DTaskWrapper) getTaskWrapper()))
.addComponent(new NormalTTBuilder(getTaskWrapper(), new HttpDTTBuilderAdapter()));
structure.accept(getLoader());
return structure;
}
}

@ -24,7 +24,7 @@ import com.arialyy.aria.core.processor.IHttpFileLenAdapter
import com.arialyy.aria.core.task.DownloadTask import com.arialyy.aria.core.task.DownloadTask
import com.arialyy.aria.core.task.ITaskInterceptor import com.arialyy.aria.core.task.ITaskInterceptor
import com.arialyy.aria.core.task.TaskCachePool import com.arialyy.aria.core.task.TaskCachePool
import com.arialyy.aria.http.HttpBaseController import com.arialyy.aria.http.HttpBaseStartController
import com.arialyy.aria.http.HttpOption import com.arialyy.aria.http.HttpOption
import com.arialyy.aria.http.HttpUtil import com.arialyy.aria.http.HttpUtil
import com.arialyy.aria.orm.entity.DEntity import com.arialyy.aria.orm.entity.DEntity
@ -37,7 +37,7 @@ import java.net.HttpURLConnection
* @Description * @Description
* @Date 12:38 PM 2023/1/22 * @Date 12:38 PM 2023/1/22
**/ **/
class HttpDStartController(target: Any, val url: String) : HttpBaseController(target), class HttpDStartStartController(target: Any, val url: String) : HttpBaseStartController(target),
IStartController { IStartController {
private var httpDTaskOption = HttpDTaskOption() private var httpDTaskOption = HttpDTaskOption()
@ -50,7 +50,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta
* use multi-threaded download file, if file size <= 5m, this setting is not valid * use multi-threaded download file, if file size <= 5m, this setting is not valid
* @param threadNum range [1 - 32] * @param threadNum range [1 - 32]
*/ */
fun setThreadNum(threadNum: Int): HttpDStartController { fun setThreadNum(threadNum: Int): HttpDStartStartController {
if (threadNum !in 1..32) { if (threadNum !in 1..32) {
Timber.e("set thread num fail, only 0 < threadNum < 33, threadNum: $threadNum") Timber.e("set thread num fail, only 0 < threadNum < 33, threadNum: $threadNum")
return this return this
@ -62,7 +62,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta
/** /**
* set http params, link Header * set http params, link Header
*/ */
fun setHttpOption(httpOption: HttpOption): HttpDStartController { fun setHttpOption(httpOption: HttpOption): HttpDStartStartController {
httpDTaskOption.httpOption = httpOption httpDTaskOption.httpOption = httpOption
return this return this
} }
@ -70,7 +70,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta
/** /**
* Maybe the server has special rules, you need set [IHttpFileLenAdapter] to get the file length from [HttpURLConnection.getHeaderFields] * Maybe the server has special rules, you need set [IHttpFileLenAdapter] to get the file length from [HttpURLConnection.getHeaderFields]
*/ */
fun setHttpFileLenAdapter(adapter: IHttpFileLenAdapter): HttpDStartController { fun setHttpFileLenAdapter(adapter: IHttpFileLenAdapter): HttpDStartStartController {
httpDTaskOption.fileSizeAdapter = adapter httpDTaskOption.fileSizeAdapter = adapter
return this return this
} }
@ -79,7 +79,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta
* if you want to do something before the task is executed, you can set up a task interceptor * if you want to do something before the task is executed, you can set up a task interceptor
* eg: determine the network status before task execution * eg: determine the network status before task execution
*/ */
fun setTaskInterceptor(taskInterceptor: ITaskInterceptor): HttpDStartController { fun setTaskInterceptor(taskInterceptor: ITaskInterceptor): HttpDStartStartController {
httpDTaskOption.taskInterceptor.add(taskInterceptor) httpDTaskOption.taskInterceptor.add(taskInterceptor)
return this return this
} }
@ -87,7 +87,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta
/** /**
* set download listener * set download listener
*/ */
fun setListener(listener: HttpDownloadListener): HttpDStartController { fun setListener(listener: HttpDownloadListener): HttpDStartStartController {
DuaContext.getLifeManager().addCustomListener(target, listener) DuaContext.getLifeManager().addCustomListener(target, listener)
return this return this
} }
@ -95,7 +95,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta
/** /**
* set file save path, eg: /mnt/sdcard/Downloads/test.zip * set file save path, eg: /mnt/sdcard/Downloads/test.zip
*/ */
fun setSavePath(savePath: Uri): HttpDStartController { fun setSavePath(savePath: Uri): HttpDStartStartController {
httpDTaskOption.savePathUri = savePath httpDTaskOption.savePathUri = savePath
return this return this
} }
@ -104,7 +104,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta
if (HttpUtil.checkHttpDParams(httpDTaskOption)) { if (HttpUtil.checkHttpDParams(httpDTaskOption)) {
throw IllegalArgumentException("invalid params") throw IllegalArgumentException("invalid params")
} }
val savePath = httpDTaskOption.savePathUri!!.toString() val savePath = httpDTaskOption.savePathUri!!
var util = TaskCachePool.getTaskUtil(savePath) var util = TaskCachePool.getTaskUtil(savePath)
if (util == null) { if (util == null) {
util = HttpDTaskUtil() util = HttpDTaskUtil()
@ -115,6 +115,7 @@ class HttpDStartController(target: Any, val url: String) : HttpBaseController(ta
val dEntity = findDEntityBySavePath(httpDTaskOption) val dEntity = findDEntityBySavePath(httpDTaskOption)
TaskCachePool.putEntity(task.taskId, dEntity) TaskCachePool.putEntity(task.taskId, dEntity)
} }
TaskCachePool.putTask(task)
return task return task
} }

@ -0,0 +1,47 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.http.download
import android.net.Uri
import com.arialyy.aria.core.task.TaskCachePool
import timber.log.Timber
/**
* @Author laoyuyu
* @Description
* @Date 20:25 2023/2/19
**/
class HttpDStopController(val taskId: Int) {
fun cancel() {
val task = TaskCachePool.getTask(taskId)
if (task == null) {
Timber.e("task not found, taskId: $taskId")
return
}
HttpDStopController2(Uri.parse(task.filePath)).cancel()
}
fun stop() {
val task = TaskCachePool.getTask(taskId)
if (task == null) {
Timber.e("task not found, taskId: $taskId")
return
}
HttpDStopController2(Uri.parse(task.filePath)).stop()
}
}

@ -0,0 +1,65 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.http.download
import android.net.Uri
import com.arialyy.aria.core.DuaContext
import com.arialyy.aria.http.HttpUtil
import com.arialyy.aria.util.FileUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
/**
* @Author laoyuyu
* @Description
* @Date 20:25 2023/2/19
**/
class HttpDStopController2(val filePath: Uri) {
private suspend fun checkUri(): Boolean {
if (!FileUtils.uriEffective(filePath)) {
Timber.e("invalid uri: $filePath")
return false
}
return withContext(Dispatchers.IO) {
val entity = DuaContext.getServiceManager().getDbService().getDuaDb().getDEntityDao()
.getDEntityBySavePath(filePath.toString())
if (entity == null) {
Timber.e("No found task, uri: $filePath")
return@withContext false
}
return@withContext true
}
}
fun cancel() {
DuaContext.duaScope.launch {
if (checkUri()) {
HttpUtil.getDTaskUtil(filePath).cancel()
}
}
}
fun stop() {
DuaContext.duaScope.launch {
if (checkUri()) {
HttpUtil.getDTaskUtil(filePath).stop()
}
}
}
}

@ -1,61 +0,0 @@
package com.arialyy.aria.http.download;
import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.loader.AbsNormalTTBuilderAdapter;
import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.task.IThreadTaskAdapter;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile;
import com.arialyy.aria.util.FileUtil;
import java.io.File;
import java.io.IOException;
final class HttpDTTBuilderAdapter extends AbsNormalTTBuilderAdapter {
@Override public IThreadTaskAdapter getAdapter(SubThreadConfig config) {
return new HttpDThreadTaskAdapter(config);
}
@Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) {
if (!record.isBlock) {
if (getTempFile().exists()) {
FileUtil.deleteFile(getTempFile());
}
} else {
for (int i = 0; i < totalThreadNum; i++) {
File blockFile =
new File(String.format(IRecordHandler.SUB_PATH, getTempFile().getPath(), i));
if (blockFile.exists()) {
ALog.d(TAG, String.format("分块【%s】已经存在,将删除该分块", i));
FileUtil.deleteFile(blockFile);
}
}
}
BufferedRandomAccessFile file = null;
try {
if (totalThreadNum > 1 && !record.isBlock) {
file = new BufferedRandomAccessFile(getTempFile().getPath(), "rwd", 8192);
//设置文件长度
file.setLength(getEntity().getFileSize());
}
if (getTempFile().exists()) {
FileUtil.deleteFile(getTempFile());
}
return true;
} catch (IOException e) {
e.printStackTrace();
ALog.e(TAG, String.format("下载失败,filePath: %s, url: %s", getEntity().getFilePath(),
getEntity().getUrl()));
} finally {
if (file != null) {
try {
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
}
}

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.http.download package com.arialyy.aria.http.download
import android.net.Uri
import com.arialyy.annotations.TaskEnum import com.arialyy.annotations.TaskEnum
import com.arialyy.annotations.TaskEnum.DOWNLOAD import com.arialyy.annotations.TaskEnum.DOWNLOAD
import com.arialyy.aria.core.inf.IDownloader import com.arialyy.aria.core.inf.IDownloader
@ -30,7 +31,28 @@ class HttpDownloader(val target: Any) : IDownloader {
return DOWNLOAD return DOWNLOAD
} }
fun load(url: String): HttpDStartController { /**
return HttpDStartController(target, url) * start, create a task
* @param url download url
*/
fun load(url: String): HttpDStartStartController {
return HttpDStartStartController(target, url)
} }
/**
* stop, cancel a task
* @param taskId taskId
*/
fun load(taskId: Int): HttpDStopController {
return HttpDStopController(taskId)
}
/**
* stop, cancel a task
* @param filePath filePath
*/
fun load(filePath: Uri): HttpDStopController2 {
return HttpDStopController2(filePath)
}
} }

@ -15,12 +15,13 @@
*/ */
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.inf;
import android.os.Parcelable;
import androidx.room.Ignore; import androidx.room.Ignore;
/** /**
* Created by lyy on 2017/2/23. * Created by lyy on 2017/2/23.
*/ */
public interface IEntity { public interface IEntity extends Parcelable {
/** /**
* 其它状态 * 其它状态
*/ */

@ -0,0 +1,46 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.core.inf
import android.net.Uri
/**
* @Author laoyuyu
* @Description
* @Date 20:26 2023/2/19
**/
interface IStopController {
/**
* remove a task
*/
fun cancel(taskId: Int)
/**
* remove task by file path
*/
fun cancelByFilePath(filePath: Uri)
/**
* stop a task
*/
fun stop(taskId: Int)
/**
* remove task by file path
*/
fun stopByFilePath(filePath: Uri)
}

@ -26,7 +26,6 @@ import com.arialyy.aria.core.task.TaskState;
import com.arialyy.aria.exception.AriaException; import com.arialyy.aria.exception.AriaException;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.ErrorHelp; import com.arialyy.aria.util.ErrorHelp;
import java.lang.ref.WeakReference;
import timber.log.Timber; import timber.log.Timber;
public abstract class AbsEventListener implements IEventListener { public abstract class AbsEventListener implements IEventListener {
@ -142,8 +141,12 @@ public abstract class AbsEventListener implements IEventListener {
if (state == IEntity.STATE_CANCEL) { if (state == IEntity.STATE_CANCEL) {
handleCancel(); handleCancel();
TaskCachePool.INSTANCE.removeTask(getTask().getTaskId());
return; return;
} }
if (state == IEntity.STATE_COMPLETE || state == IEntity.STATE_STOP) {
TaskCachePool.INSTANCE.removeTask(getTask().getTaskId());
}
TaskCachePool.INSTANCE.updateState(mTask.getTaskId(), state, location); TaskCachePool.INSTANCE.updateState(mTask.getTaskId(), state, location);
} }

@ -218,7 +218,7 @@ public abstract class AbsTask implements ITask {
* @return {@code true}任务已经取消 * @return {@code true}任务已经取消
*/ */
@Override @Override
public boolean isCancel() { public boolean isCanceled() {
return isCancel; return isCancel;
} }
@ -228,7 +228,7 @@ public abstract class AbsTask implements ITask {
* @return {@code true}任务已经停止 * @return {@code true}任务已经停止
*/ */
@Override @Override
public boolean isStop() { public boolean isStopped() {
return isStop; return isStop;
} }

@ -46,7 +46,7 @@ public class DownloadTask extends AbsTask {
return ITask.DOWNLOAD; return ITask.DOWNLOAD;
} }
@Override public String getTaskKey() { @Override public String getFilePath() {
return Objects.requireNonNull(getTaskOption(DTaskOption.class).getSavePathUri()).toString(); return Objects.requireNonNull(getTaskOption(DTaskOption.class).getSavePathUri()).toString();
} }
} }

@ -99,14 +99,14 @@ public interface ITask {
* *
* @return {@code true}任务已经停止 * @return {@code true}任务已经停止
*/ */
boolean isStop(); boolean isStopped();
/** /**
* 任务是否取消了 * 任务是否取消了
* *
* @return {@code true}任务已经取消 * @return {@code true}任务已经取消
*/ */
boolean isCancel(); boolean isCanceled();
/** /**
* 任务的调度类型 * 任务的调度类型
@ -116,7 +116,10 @@ public interface ITask {
int getTaskId(); int getTaskId();
String getTaskKey(); /**
* @return task unique identifier, like: savePath
*/
String getFilePath();
<T extends ITaskOption> T getTaskOption(Class<T> clazz); <T extends ITaskOption> T getTaskOption(Class<T> clazz);
} }

@ -15,10 +15,12 @@
*/ */
package com.arialyy.aria.core.task package com.arialyy.aria.core.task
import android.net.Uri
import com.arialyy.aria.core.inf.BaseEntity import com.arialyy.aria.core.inf.BaseEntity
import com.arialyy.aria.core.inf.IEntity import com.arialyy.aria.core.inf.IEntity
import com.arialyy.aria.core.inf.ITaskUtil import com.arialyy.aria.core.inf.ITaskUtil
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.ConcurrentHashMap
/** /**
* @Author laoyuyu * @Author laoyuyu
@ -29,25 +31,35 @@ object TaskCachePool {
/** /**
* key: taskId * key: taskId
*/ */
private val entityMap = hashMapOf<Int, BaseEntity>() private val entityMap = ConcurrentHashMap<Int, BaseEntity>()
private val taskUtilMap = hashMapOf<String, ITaskUtil>() private val taskUtilMap = ConcurrentHashMap<Uri, ITaskUtil>()
private val taskMap = ConcurrentHashMap<Int, ITask>()
fun removeTask(taskId: Int) {
taskMap.remove(taskId)
}
/** /**
* @param taskKey task unique identifier, like: savePath, sourceUrl * if task is completed, stopped, canceled, return null
*/ */
fun putTaskUtil(taskKey: String, taskUtil: ITaskUtil) { fun getTask(taskId: Int) = taskMap[taskId]
if (taskKey.isEmpty()) {
Timber.e("invalid taskKey: $taskKey") fun putTask(task: ITask) {
return taskMap[task.taskId] = task
} }
taskUtilMap[taskKey] = taskUtil
/**
* @param filePath task unique identifier, like: savePath, sourceUrl
*/
fun putTaskUtil(filePath: Uri, taskUtil: ITaskUtil) {
taskUtilMap[filePath] = taskUtil
} }
/** /**
* @param taskKey task unique identifier, like: savePath, sourceUrl * @param filePath unique identifier, like: savePath, sourceUrl
*/ */
fun getTaskUtil(taskKey: String): ITaskUtil? { fun getTaskUtil(filePath: Uri): ITaskUtil? {
return taskUtilMap[taskKey] return taskUtilMap[filePath]
} }
fun putEntity(taskId: Int, entity: BaseEntity) { fun putEntity(taskId: Int, entity: BaseEntity) {

@ -16,6 +16,8 @@
package com.arialyy.aria.orm.entity package com.arialyy.aria.orm.entity
import android.net.Uri import android.net.Uri
import android.os.Parcel
import android.os.Parcelable.Creator
import androidx.room.Entity import androidx.room.Entity
import androidx.room.Index import androidx.room.Index
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
@ -53,6 +55,17 @@ data class DEntity(
val fileSize: Long = 0 val fileSize: Long = 0
) : BaseEntity() { ) : BaseEntity() {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readInt(),
parcel.readString()!!,
parcel.readParcelable(Uri::class.java.classLoader)!!,
parcel.readString(),
parcel.readByte() != 0.toByte(),
parcel.readLong()
) {
}
override fun update() { override fun update() {
updateTime = System.currentTimeMillis() updateTime = System.currentTimeMillis()
DuaContext.duaScope.launch(Dispatchers.IO) { DuaContext.duaScope.launch(Dispatchers.IO) {
@ -60,4 +73,28 @@ data class DEntity(
.update(this@DEntity) .update(this@DEntity)
} }
} }
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(did)
parcel.writeInt(parentId)
parcel.writeString(sourceUrl)
parcel.writeParcelable(savePath, flags)
parcel.writeString(ext)
parcel.writeByte(if (isSub) 1 else 0)
parcel.writeLong(fileSize)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Creator<DEntity> {
override fun createFromParcel(parcel: Parcel): DEntity {
return DEntity(parcel)
}
override fun newArray(size: Int): Array<DEntity?> {
return arrayOfNulls(size)
}
}
} }

@ -20,8 +20,8 @@ import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.IPool; import com.arialyy.aria.core.inf.IPool;
import com.arialyy.aria.core.inf.ITaskQueue; import com.arialyy.aria.core.inf.ITaskQueue;
import com.arialyy.aria.core.inf.TaskSchedulerType; import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.task.ThreadTaskManager2;
import com.arialyy.aria.core.task.ITask; import com.arialyy.aria.core.task.ITask;
import com.arialyy.aria.core.task.ThreadTaskManager2;
import timber.log.Timber; import timber.log.Timber;
/** /**
@ -65,17 +65,17 @@ public abstract class AbsTaskQueue<TASK extends ITask> implements ITaskQueue<TAS
} }
/** /**
* @return if cachePool or exePool has task, return true, otherwise false * @return if exePool has task, return true, otherwise false
*/ */
@Override public boolean taskIsRunning(int taskId) { @Override public boolean taskIsRunning(int taskId) {
if (getCachePool().getTask(taskId) != null) { if (getExePool().getTask(taskId) != null) {
return true; return true;
} }
TASK task = getExePool().getTask(taskId); boolean b = ThreadTaskManager2.INSTANCE.taskIsRunning(taskId);
if (task == null && ThreadTaskManager2.INSTANCE.taskIsRunning(taskId)) { if (b) {
ThreadTaskManager2.INSTANCE.stopThreadTask(taskId); ThreadTaskManager2.INSTANCE.stopThreadTask(taskId, false);
} }
return task != null && task.isRunning() && taskExists(taskId); return false;
} }
@Override public int startTask(TASK task) { @Override public int startTask(TASK task) {
@ -168,7 +168,7 @@ public abstract class AbsTaskQueue<TASK extends ITask> implements ITaskQueue<TAS
getCachePool().removeTask(task.getTaskId()); getCachePool().removeTask(task.getTaskId());
getExePool().removeTask(task.getTaskId()); getExePool().removeTask(task.getTaskId());
if (ThreadTaskManager2.INSTANCE.taskIsRunning(task.getTaskId())) { if (ThreadTaskManager2.INSTANCE.taskIsRunning(task.getTaskId())) {
ThreadTaskManager2.INSTANCE.stopThreadTask(task.getTaskId()); ThreadTaskManager2.INSTANCE.stopThreadTask(task.getTaskId(), false);
} }
} }
break; break;

@ -23,17 +23,15 @@ import androidx.annotation.NonNull;
import com.arialyy.annotations.TaskEnum; import com.arialyy.annotations.TaskEnum;
import com.arialyy.aria.core.AriaConfig; import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.core.DuaContext; import com.arialyy.aria.core.DuaContext;
import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.common.AbsNormalEntity; import com.arialyy.aria.core.common.AbsNormalEntity;
import com.arialyy.aria.core.group.GroupSendParams; import com.arialyy.aria.core.group.GroupSendParams;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.ITaskQueue; import com.arialyy.aria.core.inf.ITaskQueue;
import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.listener.ISchedulers; import com.arialyy.aria.core.listener.ISchedulers;
import com.arialyy.aria.core.task.AbsTask; import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.core.task.DownloadGroupTask; import com.arialyy.aria.core.task.DownloadGroupTask;
import com.arialyy.aria.core.task.DownloadTask; import com.arialyy.aria.core.task.DownloadTask;
import com.arialyy.aria.core.task.ITask; import com.arialyy.aria.core.task.ITask;
import com.arialyy.aria.core.task.TaskCachePool;
import com.arialyy.aria.core.task.UploadTask; import com.arialyy.aria.core.task.UploadTask;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
@ -164,13 +162,9 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
private ISchedulerListener createListener(String proxyClassName) { private ISchedulerListener createListener(String proxyClassName) {
ISchedulerListener listener = null; ISchedulerListener listener = null;
try { try {
Class clazz = Class.forName(proxyClassName); Class<?> clazz = Class.forName(proxyClassName);
listener = (ISchedulerListener) clazz.newInstance(); listener = (ISchedulerListener) clazz.newInstance();
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
ALog.e(TAG, e.getMessage());
} catch (InstantiationException e) {
ALog.e(TAG, e.getMessage());
} catch (IllegalAccessException e) {
ALog.e(TAG, e.getMessage()); ALog.e(TAG, e.getMessage());
} }
return listener; return listener;
@ -312,7 +306,7 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
if (!queue.isFull()) { if (!queue.isFull()) {
Timber.d("stop task success, if there is a task, start the next task, taskId: %s", Timber.d("stop task success, if there is a task, start the next task, taskId: %s",
task.getTaskId()); task.getTaskId());
startNextTask(queue, task.getSchedulerType()); queue.startNextTask();
} else { } else {
Timber.d("stop task success, taskId: %s", task.getTaskId()); Timber.d("stop task success, taskId: %s", task.getTaskId());
} }
@ -323,7 +317,7 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
if (!queue.isFull()) { if (!queue.isFull()) {
Timber.d("remove task success, if there is a task, start the next task, taskId: %s", Timber.d("remove task success, if there is a task, start the next task, taskId: %s",
task.getTaskId()); task.getTaskId());
startNextTask(queue, task.getSchedulerType()); queue.startNextTask();
} else { } else {
Timber.d("remove task success, taskId: %s", task.getTaskId()); Timber.d("remove task success, taskId: %s", task.getTaskId());
} }
@ -331,7 +325,7 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
case COMPLETE: case COMPLETE:
queue.removeTask(task); queue.removeTask(task);
Timber.d("task complete, taskId: %s", task.getTaskId()); Timber.d("task complete, taskId: %s", task.getTaskId());
startNextTask(queue, task.getSchedulerType()); queue.startNextTask();
break; break;
case FAIL: case FAIL:
handleFailTask(queue, task); handleFailTask(queue, task);
@ -350,8 +344,7 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
* @param taskType 任务类型 * @param taskType 任务类型
*/ */
private void handlePreFailTask(int taskType) { private void handlePreFailTask(int taskType) {
startNextTask(getQueue(taskType), TaskSchedulerType.TYPE_DEFAULT); getQueue(taskType).startNextTask();
// 发送广播 // 发送广播
boolean canSend = mAriaConfig.getAConfig().isUseBroadcast(); boolean canSend = mAriaConfig.getAConfig().isUseBroadcast();
if (canSend) { if (canSend) {
@ -478,11 +471,9 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
} }
int type = task.getTaskType(); int type = task.getTaskType();
if (type == ITask.DOWNLOAD || type == ITask.DOWNLOAD_GROUP) { if (type == ITask.DOWNLOAD || type == ITask.DOWNLOAD_GROUP) {
mAriaConfig.getAPP().sendBroadcast( mAriaConfig.getAPP().sendBroadcast(createData(task));
createData(state, type, task.getTaskWrapper().getEntity()));
} else if (type == ITask.UPLOAD) { } else if (type == ITask.UPLOAD) {
mAriaConfig.getAPP().sendBroadcast( mAriaConfig.getAPP().sendBroadcast(createData(task));
createData(state, type, task.getTaskWrapper().getEntity()));
} else { } else {
ALog.w(TAG, "发送广播失败,没有对应的任务"); ALog.w(TAG, "发送广播失败,没有对应的任务");
} }
@ -490,20 +481,16 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
/** /**
* 创建广播发送的数据 * 创建广播发送的数据
*
* @param taskState 任务状态 {@link ISchedulers}
* @param taskType 任务类型 {@link ITask}
* @param entity 任务实体
*/ */
private Intent createData(int taskState, int taskType, AbsEntity entity) { private Intent createData(ITask task) {
Intent intent = new Intent(ISchedulers.ARIA_TASK_INFO_ACTION); Intent intent = new Intent(ISchedulers.ARIA_TASK_INFO_ACTION);
intent.setPackage(mAriaConfig.getAPP().getPackageName()); intent.setPackage(mAriaConfig.getAPP().getPackageName());
Bundle b = new Bundle(); Bundle b = new Bundle();
b.putInt(ISchedulers.TASK_TYPE, taskType); b.putInt(ISchedulers.TASK_TYPE, task.getTaskType());
b.putInt(ISchedulers.TASK_STATE, taskState); b.putInt(ISchedulers.TASK_STATE, task.getTaskState().getState());
b.putLong(ISchedulers.TASK_SPEED, entity.getSpeed()); b.putLong(ISchedulers.TASK_SPEED, task.getTaskState().getSpeed());
b.putInt(ISchedulers.TASK_PERCENT, entity.getPercent()); b.putInt(ISchedulers.TASK_PERCENT, task.getTaskState().getPercent());
b.putParcelable(ISchedulers.TASK_ENTITY, entity); b.putParcelable(ISchedulers.TASK_ENTITY, TaskCachePool.INSTANCE.getEntity(task.getTaskId()));
intent.putExtras(b); intent.putExtras(b);
return intent; return intent;
} }
@ -514,9 +501,9 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
* @param task 下载任务 * @param task 下载任务
*/ */
private void handleFailTask(final ITaskQueue<ITask> queue, final TASK task) { private void handleFailTask(final ITaskQueue<ITask> queue, final TASK task) {
if (!task.getTaskState().getNeedRetry() || task.isStop() || task.isCancel()) { if (!task.getTaskState().getNeedRetry() || task.isStopped() || task.isCanceled()) {
queue.removeTask(task); queue.removeTask(task);
startNextTask(queue, task.getSchedulerType()); queue.startNextTask();
normalTaskCallback(FAIL, task); normalTaskCallback(FAIL, task);
return; return;
} }
@ -525,7 +512,7 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
if ((!NetUtils.isConnected(mAriaConfig.getAPP()) && !isNotNetRetry)) { if ((!NetUtils.isConnected(mAriaConfig.getAPP()) && !isNotNetRetry)) {
queue.removeTask(task); queue.removeTask(task);
startNextTask(queue, task.getSchedulerType()); queue.startNextTask();
normalTaskCallback(FAIL, task); normalTaskCallback(FAIL, task);
return; return;
} }
@ -533,25 +520,6 @@ public class TaskSchedulers<TASK extends ITask> implements ISchedulers {
mFailureTaskHandler.offer(task); mFailureTaskHandler.offer(task);
} }
/**
* 启动下一个任务条件任务停止取消下载任务完成
*/
void startNextTask(final ITaskQueue<ITask> queue, int schedulerType) {
if (schedulerType == TaskSchedulerType.TYPE_STOP_NOT_NEXT) {
return;
}
TASK newTask = (TASK) queue.getNextTask();
if (newTask == null) {
if (queue.getCurrentExePoolNum() == 0) {
ALog.i(TAG, "没有等待中的任务");
}
return;
}
if (newTask.getTaskState().getState() == IEntity.STATE_WAIT) {
queue.startTask(newTask);
}
}
@Override public void init(@NonNull Context context) { @Override public void init(@NonNull Context context) {
} }

Loading…
Cancel
Save