loader 优化

pull/617/head
laoyuyu 6 years ago
parent c9eb57132b
commit 1e237d795d
  1. 2
      Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
  2. 2
      Aria/src/main/java/com/arialyy/aria/core/manager/DTaskWrapperFactory.java
  3. 2
      FtpComponent/src/main/java/aria/apache/commons/net/ftp/FTPFile.java
  4. 2
      FtpComponent/src/main/java/aria/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java
  5. 2
      FtpComponent/src/main/java/aria/apache/commons/net/ftp/parser/VMSFTPEntryParser.java
  6. 8
      FtpComponent/src/main/java/com/arialyy/aria/ftp/FtpRecordHandler.java
  7. 6
      FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDLoaderAdapter.java
  8. 4
      FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDirDLoaderUtil.java
  9. 6
      FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpULoaferAdapter.java
  10. 30
      HttpComponent/src/main/java/com/arialyy/aria/http/HttpFileInfoTask.java
  11. 167
      HttpComponent/src/main/java/com/arialyy/aria/http/HttpGroupInfoTask.java
  12. 14
      HttpComponent/src/main/java/com/arialyy/aria/http/HttpRecordHandler.java
  13. 8
      HttpComponent/src/main/java/com/arialyy/aria/http/download/DGroupLoaderUtil.java
  14. 200
      HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDLoaderAdapter.java
  15. 36
      HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDLoaderUtil.java
  16. 62
      HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDTTBuilder.java
  17. 4
      HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpSubDLoaderUtil.java
  18. 6
      HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpULoaderAdapter.java
  19. 4
      M3U8Component/src/main/java/com/arialyy/aria/m3u8/BaseM3U8Loader.java
  20. 8
      M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8RecordHandler.java
  21. 44
      PublicComponent/src/main/java/com/arialyy/aria/core/common/AbsRecordHandlerAdapter.java
  22. 56
      PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHandler.java
  23. 2
      PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHelper.java
  24. 4
      PublicComponent/src/main/java/com/arialyy/aria/core/config/XMLReader.java
  25. 4
      PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsGroupLoaderUtil.java
  26. 2
      PublicComponent/src/main/java/com/arialyy/aria/core/group/SimpleSchedulers.java
  27. 2
      PublicComponent/src/main/java/com/arialyy/aria/core/group/SimpleSubQueue.java
  28. 15
      PublicComponent/src/main/java/com/arialyy/aria/core/inf/IThreadState.java
  29. 2
      PublicComponent/src/main/java/com/arialyy/aria/core/listener/BaseDListener.java
  30. 2
      PublicComponent/src/main/java/com/arialyy/aria/core/listener/BaseUListener.java
  31. 2
      PublicComponent/src/main/java/com/arialyy/aria/core/listener/DownloadGroupListener.java
  32. 97
      PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsLoader.java
  33. 36
      PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsNormalLoaderUtil.java
  34. 185
      PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsNormalTTBuilder.java
  35. 40
      PublicComponent/src/main/java/com/arialyy/aria/core/loader/IInfoTask.java
  36. 15
      PublicComponent/src/main/java/com/arialyy/aria/core/loader/ILoader.java
  37. 1
      PublicComponent/src/main/java/com/arialyy/aria/core/loader/ILoaderAdapter.java
  38. 32
      PublicComponent/src/main/java/com/arialyy/aria/core/loader/ILoaderComponent.java
  39. 43
      PublicComponent/src/main/java/com/arialyy/aria/core/loader/ILoaderVisitor.java
  40. 37
      PublicComponent/src/main/java/com/arialyy/aria/core/loader/IRecordHandler.java
  41. 31
      PublicComponent/src/main/java/com/arialyy/aria/core/loader/IThreadTaskBuilder.java
  42. 75
      PublicComponent/src/main/java/com/arialyy/aria/core/loader/LoaderChain.java
  43. 38
      PublicComponent/src/main/java/com/arialyy/aria/core/loader/LoaderStructure.java
  44. 186
      PublicComponent/src/main/java/com/arialyy/aria/core/loader/NormalLoader.java
  45. 140
      PublicComponent/src/main/java/com/arialyy/aria/core/loader/ThreadStateManager.java
  46. 6
      PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsGroupTask.java
  47. 6
      PublicComponent/src/main/java/com/arialyy/aria/core/task/IThreadTask.java
  48. 4
      PublicComponent/src/main/java/com/arialyy/aria/core/task/ThreadTask.java
  49. 2
      PublicComponent/src/main/java/com/arialyy/aria/util/CheckUtil.java
  50. 2
      PublicComponent/src/main/java/com/arialyy/aria/util/RecordUtil.java
  51. 4
      app/gradle.properties
  52. 4
      build.gradle

@ -35,7 +35,7 @@ import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadReceiver; import com.arialyy.aria.core.download.DownloadReceiver;
import com.arialyy.aria.core.inf.AbsReceiver; import com.arialyy.aria.core.inf.AbsReceiver;
import com.arialyy.aria.core.inf.IReceiver; import com.arialyy.aria.core.inf.IReceiver;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.inf.ReceiverType; import com.arialyy.aria.core.inf.ReceiverType;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadReceiver; import com.arialyy.aria.core.upload.UploadReceiver;

@ -19,7 +19,7 @@ import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.wrapper.ITaskWrapper; import com.arialyy.aria.core.wrapper.ITaskWrapper;
import java.io.File; import java.io.File;

@ -55,7 +55,7 @@ public class FTPFile implements Serializable {
/** A constant indicating file/directory write permission. ***/ /** A constant indicating file/directory write permission. ***/
public static final int WRITE_PERMISSION = 1; public static final int WRITE_PERMISSION = 1;
/** /**
* A constant indicating file execute permission or directory listing * A constant indicating file accept permission or directory listing
* permission. * permission.
***/ ***/
public static final int EXECUTE_PERMISSION = 2; public static final int EXECUTE_PERMISSION = 2;

@ -95,7 +95,7 @@ public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* Netware file permissions are in the following format: RWCEAFMS, and are explained as follows: * Netware file permissions are in the following format: RWCEAFMS, and are explained as follows:
* <ul> * <ul>
* <li><b>S</b> - Supervisor; All rights. * <li><b>S</b> - Supervisor; All rights.
* <li><b>R</b> - Read; Right to open and read or execute. * <li><b>R</b> - Read; Right to open and read or accept.
* <li><b>W</b> - Write; Right to open and modify. * <li><b>W</b> - Write; Right to open and modify.
* <li><b>C</b> - Create; Right to create; when assigned to a file, allows a deleted file to be * <li><b>C</b> - Create; Right to create; when assigned to a file, allows a deleted file to be
* recovered. * recovered.

@ -164,7 +164,7 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
//Set file permission. //Set file permission.
//VMS has (SYSTEM,OWNER,GROUP,WORLD) users that can contain //VMS has (SYSTEM,OWNER,GROUP,WORLD) users that can contain
//R (read) W (write) E (execute) D (delete) //R (read) W (write) E (accept) D (delete)
//iterate for OWNER GROUP WORLD permissions //iterate for OWNER GROUP WORLD permissions
for (int access = 0; access < 3; access++) { for (int access = 0; access < 3; access++) {

@ -17,11 +17,11 @@ package com.arialyy.aria.ftp;
import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.ThreadRecord; import com.arialyy.aria.core.ThreadRecord;
import com.arialyy.aria.core.common.AbsRecordHandlerAdapter; import com.arialyy.aria.core.common.RecordHandler;
import com.arialyy.aria.core.common.RecordHelper; import com.arialyy.aria.core.common.RecordHelper;
import com.arialyy.aria.core.config.Configuration; import com.arialyy.aria.core.config.Configuration;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.wrapper.ITaskWrapper; import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.util.RecordUtil; import com.arialyy.aria.util.RecordUtil;
@ -31,9 +31,9 @@ import java.util.ArrayList;
* @Author lyy * @Author lyy
* @Date 2019-09-19 * @Date 2019-09-19
*/ */
public class FtpRecordAdapter extends AbsRecordHandlerAdapter { public class FtpRecordHandler extends RecordHandler {
public FtpRecordAdapter(AbsTaskWrapper wrapper) { public FtpRecordHandler(AbsTaskWrapper wrapper) {
super(wrapper); super(wrapper);
} }

@ -18,13 +18,13 @@ package com.arialyy.aria.ftp.download;
import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.common.RecordHandler; import com.arialyy.aria.core.common.RecordHandler;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.task.AbsNormalLoaderAdapter; import com.arialyy.aria.core.task.AbsNormalLoaderAdapter;
import com.arialyy.aria.core.task.IThreadTask; import com.arialyy.aria.core.task.IThreadTask;
import com.arialyy.aria.core.task.ThreadTask; import com.arialyy.aria.core.task.ThreadTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.wrapper.ITaskWrapper; import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.ftp.FtpRecordAdapter; import com.arialyy.aria.ftp.FtpRecordHandler;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.FileUtil; import com.arialyy.aria.util.FileUtil;
import java.io.File; import java.io.File;
@ -66,7 +66,7 @@ public class FtpDLoaderAdapter extends AbsNormalLoaderAdapter {
} }
@Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) { @Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) {
FtpRecordAdapter adapter = new FtpRecordAdapter(wrapper); FtpRecordHandler adapter = new FtpRecordHandler(wrapper);
RecordHandler handler = new RecordHandler(wrapper); RecordHandler handler = new RecordHandler(wrapper);
handler.setAdapter(adapter); handler.setAdapter(adapter);
return handler; return handler;

@ -21,7 +21,7 @@ import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.AbsEntity; import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.group.AbsGroupUtil; import com.arialyy.aria.core.group.AbsGroupLoaderUtil;
import com.arialyy.aria.core.group.AbsSubDLoadUtil; import com.arialyy.aria.core.group.AbsSubDLoadUtil;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.OnFileInfoCallback; import com.arialyy.aria.core.inf.OnFileInfoCallback;
@ -37,7 +37,7 @@ import java.util.concurrent.locks.ReentrantLock;
* Created by Aria.Lao on 2017/7/27. * Created by Aria.Lao on 2017/7/27.
* ftp文件夹下载工具 * ftp文件夹下载工具
*/ */
public class FtpDirDLoaderUtil extends AbsGroupUtil { public class FtpDirDLoaderUtil extends AbsGroupLoaderUtil {
private ReentrantLock LOCK = new ReentrantLock(); private ReentrantLock LOCK = new ReentrantLock();
private Condition condition = LOCK.newCondition(); private Condition condition = LOCK.newCondition();

@ -21,10 +21,10 @@ import com.arialyy.aria.core.common.RecordHandler;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.task.ThreadTask; import com.arialyy.aria.core.task.ThreadTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.task.IThreadTask; import com.arialyy.aria.core.task.IThreadTask;
import com.arialyy.aria.core.wrapper.ITaskWrapper; import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.ftp.FtpRecordAdapter; import com.arialyy.aria.ftp.FtpRecordHandler;
/** /**
* @Author lyy * @Author lyy
@ -48,7 +48,7 @@ class FtpULoaferAdapter extends AbsNormalLoaderAdapter {
} }
@Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) { @Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) {
FtpRecordAdapter adapter = new FtpRecordAdapter(wrapper); FtpRecordHandler adapter = new FtpRecordHandler(wrapper);
RecordHandler handler = new RecordHandler(wrapper); RecordHandler handler = new RecordHandler(wrapper);
handler.setAdapter(adapter); handler.setAdapter(adapter);
return handler; return handler;

@ -24,7 +24,8 @@ import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.OnFileInfoCallback; 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.core.processor.IHttpFileLenAdapter;
import com.arialyy.aria.exception.AriaIOException; import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.BaseException;
@ -54,19 +55,18 @@ import java.util.UUID;
/** /**
* 下载文件信息获取 * 下载文件信息获取
*/ */
public class HttpFileInfoThread implements Runnable { public class HttpFileInfoTask implements IInfoTask, Runnable {
private static final String TAG = "HttpFileInfoThread"; private static final String TAG = "HttpFileInfoThread";
private DownloadEntity mEntity; private DownloadEntity mEntity;
private DTaskWrapper mTaskWrapper; private DTaskWrapper mTaskWrapper;
private int mConnectTimeOut; private int mConnectTimeOut;
private OnFileInfoCallback onFileInfoCallback; private Callback callback;
private HttpTaskOption taskOption; private HttpTaskOption taskOption;
public HttpFileInfoThread(DTaskWrapper taskWrapper, OnFileInfoCallback callback) { public HttpFileInfoTask(DTaskWrapper taskWrapper) {
this.mTaskWrapper = taskWrapper; this.mTaskWrapper = taskWrapper;
mEntity = taskWrapper.getEntity(); mEntity = taskWrapper.getEntity();
mConnectTimeOut = AriaConfig.getInstance().getDConfig().getConnectTimeOut(); mConnectTimeOut = AriaConfig.getInstance().getDConfig().getConnectTimeOut();
onFileInfoCallback = callback;
taskOption = (HttpTaskOption) taskWrapper.getTaskOption(); taskOption = (HttpTaskOption) taskWrapper.getTaskOption();
} }
@ -99,6 +99,10 @@ public class HttpFileInfoThread implements Runnable {
} }
} }
@Override public void setCallback(Callback callback) {
this.callback = callback;
}
private void handleConnect(HttpURLConnection conn) throws IOException { private void handleConnect(HttpURLConnection conn) throws IOException {
if (taskOption.getRequestEnum() == RequestEnum.POST) { if (taskOption.getRequestEnum() == RequestEnum.POST) {
Map<String, String> params = taskOption.getParams(); Map<String, String> params = taskOption.getParams();
@ -223,9 +227,9 @@ public class HttpFileInfoThread implements Runnable {
} }
if (end) { if (end) {
taskOption.setChunked(isChunked); taskOption.setChunked(isChunked);
if (onFileInfoCallback != null) { if (callback != null) {
CompleteInfo info = new CompleteInfo(code, mTaskWrapper); CompleteInfo info = new CompleteInfo(code, mTaskWrapper);
onFileInfoCallback.onComplete(mEntity.getUrl(), info); callback.onSucceed(mEntity.getUrl(), info);
} }
mEntity.update(); mEntity.update();
} }
@ -291,8 +295,8 @@ public class HttpFileInfoThread implements Runnable {
private void handleUrlReTurn(HttpURLConnection conn, String newUrl) throws IOException { private void handleUrlReTurn(HttpURLConnection conn, String newUrl) throws IOException {
ALog.d(TAG, "30x跳转,新url为【" + newUrl + "】"); ALog.d(TAG, "30x跳转,新url为【" + newUrl + "】");
if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null")) { if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null")) {
if (onFileInfoCallback != null) { if (callback != null) {
onFileInfoCallback.onFail(mEntity, new TaskException(TAG, "获取重定向链接失败"), false); callback.onFail(mEntity, new TaskException(TAG, "获取重定向链接失败"), false);
} }
return; return;
} }
@ -336,11 +340,15 @@ public class HttpFileInfoThread implements Runnable {
} }
private void failDownload(BaseException e, boolean needRetry) { private void failDownload(BaseException e, boolean needRetry) {
if (onFileInfoCallback != null) { if (callback != null) {
onFileInfoCallback.onFail(mEntity, e, needRetry); callback.onFail(mEntity, e, needRetry);
} }
} }
@Override public void accept(ILoaderVisitor visitor) {
visitor.addComponent(this);
}
private static class FileLenAdapter implements IHttpFileLenAdapter { private static class FileLenAdapter implements IHttpFileLenAdapter {
@Override public long handleFileLen(Map<String, List<String>> headers) { @Override public long handleFileLen(Map<String, List<String>> headers) {

@ -0,0 +1,167 @@
/*
* 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;
import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.listener.DownloadGroupListener;
import com.arialyy.aria.core.loader.IInfoTask;
import com.arialyy.aria.core.loader.ILoaderVisitor;
import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 组合任务文件信息用于获取长度未知时组合任务的长度
*/
public class HttpGroupInfoTask implements IInfoTask {
private String TAG = CommonUtil.getClassName(this);
private Callback callback;
private DGTaskWrapper wrapper;
private final Object LOCK = new Object();
private ExecutorService mPool = null;
private boolean getLenComplete = false;
private int count;
private int failCount;
private DownloadGroupListener listener;
/**
* 子任务回调
*/
private Callback subCallback = new Callback() {
@Override public void onSucceed(String url, CompleteInfo info) {
count++;
checkGetSizeComplete(count, failCount);
ALog.d(TAG, "获取子任务信息完成");
}
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
ALog.e(TAG, String.format("获取文件信息失败,url:%s", ((DownloadEntity) entity).getUrl()));
count++;
failCount++;
listener.onSubFail((DownloadEntity) entity, new AriaIOException(TAG,
String.format("子任务获取文件长度失败,url:%s", ((DownloadEntity) entity).getUrl())));
checkGetSizeComplete(count, failCount);
}
};
public HttpGroupInfoTask(DGTaskWrapper wrapper, DownloadGroupListener listener) {
this.wrapper = wrapper;
this.listener = listener;
}
@Override public void run() {
// 如果是isUnknownSize()标志,并且获取大小没有完成,则直接回调onStop
if (mPool != null && !getLenComplete) {
ALog.d(TAG, "获取长度未完成的情况下,停止组合任务");
mPool.shutdown();
//mListener.onStop(0);
return;
}
// 处理组合任务大小未知的情况
if (wrapper.isUnknownSize() && wrapper.getEntity().getFileSize() < 1) {
mPool = Executors.newCachedThreadPool();
getGroupSize();
try {
synchronized (LOCK) {
LOCK.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
for (DTaskWrapper wrapper : wrapper.getSubTaskWrapper()) {
cloneHeader(wrapper);
}
callback.onSucceed(wrapper.getKey(), new CompleteInfo());
}
}
/**
* 获取组合任务大小使用该方式获取到的组合任务大小子任务不需要再重新获取文件大小
*/
private void getGroupSize() {
new Thread(new Runnable() {
@Override public void run() {
for (DTaskWrapper dTaskWrapper : wrapper.getSubTaskWrapper()) {
cloneHeader(dTaskWrapper);
HttpFileInfoTask infoTask = new HttpFileInfoTask(dTaskWrapper);
infoTask.setCallback(subCallback);
}
}
}).start();
}
/**
* 检查组合任务大小是否获取完成获取完成后取消阻塞并设置组合任务大小
*/
private void checkGetSizeComplete(int count, int failCount) {
if (failCount == wrapper.getSubTaskWrapper().size()) {
callback.onFail(wrapper.getEntity(), new AriaIOException(TAG, "获取子任务长度失败"), false);
notifyLock();
return;
}
if (count == wrapper.getSubTaskWrapper().size()) {
long size = 0;
for (DTaskWrapper wrapper : wrapper.getSubTaskWrapper()) {
size += wrapper.getEntity().getFileSize();
}
wrapper.getEntity().setConvertFileSize(CommonUtil.formatFileSize(size));
wrapper.getEntity().setFileSize(size);
wrapper.getEntity().update();
getLenComplete = true;
ALog.d(TAG, String.format("获取组合任务长度完成,组合任务总长度:%s,失败的只任务数:%s", size, failCount));
callback.onSucceed(wrapper.getKey(), new CompleteInfo());
notifyLock();
}
}
private void notifyLock() {
synchronized (LOCK) {
LOCK.notifyAll();
}
}
/**
* 子任务使用父包裹器的属性
*/
private void cloneHeader(DTaskWrapper taskWrapper) {
HttpTaskOption groupOption = (HttpTaskOption) wrapper.getTaskOption();
HttpTaskOption subOption = new HttpTaskOption();
// 设置属性
subOption.setFileLenAdapter(groupOption.getFileLenAdapter());
subOption.setRequestEnum(groupOption.getRequestEnum());
subOption.setHeaders(groupOption.getHeaders());
subOption.setProxy(groupOption.getProxy());
subOption.setParams(groupOption.getParams());
taskWrapper.setTaskOption(subOption);
}
@Override public void setCallback(Callback callback) {
this.callback = callback;
}
@Override public void accept(ILoaderVisitor visitor) {
visitor.addComponent(this);
}
}

@ -17,11 +17,11 @@ package com.arialyy.aria.http;
import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.ThreadRecord; import com.arialyy.aria.core.ThreadRecord;
import com.arialyy.aria.core.common.AbsRecordHandlerAdapter; import com.arialyy.aria.core.common.RecordHandler;
import com.arialyy.aria.core.common.RecordHelper; import com.arialyy.aria.core.common.RecordHelper;
import com.arialyy.aria.core.config.Configuration; import com.arialyy.aria.core.config.Configuration;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.wrapper.ITaskWrapper; import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.util.RecordUtil; import com.arialyy.aria.util.RecordUtil;
@ -31,16 +31,16 @@ import java.util.ArrayList;
* @Author lyy * @Author lyy
* @Date 2019-09-23 * @Date 2019-09-23
*/ */
public class HttpRecordAdapter extends AbsRecordHandlerAdapter { public class HttpRecordHandler extends RecordHandler {
public HttpRecordAdapter(AbsTaskWrapper wrapper) { public HttpRecordHandler(AbsTaskWrapper wrapper) {
super(wrapper); super(wrapper);
} }
@Override public void onPre() { @Override public void onPre() {
super.onPre(); super.onPre();
if (getWrapper().getRequestType() == ITaskWrapper.U_HTTP) { //if (getWrapper().getRequestType() == ITaskWrapper.U_HTTP) {
RecordUtil.delTaskRecord(getEntity().getFilePath(), IRecordHandler.TYPE_UPLOAD); // RecordUtil.delTaskRecord(getEntity().getFilePath(), IRecordHandler.TYPE_UPLOAD);
} //}
} }
@Override public void handlerTaskRecord(TaskRecord record) { @Override public void handlerTaskRecord(TaskRecord record) {

@ -25,9 +25,9 @@ import com.arialyy.aria.core.listener.IEventListener;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.exception.AriaIOException; import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.core.group.AbsGroupUtil; import com.arialyy.aria.core.group.AbsGroupLoaderUtil;
import com.arialyy.aria.core.group.AbsSubDLoadUtil; import com.arialyy.aria.core.group.AbsSubDLoadUtil;
import com.arialyy.aria.http.HttpFileInfoThread; import com.arialyy.aria.http.HttpFileInfoTask;
import com.arialyy.aria.http.HttpTaskOption; import com.arialyy.aria.http.HttpTaskOption;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
@ -40,7 +40,7 @@ import java.util.concurrent.Executors;
* Created by AriaL on 2017/6/30. * Created by AriaL on 2017/6/30.
* 任务组下载工具 * 任务组下载工具
*/ */
public class DGroupLoaderUtil extends AbsGroupUtil { public class DGroupLoaderUtil extends AbsGroupLoaderUtil {
private final Object LOCK = new Object(); private final Object LOCK = new Object();
private ExecutorService mPool = null; private ExecutorService mPool = null;
private boolean getLenComplete = false; private boolean getLenComplete = false;
@ -113,7 +113,7 @@ public class DGroupLoaderUtil extends AbsGroupUtil {
@Override public void run() { @Override public void run() {
for (DTaskWrapper dTaskWrapper : getWrapper().getSubTaskWrapper()) { for (DTaskWrapper dTaskWrapper : getWrapper().getSubTaskWrapper()) {
cloneHeader(dTaskWrapper); cloneHeader(dTaskWrapper);
mPool.submit(new HttpFileInfoThread(dTaskWrapper, new OnFileInfoCallback() { mPool.submit(new HttpFileInfoTask(dTaskWrapper, new OnFileInfoCallback() {
@Override public void onComplete(String url, CompleteInfo info) { @Override public void onComplete(String url, CompleteInfo info) {
if (!getWrapper().isUnknownSize()) { if (!getWrapper().isUnknownSize()) {
startSubLoader(createSubLoader((DTaskWrapper) info.wrapper, false)); startSubLoader(createSubLoader((DTaskWrapper) info.wrapper, false));

@ -1,100 +1,100 @@
/* ///*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) // * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
* // *
* Licensed under the Apache License, Version 2.0 (the "License"); // * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. // * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at // * You may obtain a copy of the License at
* // *
* http://www.apache.org/licenses/LICENSE-2.0 // * http://www.apache.org/licenses/LICENSE-2.0
* // *
* Unless required by applicable law or agreed to in writing, software // * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, // * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and // * See the License for the specific language governing permissions and
* limitations under the License. // * limitations under the License.
*/ // */
package com.arialyy.aria.http.download; //package com.arialyy.aria.http.download;
//
import com.arialyy.aria.core.TaskRecord; //import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.common.RecordHandler; //import com.arialyy.aria.core.common.RecordHandler;
import com.arialyy.aria.core.common.SubThreadConfig; //import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.download.DownloadEntity; //import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.IRecordHandler; //import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.task.AbsNormalLoaderAdapter; //import com.arialyy.aria.core.task.AbsNormalLoaderAdapter;
import com.arialyy.aria.core.task.IThreadTask; //import com.arialyy.aria.core.task.IThreadTask;
import com.arialyy.aria.core.task.ThreadTask; //import com.arialyy.aria.core.task.ThreadTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; //import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.wrapper.ITaskWrapper; //import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.http.HttpRecordAdapter; //import com.arialyy.aria.http.HttpRecordHandler;
import com.arialyy.aria.util.ALog; //import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile; //import com.arialyy.aria.util.BufferedRandomAccessFile;
import com.arialyy.aria.util.FileUtil; //import com.arialyy.aria.util.FileUtil;
import java.io.File; //import java.io.File;
import java.io.IOException; //import java.io.IOException;
//
/** ///**
* @Author lyy // * @Author lyy
* @Date 2019-09-21 // * @Date 2019-09-21
*/ // */
final class HttpDLoaderAdapter extends AbsNormalLoaderAdapter { //final class HttpDLoaderAdapter extends AbsNormalLoaderAdapter {
HttpDLoaderAdapter(ITaskWrapper wrapper) { // HttpDLoaderAdapter(ITaskWrapper wrapper) {
super(wrapper); // super(wrapper);
} // }
//
@Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) { // @Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) {
if (!record.isBlock) { // if (!record.isBlock) {
if (getTempFile().exists()) { // if (getTempFile().exists()) {
FileUtil.deleteFile(getTempFile()); // FileUtil.deleteFile(getTempFile());
} // }
} else { // } else {
for (int i = 0; i < totalThreadNum; i++) { // for (int i = 0; i < totalThreadNum; i++) {
File blockFile = // File blockFile =
new File(String.format(IRecordHandler.SUB_PATH, getTempFile().getPath(), i)); // new File(String.format(IRecordHandler.SUB_PATH, getTempFile().getPath(), i));
if (blockFile.exists()) { // if (blockFile.exists()) {
ALog.d(TAG, String.format("分块【%s】已经存在,将删除该分块", i)); // ALog.d(TAG, String.format("分块【%s】已经存在,将删除该分块", i));
FileUtil.deleteFile(blockFile); // FileUtil.deleteFile(blockFile);
} // }
} // }
} // }
BufferedRandomAccessFile file = null; // BufferedRandomAccessFile file = null;
try { // try {
if (totalThreadNum > 1 && !record.isBlock) { // if (totalThreadNum > 1 && !record.isBlock) {
file = new BufferedRandomAccessFile(new File(getTempFile().getPath()), "rwd", 8192); // file = new BufferedRandomAccessFile(new File(getTempFile().getPath()), "rwd", 8192);
//设置文件长度 // //设置文件长度
file.setLength(getEntity().getFileSize()); // file.setLength(getEntity().getFileSize());
} // }
return true; // return true;
} catch (IOException e) { // } catch (IOException e) {
e.printStackTrace(); // e.printStackTrace();
ALog.e(TAG, String.format("下载失败,filePath: %s, url: %s", getEntity().getFilePath(), // ALog.e(TAG, String.format("下载失败,filePath: %s, url: %s", getEntity().getFilePath(),
getEntity().getUrl())); // getEntity().getUrl()));
} finally { // } finally {
if (file != null) { // if (file != null) {
try { // try {
file.close(); // file.close();
} catch (IOException e) { // } catch (IOException e) {
e.printStackTrace(); // e.printStackTrace();
} // }
} // }
} // }
return false; // return false;
} // }
//
@Override public IThreadTask createThreadTask(SubThreadConfig config) { // @Override public IThreadTask createThreadTask(SubThreadConfig config) {
ThreadTask task = new ThreadTask(config); // ThreadTask task = new ThreadTask(config);
HttpDThreadTaskAdapter adapter = new HttpDThreadTaskAdapter(config); // HttpDThreadTaskAdapter adapter = new HttpDThreadTaskAdapter(config);
task.setAdapter(adapter); // task.setAdapter(adapter);
return task; // return task;
} // }
//
@Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) { // @Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) {
RecordHandler recordHandler = new RecordHandler(wrapper); // RecordHandler recordHandler = new RecordHandler(wrapper);
HttpRecordAdapter adapter = new HttpRecordAdapter(wrapper); // HttpRecordHandler adapter = new HttpRecordHandler(wrapper);
recordHandler.setAdapter(adapter); // recordHandler.setAdapter(adapter);
return recordHandler; // return recordHandler;
} // }
//
private DownloadEntity getEntity() { // private DownloadEntity getEntity() {
return (DownloadEntity) getWrapper().getEntity(); // return (DownloadEntity) getWrapper().getEntity();
} // }
} //}

@ -15,17 +15,16 @@
*/ */
package com.arialyy.aria.http.download; package com.arialyy.aria.http.download;
import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.inf.OnFileInfoCallback;
import com.arialyy.aria.core.listener.IEventListener; import com.arialyy.aria.core.listener.IEventListener;
import com.arialyy.aria.core.loader.AbsLoader; import com.arialyy.aria.core.loader.AbsLoader;
import com.arialyy.aria.core.loader.AbsNormalLoaderUtil; 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.NormalLoader;
import com.arialyy.aria.core.loader.ThreadStateManager;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.http.HttpFileInfoTask;
import com.arialyy.aria.http.HttpFileInfoThread; import com.arialyy.aria.http.HttpRecordHandler;
import com.arialyy.aria.http.HttpTaskOption; import com.arialyy.aria.http.HttpTaskOption;
/** /**
@ -38,24 +37,17 @@ public class HttpDLoaderUtil extends AbsNormalLoaderUtil {
wrapper.generateTaskOption(HttpTaskOption.class); wrapper.generateTaskOption(HttpTaskOption.class);
} }
@Override protected AbsLoader createLoader() { @Override public AbsLoader getLoader() {
NormalLoader loader = new NormalLoader(getListener(), getTaskWrapper()); return mLoader == null ? new NormalLoader(getTaskWrapper(), getListener()) : mLoader;
HttpDLoaderAdapter adapter = new HttpDLoaderAdapter(getTaskWrapper());
loader.setAdapter(adapter);
return loader;
} }
@Override protected Runnable createInfoThread() { public LoaderStructure getLoaderStructure() {
return new HttpFileInfoThread((DTaskWrapper) getTaskWrapper(), new OnFileInfoCallback() { LoaderStructure structure = new LoaderStructure();
@Override public void onComplete(String url, CompleteInfo info) { structure.addComponent(new HttpRecordHandler(getTaskWrapper()))
((NormalLoader) getLoader()).updateTempFile(); .addComponent(new ThreadStateManager(getListener()))
getLoader().start(); .addComponent(new HttpFileInfoTask((DTaskWrapper) getTaskWrapper()))
} .addComponent(new HttpDTTBuilder(getTaskWrapper()));
structure.accept(getLoader());
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { return structure;
fail(e, needRetry);
getLoader().closeTimer();
}
});
} }
} }

@ -0,0 +1,62 @@
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.AbsNormalTTBuilder;
import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.task.IThreadTaskAdapter;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
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 HttpDTTBuilder extends AbsNormalTTBuilder {
HttpDTTBuilder(AbsTaskWrapper wrapper) {
super(wrapper);
}
@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(new File(getTempFile().getPath()), "rwd", 8192);
//设置文件长度
file.setLength(getEntity().getFileSize());
}
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;
}
}

@ -25,7 +25,7 @@ import com.arialyy.aria.core.inf.OnFileInfoCallback;
import com.arialyy.aria.core.listener.ISchedulers; import com.arialyy.aria.core.listener.ISchedulers;
import com.arialyy.aria.core.loader.NormalLoader; import com.arialyy.aria.core.loader.NormalLoader;
import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.http.HttpFileInfoThread; import com.arialyy.aria.http.HttpFileInfoTask;
/** /**
* @Author lyy * @Author lyy
@ -49,7 +49,7 @@ class HttpSubDLoaderUtil extends AbsSubDLoadUtil {
@Override public void start() { @Override public void start() {
if (isNeedGetInfo()) { if (isNeedGetInfo()) {
new Thread(new HttpFileInfoThread(getWrapper(), new OnFileInfoCallback() { new Thread(new HttpFileInfoTask(getWrapper(), new OnFileInfoCallback() {
@Override public void onComplete(String url, CompleteInfo info) { @Override public void onComplete(String url, CompleteInfo info) {
getDownloader().start(); getDownloader().start();

@ -18,13 +18,13 @@ package com.arialyy.aria.http.upload;
import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.common.RecordHandler; import com.arialyy.aria.core.common.RecordHandler;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.task.AbsNormalLoaderAdapter; import com.arialyy.aria.core.task.AbsNormalLoaderAdapter;
import com.arialyy.aria.core.task.IThreadTask; import com.arialyy.aria.core.task.IThreadTask;
import com.arialyy.aria.core.task.ThreadTask; import com.arialyy.aria.core.task.ThreadTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.wrapper.ITaskWrapper; import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.http.HttpRecordAdapter; import com.arialyy.aria.http.HttpRecordHandler;
/** /**
* @Author lyy * @Author lyy
@ -48,7 +48,7 @@ final class HttpULoaderAdapter extends AbsNormalLoaderAdapter {
@Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) { @Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) {
RecordHandler recordHandler = new RecordHandler(wrapper); RecordHandler recordHandler = new RecordHandler(wrapper);
HttpRecordAdapter adapter = new HttpRecordAdapter(wrapper); HttpRecordHandler adapter = new HttpRecordHandler(wrapper);
recordHandler.setAdapter(adapter); recordHandler.setAdapter(adapter);
return recordHandler; return recordHandler;
} }

@ -20,7 +20,7 @@ import com.arialyy.aria.core.common.RecordHandler;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.M3U8Entity; import com.arialyy.aria.core.download.M3U8Entity;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.listener.IEventListener; import com.arialyy.aria.core.listener.IEventListener;
import com.arialyy.aria.core.loader.AbsLoader; import com.arialyy.aria.core.loader.AbsLoader;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
@ -142,7 +142,7 @@ public abstract class BaseM3U8Loader extends AbsLoader {
@Override protected IRecordHandler getRecordHandler(AbsTaskWrapper wrapper) { @Override protected IRecordHandler getRecordHandler(AbsTaskWrapper wrapper) {
RecordHandler handler = new RecordHandler(wrapper); RecordHandler handler = new RecordHandler(wrapper);
M3U8RecordAdapter adapter = new M3U8RecordAdapter((DTaskWrapper) wrapper); M3U8RecordHandler adapter = new M3U8RecordHandler((DTaskWrapper) wrapper);
handler.setAdapter(adapter); handler.setAdapter(adapter);
return handler; return handler;
} }

@ -17,11 +17,11 @@ package com.arialyy.aria.m3u8;
import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.ThreadRecord; import com.arialyy.aria.core.ThreadRecord;
import com.arialyy.aria.core.common.AbsRecordHandlerAdapter; import com.arialyy.aria.core.common.RecordHandler;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.M3U8Entity; import com.arialyy.aria.core.download.M3U8Entity;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.wrapper.ITaskWrapper; import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.FileUtil; import com.arialyy.aria.util.FileUtil;
@ -33,10 +33,10 @@ import java.util.ArrayList;
* @Author lyy * @Author lyy
* @Date 2019-09-24 * @Date 2019-09-24
*/ */
public class M3U8RecordAdapter extends AbsRecordHandlerAdapter { public class M3U8RecordHandler extends RecordHandler {
private M3U8TaskOption mOption; private M3U8TaskOption mOption;
M3U8RecordAdapter(DTaskWrapper wrapper) { M3U8RecordHandler(DTaskWrapper wrapper) {
super(wrapper); super(wrapper);
mOption = (M3U8TaskOption) wrapper.getM3u8Option(); mOption = (M3U8TaskOption) wrapper.getM3u8Option();
} }

@ -1,44 +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.core.common;
import com.arialyy.aria.core.inf.IRecordHandlerAdapter;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.util.CommonUtil;
/**
* @Author lyy
* @Date 2019-09-19
*/
public abstract class AbsRecordHandlerAdapter implements IRecordHandlerAdapter {
private AbsTaskWrapper mWrapper;
protected String TAG = CommonUtil.getClassName(getClass());
@Override public void onPre() {
}
public AbsRecordHandlerAdapter(AbsTaskWrapper wrapper) {
mWrapper = wrapper;
}
public AbsTaskWrapper getWrapper() {
return mWrapper;
}
protected AbsNormalEntity getEntity() {
return (AbsNormalEntity) getWrapper().getEntity();
}
}

@ -18,8 +18,8 @@ package com.arialyy.aria.core.common;
import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.ThreadRecord; import com.arialyy.aria.core.ThreadRecord;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.ILoaderVisitor;
import com.arialyy.aria.core.inf.IRecordHandlerAdapter; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.wrapper.ITaskWrapper; import com.arialyy.aria.core.wrapper.ITaskWrapper;
@ -38,22 +38,29 @@ import java.util.Set;
/** /**
* 处理任务记录分配线程区间 * 处理任务记录分配线程区间
*/ */
public class RecordHandler implements IRecordHandler { public abstract class RecordHandler implements IRecordHandler {
private final String TAG = "RecordHandler"; protected final String TAG = CommonUtil.getClassName(this);
@Deprecated private File mConfigFile; @Deprecated private File mConfigFile;
private TaskRecord mTaskRecord; private TaskRecord mTaskRecord;
private AbsTaskWrapper mTaskWrapper; private AbsTaskWrapper mTaskWrapper;
private AbsNormalEntity mEntity; private AbsNormalEntity mEntity;
private IRecordHandlerAdapter mAdapter;
public RecordHandler(AbsTaskWrapper wrapper) { public RecordHandler(AbsTaskWrapper wrapper) {
mTaskWrapper = wrapper; mTaskWrapper = wrapper;
mEntity = (AbsNormalEntity) mTaskWrapper.getEntity(); mEntity = (AbsNormalEntity) mTaskWrapper.getEntity();
} }
public void setAdapter(IRecordHandlerAdapter mAdapter) { public AbsTaskWrapper getWrapper() {
this.mAdapter = mAdapter; return mTaskWrapper;
}
public AbsNormalEntity getEntity() {
return mEntity;
}
@Override public void onPre() {
} }
/** /**
@ -70,10 +77,10 @@ public class RecordHandler implements IRecordHandler {
if (mConfigFile.exists()) { if (mConfigFile.exists()) {
convertDb(); convertDb();
} else { } else {
mAdapter.onPre(); onPre();
mTaskRecord = DbDataHelper.getTaskRecord(getFilePath(), mEntity.getTaskType()); mTaskRecord = DbDataHelper.getTaskRecord(getFilePath(), mEntity.getTaskType());
if (mTaskRecord == null) { if (mTaskRecord == null) {
if (!new File(getFilePath()).exists()){ if (!new File(getFilePath()).exists()) {
FileUtil.createFile(getFilePath()); FileUtil.createFile(getFilePath());
} }
initRecord(true); initRecord(true);
@ -83,14 +90,14 @@ public class RecordHandler implements IRecordHandler {
ALog.w(TAG, String.format("文件【%s】不存在,重新分配线程区间", mTaskRecord.filePath)); ALog.w(TAG, String.format("文件【%s】不存在,重新分配线程区间", mTaskRecord.filePath));
DbEntity.deleteData(ThreadRecord.class, "taskKey=?", mTaskRecord.filePath); DbEntity.deleteData(ThreadRecord.class, "taskKey=?", mTaskRecord.filePath);
mTaskRecord.threadRecords.clear(); mTaskRecord.threadRecords.clear();
mTaskRecord.threadNum = mAdapter.initTaskThreadNum(); mTaskRecord.threadNum = initTaskThreadNum();
initRecord(false); initRecord(false);
} else if (mTaskRecord.threadRecords == null || mTaskRecord.threadRecords.isEmpty()) { } else if (mTaskRecord.threadRecords == null || mTaskRecord.threadRecords.isEmpty()) {
mTaskRecord.threadNum = mAdapter.initTaskThreadNum(); mTaskRecord.threadNum = initTaskThreadNum();
initRecord(false); initRecord(false);
} }
} }
mAdapter.handlerTaskRecord(mTaskRecord); handlerTaskRecord(mTaskRecord);
} }
saveRecord(); saveRecord();
return mTaskRecord; return mTaskRecord;
@ -127,7 +134,7 @@ public class RecordHandler implements IRecordHandler {
return; return;
} }
mTaskWrapper.setNewTask(false); mTaskWrapper.setNewTask(false);
mTaskRecord = mAdapter.createTaskRecord(threadNum); mTaskRecord = createTaskRecord(threadNum);
mTaskRecord.isBlock = false; mTaskRecord.isBlock = false;
File tempFile = new File(getFilePath()); File tempFile = new File(getFilePath());
for (int i = 0; i < threadNum; i++) { for (int i = 0; i < threadNum; i++) {
@ -158,7 +165,7 @@ public class RecordHandler implements IRecordHandler {
*/ */
private void initRecord(boolean newRecord) { private void initRecord(boolean newRecord) {
if (newRecord) { if (newRecord) {
mTaskRecord = mAdapter.createTaskRecord(mAdapter.initTaskThreadNum()); mTaskRecord = createTaskRecord(initTaskThreadNum());
} }
mTaskWrapper.setNewTask(true); mTaskWrapper.setNewTask(true);
int requestType = mTaskWrapper.getRequestType(); int requestType = mTaskWrapper.getRequestType();
@ -169,7 +176,7 @@ public class RecordHandler implements IRecordHandler {
// 处理线程区间记录 // 处理线程区间记录
for (int i = 0; i < mTaskRecord.threadNum; i++) { for (int i = 0; i < mTaskRecord.threadNum; i++) {
long startL = i * blockSize, endL = (i + 1) * blockSize; long startL = i * blockSize, endL = (i + 1) * blockSize;
ThreadRecord tr = mAdapter.createThreadRecord(mTaskRecord, i, startL, endL); ThreadRecord tr = createThreadRecord(mTaskRecord, i, startL, endL);
mTaskRecord.threadRecords.add(tr); mTaskRecord.threadRecords.add(tr);
} }
} }
@ -198,4 +205,23 @@ public class RecordHandler implements IRecordHandler {
return ((UploadEntity) mTaskWrapper.getEntity()).getFilePath(); return ((UploadEntity) mTaskWrapper.getEntity()).getFilePath();
} }
} }
@Override public void accept(ILoaderVisitor visitor) {
visitor.addComponent(this);
}
@Override public boolean checkTaskCompleted() {
if (mTaskRecord == null
|| mTaskRecord.threadRecords == null
|| mTaskRecord.threadRecords.isEmpty()) {
return false;
}
int completeNum = 0;
for (ThreadRecord tr : mTaskRecord.threadRecords) {
if (tr.isComplete) {
completeNum++;
}
}
return completeNum != 0 && completeNum == mTaskRecord.threadNum;
}
} }

@ -17,7 +17,7 @@ package com.arialyy.aria.core.common;
import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.ThreadRecord; import com.arialyy.aria.core.ThreadRecord;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile; import com.arialyy.aria.util.BufferedRandomAccessFile;

@ -62,13 +62,13 @@ public class XMLReader extends DefaultHandler {
String value = attributes.getValue("value"); String value = attributes.getValue("value");
switch (qName) { switch (qName) {
case "threadNum": // 线程数 case "getCreatedThreadNum": // 线程数
int threadNum = checkInt(value) ? Integer.parseInt(value) : 3; int threadNum = checkInt(value) ? Integer.parseInt(value) : 3;
if (threadNum < 1) { if (threadNum < 1) {
ALog.w(TAG, "下载线程数不能小于 1"); ALog.w(TAG, "下载线程数不能小于 1");
threadNum = 1; threadNum = 1;
} }
setField("threadNum", threadNum, ConfigType.DOWNLOAD); setField("getCreatedThreadNum", threadNum, ConfigType.DOWNLOAD);
break; break;
case "maxTaskNum": //最大任务书 case "maxTaskNum": //最大任务书
int maxTaskNum = checkInt(value) ? Integer.parseInt(value) : 2; int maxTaskNum = checkInt(value) ? Integer.parseInt(value) : 2;

@ -37,7 +37,7 @@ import java.util.concurrent.TimeUnit;
* Created by AriaL on 2017/6/30. * Created by AriaL on 2017/6/30.
* 任务组核心逻辑 * 任务组核心逻辑
*/ */
public abstract class AbsGroupUtil implements IUtil, Runnable { public abstract class AbsGroupLoaderUtil implements IUtil, Runnable {
protected final String TAG = CommonUtil.getClassName(getClass()); protected final String TAG = CommonUtil.getClassName(getClass());
private long mCurrentLocation = 0; private long mCurrentLocation = 0;
@ -52,7 +52,7 @@ public abstract class AbsGroupUtil implements IUtil, Runnable {
private DGTaskWrapper mGTWrapper; private DGTaskWrapper mGTWrapper;
private GroupRunState mState; private GroupRunState mState;
protected AbsGroupUtil(AbsTaskWrapper groupWrapper, IEventListener listener) { protected AbsGroupLoaderUtil(AbsTaskWrapper groupWrapper, IEventListener listener) {
mListener = (IDGroupListener) listener; mListener = (IDGroupListener) listener;
mGTWrapper = (DGTaskWrapper) groupWrapper; mGTWrapper = (DGTaskWrapper) groupWrapper;
mUpdateInterval = Configuration.getInstance().downloadCfg.getUpdateInterval(); mUpdateInterval = Configuration.getInstance().downloadCfg.getUpdateInterval();

@ -30,7 +30,7 @@ import java.util.concurrent.TimeUnit;
/** /**
* 组合任务子任务调度器用于调度任务的开始停止失败完成等情况 * 组合任务子任务调度器用于调度任务的开始停止失败完成等情况
* 该调度器生命周期和{@link AbsGroupUtil}生命周期一致 * 该调度器生命周期和{@link AbsGroupLoaderUtil}生命周期一致
*/ */
class SimpleSchedulers implements ISchedulers { class SimpleSchedulers implements ISchedulers {
private static final String TAG = "SimpleSchedulers"; private static final String TAG = "SimpleSchedulers";

@ -26,7 +26,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
* 组合任务队列该队列生命周期和{@link AbsGroupUtil}生命周期一致 * 组合任务队列该队列生命周期和{@link AbsGroupLoaderUtil}生命周期一致
*/ */
class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> { class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> {
private static final String TAG = "SimpleSubQueue"; private static final String TAG = "SimpleSubQueue";

@ -16,11 +16,14 @@
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.inf;
import android.os.Handler; import android.os.Handler;
import android.os.Looper;
import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.loader.ILoaderComponent;
/** /**
* 线程任务状态 * 线程任务状态
*/ */
public interface IThreadState extends Handler.Callback { public interface IThreadState extends ILoaderComponent {
int STATE_STOP = 0x01; int STATE_STOP = 0x01;
int STATE_FAIL = 0x02; int STATE_FAIL = 0x02;
int STATE_CANCEL = 0x03; int STATE_CANCEL = 0x03;
@ -50,4 +53,14 @@ public interface IThreadState extends Handler.Callback {
* @return 任务当前进度 * @return 任务当前进度
*/ */
long getCurrentProgress(); long getCurrentProgress();
/**
* 设置消息循环体
*/
void setLooper(TaskRecord taskRecord, Looper looper);
/**
* 创建handler 回调
*/
Handler.Callback getHandlerCallback();
} }

@ -19,7 +19,7 @@ import android.os.Handler;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.inf.TaskSchedulerType; import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.task.AbsTask; import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;

@ -17,7 +17,7 @@ package com.arialyy.aria.core.listener;
import android.os.Handler; import android.os.Handler;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.inf.TaskSchedulerType; import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.task.AbsTask; import com.arialyy.aria.core.task.AbsTask;
import com.arialyy.aria.core.upload.UTaskWrapper; import com.arialyy.aria.core.upload.UTaskWrapper;

@ -21,7 +21,7 @@ import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity; import com.arialyy.aria.core.download.DownloadGroupEntity;
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.IEntity;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.inf.TaskSchedulerType; import com.arialyy.aria.core.inf.TaskSchedulerType;
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;

@ -16,9 +16,7 @@
package com.arialyy.aria.core.loader; package com.arialyy.aria.core.loader;
import android.os.Looper; import android.os.Looper;
import android.util.SparseArray;
import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.inf.IRecordHandler;
import com.arialyy.aria.core.inf.IThreadState; import com.arialyy.aria.core.inf.IThreadState;
import com.arialyy.aria.core.listener.IEventListener; import com.arialyy.aria.core.listener.IEventListener;
import com.arialyy.aria.core.manager.ThreadTaskManager; import com.arialyy.aria.core.manager.ThreadTaskManager;
@ -27,20 +25,27 @@ import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* Created by AriaL on 2017/7/1. * Created by AriaL on 2017/7/1.
* 控制线程任务状态开始停止取消重试 * 任务执行器用于处理任务的开始停止
* 流程
* 1获取任务记录
* 2创建任务状态管理器用于管理任务的状态
* 3创建文件信息获取器获取文件信息根据文件信息执行任务
* 4创建线程任务执行下载上传操作
*/ */
public abstract class AbsLoader implements Runnable { public abstract class AbsLoader implements ILoaderVisitor, ILoader {
protected final String TAG; protected final String TAG;
protected IEventListener mListener; protected IEventListener mListener;
protected AbsTaskWrapper mTaskWrapper; protected AbsTaskWrapper mTaskWrapper;
protected File mTempFile; protected File mTempFile;
private SparseArray<IThreadTask> mTask = new SparseArray<>(); private List<IThreadTask> mTask = new ArrayList<>();
private ScheduledThreadPoolExecutor mTimer; private ScheduledThreadPoolExecutor mTimer;
/** /**
@ -48,20 +53,23 @@ public abstract class AbsLoader implements Runnable {
*/ */
private long mUpdateInterval = 1000; private long mUpdateInterval = 1000;
protected TaskRecord mRecord; protected TaskRecord mRecord;
private IThreadState mStateManager;
private boolean isCancel = false, isStop = false; private boolean isCancel = false, isStop = false;
private boolean isRuning = false; private boolean isRuning = false;
private Looper mLooper;
protected AbsLoader(IEventListener listener, AbsTaskWrapper wrapper) { protected IRecordHandler mRecordHandler;
protected IThreadState mStateManager;
protected IInfoTask mInfoTask;
protected IThreadTaskBuilder mTTBuilder;
protected AbsLoader(AbsTaskWrapper wrapper, IEventListener listener) {
mListener = listener; mListener = listener;
mTaskWrapper = wrapper; mTaskWrapper = wrapper;
TAG = CommonUtil.getClassName(getClass()); TAG = CommonUtil.getClassName(getClass());
} }
protected abstract IThreadState createStateManager(Looper looper);
/** /**
* 处理任务 * 启动线程任务
*/ */
protected abstract void handleTask(); protected abstract void handleTask();
@ -70,11 +78,6 @@ public abstract class AbsLoader implements Runnable {
*/ */
public abstract long getFileSize(); public abstract long getFileSize();
/**
* 获取当前任务位置
*/
public abstract long getCurrentLocation();
public IThreadState getStateManager() { public IThreadState getStateManager() {
return mStateManager; return mStateManager;
} }
@ -83,7 +86,7 @@ public abstract class AbsLoader implements Runnable {
return mTaskWrapper.getKey(); return mTaskWrapper.getKey();
} }
public SparseArray<IThreadTask> getTaskList() { public List<IThreadTask> getTaskList() {
return mTask; return mTask;
} }
@ -94,16 +97,20 @@ public abstract class AbsLoader implements Runnable {
closeTimer(); closeTimer();
if (mTask != null && mTask.size() != 0) { if (mTask != null && mTask.size() != 0) {
for (int i = 0; i < mTask.size(); i++) { for (int i = 0; i < mTask.size(); i++) {
mTask.valueAt(i).breakTask(); mTask.get(i).breakTask();
} }
mTask.clear(); mTask.clear();
} }
} }
/** @Override public void run() {
* 任务记录工具 checkComponent();
*/ if (isRunning()) {
protected abstract IRecordHandler getRecordHandler(AbsTaskWrapper wrapper); ALog.d(TAG, String.format("任务【%s】正在执行,启动任务失败", mTaskWrapper.getKey()));
return;
}
startFlow();
}
/** /**
* 开始流程 * 开始流程
@ -114,21 +121,18 @@ public abstract class AbsLoader implements Runnable {
} }
isRuning = true; isRuning = true;
resetState(); resetState();
mRecord = getRecordHandler(mTaskWrapper).getRecord();
Looper.prepare();
Looper looper = Looper.myLooper();
mStateManager = createStateManager(looper);
onPostPre(); onPostPre();
handleTask(); handleTask();
startTimer(); startTimer();
Looper.loop(); Looper.loop();
} }
@Override public void run() { @Override public Looper getLooper() {
if (isRunning()) { if (mLooper == null) {
return; Looper.prepare();
mLooper = Looper.myLooper();
} }
startFlow(); return mLooper;
} }
/** /**
@ -212,7 +216,7 @@ public abstract class AbsLoader implements Runnable {
isCancel = true; isCancel = true;
onCancel(); onCancel();
for (int i = 0; i < mTask.size(); i++) { for (int i = 0; i < mTask.size(); i++) {
IThreadTask task = mTask.valueAt(i); IThreadTask task = mTask.get(i);
if (task != null && !task.isThreadComplete()) { if (task != null && !task.isThreadComplete()) {
task.cancel(); task.cancel();
} }
@ -245,7 +249,7 @@ public abstract class AbsLoader implements Runnable {
isStop = true; isStop = true;
onStop(); onStop();
for (int i = 0; i < mTask.size(); i++) { for (int i = 0; i < mTask.size(); i++) {
IThreadTask task = mTask.valueAt(i); IThreadTask task = mTask.get(i);
if (task != null && !task.isThreadComplete()) { if (task != null && !task.isThreadComplete()) {
task.stop(); task.stop();
} }
@ -253,7 +257,7 @@ public abstract class AbsLoader implements Runnable {
ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey()); ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey());
onPostStop(); onPostStop();
onDestroy(); onDestroy();
mListener.onStop(getCurrentLocation()); mListener.onStop(getCurrentProgress());
} }
/** /**
@ -270,17 +274,6 @@ public abstract class AbsLoader implements Runnable {
} }
/**
* 直接调用的时候会自动启动线程执行
*/
public synchronized void start() {
if (isRunning()) {
ALog.d(TAG, String.format("任务【%s】正在执行,启动任务失败", mTaskWrapper.getKey()));
return;
}
new Thread(this).start();
}
/** /**
* 重试任务 * 重试任务
*/ */
@ -303,4 +296,22 @@ public abstract class AbsLoader implements Runnable {
} }
return false; return false;
} }
/**
* 检查组件: {@link #mRecordHandler}{@link #mInfoTask}{@link #mStateManager}{@link #mTTBuilder}
*/
private void checkComponent() {
if (mRecordHandler == null) {
throw new NullPointerException("任务记录组件为空");
}
if (mInfoTask == null) {
throw new NullPointerException(("文件信息组件为空"));
}
if (mStateManager == null) {
throw new NullPointerException("任务状态管理组件为空");
}
if (mTTBuilder == null) {
throw new NullPointerException("线程任务组件为空");
}
}
} }

@ -29,19 +29,25 @@ import com.arialyy.aria.util.CommonUtil;
public abstract class AbsNormalLoaderUtil implements IUtil { public abstract class AbsNormalLoaderUtil implements IUtil {
protected String TAG = CommonUtil.getClassName(getClass()); protected String TAG = CommonUtil.getClassName(getClass());
private IEventListener mListener; private IEventListener mListener;
private AbsLoader mLoader; protected AbsLoader mLoader;
private AbsTaskWrapper mTaskWrapper; private AbsTaskWrapper mTaskWrapper;
private boolean isStop = false, isCancel = false; private boolean isStop = false, isCancel = false;
protected AbsNormalLoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) { protected AbsNormalLoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) {
mTaskWrapper = wrapper; mTaskWrapper = wrapper;
mListener = listener; mListener = listener;
mLoader = createLoader(); mLoader = getLoader();
} }
public AbsLoader getLoader() { /**
return mLoader; * 获取加载器
} */
public abstract AbsLoader getLoader();
/**
* 获取构造器
*/
public abstract LoaderStructure getLoaderStructure();
@Override public String getKey() { @Override public String getKey() {
return mTaskWrapper.getKey(); return mTaskWrapper.getKey();
@ -55,7 +61,7 @@ public abstract class AbsNormalLoaderUtil implements IUtil {
* 获取当前下载位置 * 获取当前下载位置
*/ */
@Override public long getCurrentLocation() { @Override public long getCurrentLocation() {
return mLoader.getCurrentLocation(); return mLoader.getCurrentProgress();
} }
@Override public boolean isRunning() { @Override public boolean isRunning() {
@ -105,10 +111,10 @@ public abstract class AbsNormalLoaderUtil implements IUtil {
//} else { //} else {
// mDownloader.create(); // mDownloader.create();
//} //}
Runnable runnable = createInfoThread();
if (runnable != null) { getLoaderStructure();
new Thread(runnable).start(); new Thread(mLoader).start();
}
onStart(); onStart();
} }
@ -139,14 +145,4 @@ public abstract class AbsNormalLoaderUtil implements IUtil {
public AbsTaskWrapper getTaskWrapper() { public AbsTaskWrapper getTaskWrapper() {
return mTaskWrapper; return mTaskWrapper;
} }
/**
* 创建加载器的适配器
*/
protected abstract AbsLoader createLoader();
/**
* 通过链接类型创建不同的获取文件信息的线程
*/
protected abstract Runnable createInfoThread();
} }

@ -0,0 +1,185 @@
package com.arialyy.aria.core.loader;
import android.os.Handler;
import android.os.Looper;
import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.ThreadRecord;
import com.arialyy.aria.core.common.AbsNormalEntity;
import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.inf.IThreadState;
import com.arialyy.aria.core.task.IThreadTask;
import com.arialyy.aria.core.task.IThreadTaskAdapter;
import com.arialyy.aria.core.task.ThreadTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public abstract class AbsNormalTTBuilder implements IThreadTaskBuilder {
protected String TAG = CommonUtil.getClassName(this);
private Handler mStateHandler;
private AbsTaskWrapper mWrapper;
private TaskRecord mRecord;
private int mTotalThreadNum;
private File mTempFile;
private int mStartThreadNum;
public AbsNormalTTBuilder(AbsTaskWrapper wrapper) {
if (wrapper instanceof DGTaskWrapper) {
throw new AssertionError("NormalTTBuilder 不适用于组合任务");
}
mWrapper = wrapper;
mTempFile = new File(((AbsNormalEntity) wrapper.getEntity()).getFilePath());
}
protected File getTempFile(){
return mTempFile;
}
protected AbsNormalEntity getEntity() {
return (AbsNormalEntity) mWrapper.getEntity();
}
/**
* 创建线程任务适配器
*/
public abstract IThreadTaskAdapter getAdapter(SubThreadConfig config);
/**
* 处理新任务
*
* @param record 任务记录
* @param totalThreadNum 任务的线程总数
* @return {@code true}创建新任务成功
*/
public abstract boolean handleNewTask(TaskRecord record, int totalThreadNum);
/**
* 创建线程任务
*/
private IThreadTask createThreadTask(SubThreadConfig config) {
ThreadTask task = new ThreadTask(config);
task.setAdapter(getAdapter(config));
return task;
}
/**
* 启动断点任务时创建单线程任务
*
* @param record 线程记录
* @param startNum 启动的线程数
*/
private IThreadTask createSingThreadTask(ThreadRecord record, int startNum) {
SubThreadConfig config = new SubThreadConfig();
config.url = getEntity().isRedirect() ? getEntity().getRedirectUrl() : getEntity().getUrl();
config.tempFile =
mRecord.isBlock ? new File(
String.format(IRecordHandler.SUB_PATH, mTempFile.getPath(), record.threadId))
: mTempFile;
config.isBlock = mRecord.isBlock;
config.startThreadNum = startNum;
config.taskWrapper = mWrapper;
config.record = record;
config.stateHandler = mStateHandler;
return createThreadTask(config);
}
/**
* 处理不支持断点的任务
*/
private List<IThreadTask> handleNoSupportBP() {
List<IThreadTask> list = new ArrayList<>();
mStartThreadNum = 1;
IThreadTask task = createSingThreadTask(mRecord.threadRecords.get(0), 1);
if (task == null) {
ALog.e(TAG, "创建线程任务失败");
return null;
}
list.add(task);
return list;
}
/**
* 处理支持断点的任务
*/
private List<IThreadTask> handleBreakpoint() {
long fileLength = getEntity().getFileSize();
long blockSize = fileLength / mTotalThreadNum;
long currentProgress = 0;
List<IThreadTask> threadTasks = new ArrayList<>();
mRecord.fileLength = fileLength;
if (mWrapper.isNewTask() && !handleNewTask(mRecord, mTotalThreadNum)) {
ALog.e(TAG, "初始化线程任务失败");
return null;
}
for (ThreadRecord tr : mRecord.threadRecords) {
if (!tr.isComplete) {
mStartThreadNum++;
}
}
for (int i = 0; i < mTotalThreadNum; i++) {
long startL = i * blockSize, endL = (i + 1) * blockSize;
ThreadRecord tr = mRecord.threadRecords.get(i);
if (tr.isComplete) {//该线程已经完成
currentProgress += endL - startL;
ALog.d(TAG, String.format("任务【%s】线程__%s__已完成", mWrapper.getKey(), i));
mStateHandler.obtainMessage(IThreadState.STATE_COMPLETE).sendToTarget();
continue;
}
//如果有记录,则恢复任务
long r = tr.startLocation;
//记录的位置需要在线程区间中
if (startL < r && r <= (i == (mTotalThreadNum - 1) ? fileLength : endL)) {
currentProgress += r - startL;
}
ALog.d(TAG, String.format("任务【%s】线程__%s__恢复任务", getEntity().getFileName(), i));
IThreadTask task = createSingThreadTask(tr, mStartThreadNum);
if (task == null) {
ALog.e(TAG, "创建线程任务失败");
return null;
}
threadTasks.add(task);
}
if (currentProgress != 0 && currentProgress != getEntity().getCurrentProgress()) {
ALog.d(TAG, String.format("进度修正,当前进度:%s", currentProgress));
getEntity().setCurrentProgress(currentProgress);
}
//mStateManager.updateProgress(currentProgress);
return threadTasks;
}
private List<IThreadTask> handleTask() {
if (mWrapper.isSupportBP()) {
return handleBreakpoint();
}else {
return handleNoSupportBP();
}
}
@Override public List<IThreadTask> buildThreadTask(TaskRecord record, Looper looper,
IThreadState stateManager) {
mRecord = record;
mStateHandler = new Handler(looper, stateManager.getHandlerCallback());
mTotalThreadNum = mRecord.threadNum;
return handleTask();
}
@Override public int getCreatedThreadNum() {
return mStartThreadNum;
}
@Override public void accept(ILoaderVisitor visitor) {
visitor.addComponent(this);
}
}

@ -13,24 +13,40 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.loader;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.AbsEntity; import com.arialyy.aria.core.common.AbsEntity;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.BaseException;
public interface OnFileInfoCallback { /**
* 任务信息采集
*/
public interface IInfoTask extends ILoaderComponent {
/** /**
* 处理完成 * 执行任务
*
* @param info 一些回调的信息
*/ */
void onComplete(String key, CompleteInfo info); void run();
/** /**
* 请求失败 * 设置回调
*
* @param e 错误信息
*/ */
void onFail(AbsEntity entity, BaseException e, boolean needRetry); void setCallback(Callback callback);
}
interface Callback {
/**
* 处理完成
*
* @param info 一些回调的信息
*/
void onSucceed(String key, CompleteInfo info);
/**
* 请求失败
*
* @param e 错误信息
*/
void onFail(AbsEntity entity, BaseException e, boolean needRetry);
}
}

@ -15,15 +15,24 @@
*/ */
package com.arialyy.aria.core.loader; package com.arialyy.aria.core.loader;
public interface ILoader { import android.os.Looper;
void start(); public interface ILoader extends Runnable{
//void start();
void stop(); void stop();
void isBreak(); /**
* 任务是否被中断停止取消
*
* @return true 任务中断false 任务没有中断
*/
boolean isBreak();
String getKey(); String getKey();
long getCurrentProgress(); long getCurrentProgress();
Looper getLooper();
} }

@ -16,7 +16,6 @@
package com.arialyy.aria.core.loader; package com.arialyy.aria.core.loader;
import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.inf.IRecordHandler;
import com.arialyy.aria.core.task.IThreadTask; import com.arialyy.aria.core.task.IThreadTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;

@ -15,33 +15,11 @@
*/ */
package com.arialyy.aria.core.loader; package com.arialyy.aria.core.loader;
public class LoaderIntercept implements ILoaderInterceptor, ILoader { /**
* 加载器部件
*/
public interface ILoaderComponent {
@Override public ILoader intercept(Chain chain) {
return this;
}
@Override public void start() {
}
@Override public void stop() {
}
@Override public void isBreak() {
}
@Override public String getKey() { void accept(ILoaderVisitor visitor);
return null;
}
@Override public long getCurrentProgress() {
return 0;
}
} }

@ -15,27 +15,30 @@
*/ */
package com.arialyy.aria.core.loader; package com.arialyy.aria.core.loader;
import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.inf.IThreadState;
import com.arialyy.aria.core.listener.IEventListener;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
/** /**
* 拦截器 * 加载器访问者
*/ */
public interface ILoaderInterceptor { public interface ILoaderVisitor {
ILoader intercept(Chain chain); /**
* 处理任务记录
interface Chain { */
void addComponent(IRecordHandler recordHandler);
void updateRecord(TaskRecord record);
/**
TaskRecord getRecord(); * 处理任务的文件信息
*/
IEventListener getListener(); void addComponent(IInfoTask infoTask);
ITaskWrapper getWrapper(); /**
* 线程状态
ILoader proceed(); */
} void addComponent(IThreadState threadState);
/**
* 构造线程任务
*/
void addComponent(IThreadTaskBuilder builder);
} }

@ -13,18 +13,38 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.loader;
import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.ThreadRecord; import com.arialyy.aria.core.ThreadRecord;
/** /**
* 任务记录处理适配器
*
* @Author lyy * @Author lyy
* @Date 2019-09-19 * @Date 2019-09-18
*/ */
public interface IRecordHandlerAdapter { public interface IRecordHandler extends ILoaderComponent {
int TYPE_DOWNLOAD = 1;
int TYPE_UPLOAD = 2;
int TYPE_M3U8_VOD = 3;
int TYPE_M3U8_LIVE = 4;
String STATE = "_state_";
String RECORD = "_record_";
/**
* 小于1m的文件不启用多线程
*/
long SUB_LEN = 1024 * 1024;
/**
* 分块文件路径
*/
String SUB_PATH = "%s.%s.part";
/**
* 获取任务记录
*/
TaskRecord getRecord();
/** /**
* 记录处理前的操作可用来删除任务记录 * 记录处理前的操作可用来删除任务记录
@ -57,4 +77,11 @@ public interface IRecordHandlerAdapter {
* @return 新任务的线程数 * @return 新任务的线程数
*/ */
int initTaskThreadNum(); int initTaskThreadNum();
/**
* 检查任务是否已完成
*
* @return true 任务已完成
*/
boolean checkTaskCompleted();
} }

@ -13,35 +13,26 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.loader;
import android.os.Looper;
import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.inf.IThreadState;
import com.arialyy.aria.core.task.IThreadTask;
import java.util.List;
/** /**
* @Author lyy * 线程任务构造器
* @Date 2019-09-18
*/ */
public interface IRecordHandler { public interface IThreadTaskBuilder extends ILoaderComponent {
int TYPE_DOWNLOAD = 1;
int TYPE_UPLOAD = 2;
int TYPE_M3U8_VOD = 3;
int TYPE_M3U8_LIVE = 4;
String STATE = "_state_";
String RECORD = "_record_";
/**
* 小于1m的文件不启用多线程
*/
long SUB_LEN = 1024 * 1024;
/** /**
* 分块文件路径 * 构造线程任务
*/ */
String SUB_PATH = "%s.%s.part"; List<IThreadTask> buildThreadTask(TaskRecord record, Looper looper, IThreadState stateManager);
/** /**
* 获取任务记录 * 获取创建的线程任务数需要先调用{@link #buildThreadTask(TaskRecord, Looper, IThreadState)}方法才能获取创建的线程任务数
*/ */
TaskRecord getRecord(); int getCreatedThreadNum();
} }

@ -1,75 +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.core.loader;
import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.listener.IEventListener;
import com.arialyy.aria.core.wrapper.ITaskWrapper;
import java.util.List;
/**
* 责任链
*/
public final class LoaderChain implements ILoaderInterceptor.Chain {
private ITaskWrapper wrapper;
private IEventListener listener;
private TaskRecord taskRecord;
private int index;
private List<ILoaderInterceptor> interceptors;
public LoaderChain(List<ILoaderInterceptor> interceptors, ITaskWrapper wrapper,
IEventListener listener, TaskRecord taskRecord,
int index) {
this.interceptors = interceptors;
this.wrapper = wrapper;
this.listener = listener;
this.taskRecord = taskRecord;
this.index = index;
}
@Override public void updateRecord(TaskRecord record) {
this.taskRecord = record;
}
@Override public TaskRecord getRecord() {
return taskRecord;
}
@Override public IEventListener getListener() {
return listener;
}
@Override public ITaskWrapper getWrapper() {
return wrapper;
}
@Override public ILoader proceed() {
int index = this.index + 1;
if (index >= interceptors.size()) {
throw new AssertionError();
}
LoaderChain next = new LoaderChain(interceptors, wrapper, listener, taskRecord, index);
ILoaderInterceptor interceptor = interceptors.get(index);
ILoader loader = interceptor.intercept(next);
if (loader == null) {
throw new NullPointerException("Loader为空");
}
return loader;
}
}

@ -15,25 +15,31 @@
*/ */
package com.arialyy.aria.core.loader; package com.arialyy.aria.core.loader;
import com.arialyy.aria.core.common.RecordHandler; import com.arialyy.aria.core.inf.IThreadState;
import com.arialyy.aria.core.inf.IRecordHandlerAdapter; import java.util.ArrayList;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import java.util.List;
/** public class LoaderStructure {
* 任务记录拦截器用于处理任务记录 private List<ILoaderComponent> parts = new ArrayList<>();
*/
public final class RecordInterceptor implements ILoaderInterceptor {
private IRecordHandlerAdapter adapter;
public RecordInterceptor(IRecordHandlerAdapter adapter) { public void accept(ILoaderVisitor visitor) {
this.adapter = adapter;
}
@Override public ILoader intercept(Chain chain) { for (ILoaderComponent part : parts) {
RecordHandler recordHandler = new RecordHandler((AbsTaskWrapper) chain.getWrapper()); part.accept(visitor);
recordHandler.setAdapter(adapter); }
chain.updateRecord(recordHandler.getRecord()); }
return chain.proceed(); /**
* 将组件加入到集合必须添加以下集合
* 1 {@link IRecordHandler}
* 2 {@link IInfoTask}
* 3 {@link IThreadState}
* 4 {@link IThreadTaskBuilder}
*
* @param component 待添加的组件
*/
public LoaderStructure addComponent(ILoaderComponent component) {
parts.add(component);
return this;
} }
} }

@ -15,20 +15,17 @@
*/ */
package com.arialyy.aria.core.loader; package com.arialyy.aria.core.loader;
import android.os.Handler; import com.arialyy.aria.core.common.AbsEntity;
import android.os.Looper;
import com.arialyy.aria.core.ThreadRecord;
import com.arialyy.aria.core.common.AbsNormalEntity; import com.arialyy.aria.core.common.AbsNormalEntity;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.event.EventMsgUtil; import com.arialyy.aria.core.event.EventMsgUtil;
import com.arialyy.aria.core.inf.IRecordHandler;
import com.arialyy.aria.core.inf.IThreadState; import com.arialyy.aria.core.inf.IThreadState;
import com.arialyy.aria.core.listener.BaseDListener;
import com.arialyy.aria.core.listener.IDLoadListener; import com.arialyy.aria.core.listener.IDLoadListener;
import com.arialyy.aria.core.listener.IEventListener; import com.arialyy.aria.core.listener.IEventListener;
import com.arialyy.aria.core.manager.ThreadTaskManager; import com.arialyy.aria.core.manager.ThreadTaskManager;
import com.arialyy.aria.core.task.IThreadTask; import com.arialyy.aria.core.task.IThreadTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import java.io.File; import java.io.File;
@ -36,23 +33,15 @@ import java.io.File;
* 单文件 * 单文件
*/ */
public class NormalLoader extends AbsLoader { public class NormalLoader extends AbsLoader {
private ThreadStateManager mStateManager;
private Handler mStateHandler;
protected int mTotalThreadNum; //总线程数
private int mStartThreadNum; //启动的线程数 private int mStartThreadNum; //启动的线程数
private ILoaderAdapter mAdapter;
public NormalLoader(IEventListener listener, AbsTaskWrapper wrapper) { public NormalLoader(AbsTaskWrapper wrapper, IEventListener listener) {
super(listener, wrapper); super(wrapper, listener);
mTempFile = new File(getEntity().getFilePath()); mTempFile = new File(getEntity().getFilePath());
EventMsgUtil.getDefault().register(this); EventMsgUtil.getDefault().register(this);
setUpdateInterval(wrapper.getConfig().getUpdateInterval()); setUpdateInterval(wrapper.getConfig().getUpdateInterval());
} }
public void setAdapter(ILoaderAdapter adapter) {
mAdapter = adapter;
}
public AbsNormalEntity getEntity() { public AbsNormalEntity getEntity() {
return (AbsNormalEntity) mTaskWrapper.getEntity(); return (AbsNormalEntity) mTaskWrapper.getEntity();
} }
@ -61,24 +50,15 @@ public class NormalLoader extends AbsLoader {
return getEntity().getFileSize(); return getEntity().getFileSize();
} }
@Override public long getCurrentLocation() {
return isRunning() ? mStateManager.getCurrentProgress() : getEntity().getCurrentProgress();
}
@Override protected IRecordHandler getRecordHandler(AbsTaskWrapper wrapper) {
return mAdapter.recordHandler(wrapper);
}
/** /**
* 设置最大下载/上传速度 * 设置最大下载/上传速度AbsFtpInfoThread
* *
* @param maxSpeed 单位为kb * @param maxSpeed 单位为kb
*/ */
protected void setMaxSpeed(int maxSpeed) { protected void setMaxSpeed(int maxSpeed) {
for (int i = 0; i < getTaskList().size(); i++) { for (IThreadTask threadTask : getTaskList()) {
IThreadTask task = getTaskList().valueAt(i); if (threadTask != null && mStartThreadNum > 0) {
if (task != null && mStartThreadNum > 0) { threadTask.setMaxSpeed(maxSpeed / mStartThreadNum);
task.setMaxSpeed(maxSpeed / mStartThreadNum);
} }
} }
} }
@ -90,11 +70,6 @@ public class NormalLoader extends AbsLoader {
@Override protected void onPostPre() { @Override protected void onPostPre() {
super.onPostPre(); super.onPostPre();
if (mAdapter == null) {
throw new NullPointerException("请使用adapter设置适配器");
}
mTotalThreadNum = mRecord.threadNum;
if (mListener instanceof IDLoadListener) { if (mListener instanceof IDLoadListener) {
((IDLoadListener) mListener).onPostPre(getEntity().getFileSize()); ((IDLoadListener) mListener).onPostPre(getEntity().getFileSize());
} }
@ -114,126 +89,63 @@ public class NormalLoader extends AbsLoader {
} }
} }
@Override protected IThreadState createStateManager(Looper looper) {
mStateManager = new ThreadStateManager(looper, mRecord, mListener);
mStateHandler = new Handler(looper, mStateManager);
return mStateManager;
}
@Override protected void handleTask() {
if (mTaskWrapper.isSupportBP()) {
handleBreakpoint();
} else {
handleNoSupportBP();
}
}
/** /**
* 启动断点任务时创建单线程任务 * 启动单线程任务
*
* @param record 线程记录
* @param startNum 启动的线程数
*/ */
private IThreadTask createSingThreadTask(ThreadRecord record, int startNum) { @Override
SubThreadConfig config = new SubThreadConfig(); public void handleTask() {
config.url = getEntity().isRedirect() ? getEntity().getRedirectUrl() : getEntity().getUrl(); if (isBreak()) {
config.tempFile =
mRecord.isBlock ? new File(
String.format(IRecordHandler.SUB_PATH, mTempFile.getPath(), record.threadId))
: mTempFile;
config.isBlock = mRecord.isBlock;
config.startThreadNum = startNum;
config.taskWrapper = mTaskWrapper;
config.record = record;
config.stateHandler = mStateHandler;
return mAdapter.createThreadTask(config);
}
private void handleBreakpoint() {
long fileLength = getEntity().getFileSize();
long blockSize = fileLength / mTotalThreadNum;
long currentProgress = 0;
mRecord.fileLength = fileLength;
if (mTaskWrapper.isNewTask() && !mAdapter.handleNewTask(mRecord, mTotalThreadNum)) {
closeTimer();
mListener.onFail(false, null);
return; return;
} }
mStateManager.setLooper(mRecord, getLooper());
for (ThreadRecord tr : mRecord.threadRecords) { mInfoTask.run();
if (!tr.isComplete) {
mStartThreadNum++;
}
}
for (int i = 0; i < mTotalThreadNum; i++) {
long startL = i * blockSize, endL = (i + 1) * blockSize;
ThreadRecord tr = mRecord.threadRecords.get(i);
if (tr.isComplete) {//该线程已经完成
currentProgress += endL - startL;
ALog.d(TAG, String.format("任务【%s】线程__%s__已完成", mTaskWrapper.getKey(), i));
mStateHandler.obtainMessage(IThreadState.STATE_COMPLETE).sendToTarget();
if (mStateManager.isComplete()) {
mRecord.deleteData();
mListener.onComplete();
return;
}
continue;
}
//如果有记录,则恢复任务
long r = tr.startLocation;
//记录的位置需要在线程区间中
if (startL < r && r <= (i == (mTotalThreadNum - 1) ? fileLength : endL)) {
currentProgress += r - startL;
}
ALog.d(TAG, String.format("任务【%s】线程__%s__恢复任务", getEntity().getFileName(), i));
IThreadTask task = createSingThreadTask(tr, mStartThreadNum);
if (task == null) return;
getTaskList().put(tr.threadId, task);
}
if (currentProgress != 0 && currentProgress != getEntity().getCurrentProgress()) {
ALog.d(TAG, String.format("进度修正,当前进度:%s", currentProgress));
getEntity().setCurrentProgress(currentProgress);
}
mStateManager.updateProgress(currentProgress);
startThreadTask();
} }
/**
* 启动单线程任务
*/
private void startThreadTask() { private void startThreadTask() {
if (isBreak()) { getTaskList().addAll(mTTBuilder.buildThreadTask(mRecord, getLooper(), mStateManager));
return; mStartThreadNum = mTTBuilder.getCreatedThreadNum();
}
if (mStateManager.getCurrentProgress() > 0) { if (mStateManager.getCurrentProgress() > 0) {
mListener.onResume(mStateManager.getCurrentProgress()); mListener.onResume(mStateManager.getCurrentProgress());
} else { } else {
mListener.onStart(mStateManager.getCurrentProgress()); mListener.onStart(mStateManager.getCurrentProgress());
} }
for (int i = 0; i < getTaskList().size(); i++) { for (IThreadTask threadTask : getTaskList()) {
ThreadTaskManager.getInstance().startThread(mTaskWrapper.getKey(), getTaskList().valueAt(i)); ThreadTaskManager.getInstance().startThread(mTaskWrapper.getKey(), threadTask);
} }
} }
/** @Override public long getCurrentProgress() {
* 处理不支持断点的任务 return isRunning() ? mStateManager.getCurrentProgress() : getEntity().getCurrentProgress();
*/ }
private void handleNoSupportBP() {
if (mListener instanceof BaseDListener) { @Override public void addComponent(IRecordHandler recordHandler) {
((BaseDListener) mListener).supportBreakpoint(false); mRecordHandler = recordHandler;
mRecord = mRecordHandler.getRecord();
if (recordHandler.checkTaskCompleted()) {
mRecord.deleteData();
mListener.onComplete();
} }
mStartThreadNum = 1; }
@Override public void addComponent(IInfoTask infoTask) {
mInfoTask = infoTask;
infoTask.setCallback(new IInfoTask.Callback() {
@Override public void onSucceed(String key, CompleteInfo info) {
startThreadTask();
}
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
mListener.onFail(needRetry, e);
}
});
}
@Override public void addComponent(IThreadState threadState) {
mStateManager = threadState;
}
IThreadTask task = createSingThreadTask(mRecord.threadRecords.get(0), 1); @Override public void addComponent(IThreadTaskBuilder builder) {
if (task == null) return; mTTBuilder = builder;
getTaskList().put(0, task);
ThreadTaskManager.getInstance().startThread(mTaskWrapper.getKey(), task);
mListener.onStart(0);
} }
} }

@ -16,10 +16,10 @@
package com.arialyy.aria.core.loader; package com.arialyy.aria.core.loader;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.TaskRecord;
import com.arialyy.aria.core.inf.IRecordHandler;
import com.arialyy.aria.core.inf.IThreadState; import com.arialyy.aria.core.inf.IThreadState;
import com.arialyy.aria.core.listener.IEventListener; import com.arialyy.aria.core.listener.IEventListener;
import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.BaseException;
@ -49,76 +49,90 @@ public class ThreadStateManager implements IThreadState {
private Looper mLooper; private Looper mLooper;
/** /**
* @param taskRecord 任务记录
* @param listener 任务事件 * @param listener 任务事件
*/ */
ThreadStateManager(Looper looper, TaskRecord taskRecord, IEventListener listener) { public ThreadStateManager(IEventListener listener) {
mLooper = looper; mListener = listener;
}
@Override public void setLooper(TaskRecord taskRecord, Looper looper) {
mTaskRecord = taskRecord; mTaskRecord = taskRecord;
mThreadNum = mTaskRecord.threadNum; mThreadNum = mTaskRecord.threadNum;
mListener = listener; mLooper = looper;
} }
/** private void checkLooper(){
* 不要使用handle更新启动线程的进度因为有延迟 if (mTaskRecord == null){
*/ throw new NullPointerException("任务记录为空");
void updateProgress(long curProgress) { }
mProgress = curProgress; if (mLooper == null){
throw new NullPointerException("Looper为空");
}
} }
@Override public boolean handleMessage(Message msg) { private Handler.Callback callback = new Handler.Callback() {
switch (msg.what) { @Override public boolean handleMessage(Message msg) {
case STATE_STOP: checkLooper();
mStopNum++; switch (msg.what) {
if (isStop()) { case STATE_STOP:
quitLooper(); mStopNum++;
} if (isStop()) {
break; quitLooper();
case STATE_CANCEL: }
mCancelNum++; break;
if (isCancel()) { case STATE_CANCEL:
quitLooper(); mCancelNum++;
} if (isCancel()) {
break; quitLooper();
case STATE_FAIL: }
mFailNum++; break;
if (isFail()) { case STATE_FAIL:
Bundle b = msg.getData(); mFailNum++;
mListener.onFail(b.getBoolean(KEY_RETRY, false), if (isFail()) {
(BaseException) b.getSerializable(KEY_ERROR_INFO)); Bundle b = msg.getData();
quitLooper(); mListener.onFail(b.getBoolean(KEY_RETRY, false),
} (BaseException) b.getSerializable(KEY_ERROR_INFO));
break; quitLooper();
case STATE_COMPLETE: }
mCompleteNum++; break;
if (isComplete()) { case STATE_COMPLETE:
ALog.d(TAG, "isComplete, completeNum = " + mCompleteNum); mCompleteNum++;
if (mTaskRecord.isBlock) { if (isComplete()) {
if (mergeFile()) { ALog.d(TAG, "isComplete, completeNum = " + mCompleteNum);
mListener.onComplete(); if (mTaskRecord.isBlock) {
if (mergeFile()) {
mListener.onComplete();
} else {
mListener.onFail(false, null);
}
} else { } else {
mListener.onFail(false, null); mListener.onComplete();
} }
} else { quitLooper();
mListener.onComplete();
} }
quitLooper(); break;
} case STATE_RUNNING:
break; if (msg.obj instanceof Long) {
case STATE_RUNNING: mProgress += (long) msg.obj;
if (msg.obj instanceof Long) { }
mProgress += (long) msg.obj; break;
} case STATE_UPDATE_PROGRESS:
break; if (msg.obj == null) {
case STATE_UPDATE_PROGRESS: mProgress = updateBlockProgress();
if (msg.obj == null) { } else if (msg.obj instanceof Long) {
mProgress = updateBlockProgress(); mProgress = (long) msg.obj;
} else if (msg.obj instanceof Long) { }
mProgress = (long) msg.obj; break;
} }
break; return false;
} }
return false; };
/**
* 不要使用handle更新启动线程的进度因为有延迟
*/
void updateProgress(long curProgress) {
mProgress = curProgress;
} }
/** /**
@ -138,6 +152,10 @@ public class ThreadStateManager implements IThreadState {
return mProgress; return mProgress;
} }
@Override public Handler.Callback getHandlerCallback() {
return callback;
}
/** /**
* 所有子线程是否都已经停止 * 所有子线程是否都已经停止
*/ */
@ -226,4 +244,8 @@ public class ThreadStateManager implements IThreadState {
return false; return false;
} }
} }
@Override public void accept(ILoaderVisitor visitor) {
visitor.addComponent(this);
}
} }

@ -16,7 +16,7 @@
package com.arialyy.aria.core.task; package com.arialyy.aria.core.task;
import com.arialyy.aria.core.download.AbsGroupTaskWrapper; import com.arialyy.aria.core.download.AbsGroupTaskWrapper;
import com.arialyy.aria.core.group.AbsGroupUtil; import com.arialyy.aria.core.group.AbsGroupLoaderUtil;
/** /**
* Created by AriaL on 2017/6/29. * Created by AriaL on 2017/6/29.
@ -36,7 +36,7 @@ public abstract class AbsGroupTask<TASK_ENTITY extends AbsGroupTaskWrapper>
*/ */
public void startSubTask(String url) { public void startSubTask(String url) {
if (getUtil() != null) { if (getUtil() != null) {
((AbsGroupUtil) getUtil()).startSubTask(url); ((AbsGroupLoaderUtil) getUtil()).startSubTask(url);
} }
} }
@ -47,7 +47,7 @@ public abstract class AbsGroupTask<TASK_ENTITY extends AbsGroupTaskWrapper>
*/ */
public void stopSubTask(String url) { public void stopSubTask(String url) {
if (getUtil() != null) { if (getUtil() != null) {
((AbsGroupUtil) getUtil()).stopSubTask(url); ((AbsGroupLoaderUtil) getUtil()).stopSubTask(url);
} }
} }
} }

@ -87,4 +87,10 @@ public interface IThreadTask extends Callable<IThreadTask> {
* @return {@code true} 分块分大小正常{@code false} 分块大小错误 * @return {@code true} 分块分大小正常{@code false} 分块大小错误
*/ */
boolean checkBlock(); boolean checkBlock();
/**
* 获取线程id
* @return
*/
int getThreadId();
} }

@ -228,6 +228,10 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
return true; return true;
} }
@Override public int getThreadId() {
return mRecord.threadId;
}
/** /**
* 停止任务 * 停止任务
*/ */

@ -19,7 +19,7 @@ package com.arialyy.aria.util;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity; import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;

@ -23,7 +23,7 @@ import com.arialyy.aria.core.common.AbsNormalEntity;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity; import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.M3U8Entity; import com.arialyy.aria.core.download.M3U8Entity;
import com.arialyy.aria.core.inf.IRecordHandler; import com.arialyy.aria.core.loader.IRecordHandler;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.wrapper.ITaskWrapper; import com.arialyy.aria.core.wrapper.ITaskWrapper;
import com.arialyy.aria.core.wrapper.RecordWrapper; import com.arialyy.aria.core.wrapper.RecordWrapper;

@ -4,7 +4,7 @@
# Gradle settings configured through the IDE *will override* # Gradle settings configured through the IDE *will override*
# any settings specified in this file. # any settings specified in this file.
# For more details on how to configure your build environment visit # For more details on how to configure your build environment addComponent
# http://www.gradle.org/docs/current/userguide/build_environment.html # http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process. # Specifies the JVM arguments used for the daemon process.
@ -13,6 +13,6 @@
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit # This option should only be used with decoupled projects. More details, addComponent
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true

@ -44,8 +44,8 @@ task clean(type: Delete) {
} }
ext { ext {
versionCode = 381 versionCode = 382
versionName = '3.8.1' versionName = '3.8.2'
userOrg = 'arialyy' userOrg = 'arialyy'
groupId = 'com.arialyy.aria' groupId = 'com.arialyy.aria'
publishVersion = versionName publishVersion = versionName

Loading…
Cancel
Save