pull/330/head
laoyuyu 7 years ago
commit cf65959bf9
  1. 2
      Aria/build.gradle
  2. 9
      Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java
  3. 2
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCancelCmd.java
  4. 19
      Aria/src/main/java/com/arialyy/aria/core/command/normal/AbsNormalCmd.java
  5. 72
      Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java
  6. 88
      Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
  7. 6
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java
  8. 88
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
  9. 56
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpInfoThread.java
  10. 4
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpThreadTask.java
  11. 166
      Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java
  12. 22
      Aria/src/main/java/com/arialyy/aria/core/common/ProxyHelper.java
  13. 5
      Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java
  14. 6
      Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java
  15. 16
      Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java
  16. 5
      Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java
  17. 6
      Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java
  18. 8
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java
  19. 7
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
  20. 46
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
  21. 21
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java
  22. 7
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
  23. 8
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
  24. 89
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java
  25. 20
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
  26. 56
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
  27. 13
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java
  28. 160
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java
  29. 11
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
  30. 118
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
  31. 3
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java
  32. 7
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
  33. 11
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java
  34. 5
      Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java
  35. 4
      Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java
  36. 7
      Aria/src/main/java/com/arialyy/aria/core/manager/DGTEFactory.java
  37. 7
      Aria/src/main/java/com/arialyy/aria/core/manager/TEManager.java
  38. 26
      Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java
  39. 5
      Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
  40. 9
      Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java
  41. 2
      Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java
  42. 9
      Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java
  43. 2
      Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java
  44. 13
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java
  45. 7
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java
  46. 34
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java
  47. 6
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java
  48. 2
      Aria/src/main/java/com/arialyy/aria/orm/AbsDelegate.java
  49. 5
      Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java
  50. 3
      Aria/src/main/java/com/arialyy/aria/util/ALog.java
  51. 206
      Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
  52. 9
      Aria/src/main/java/com/arialyy/aria/util/Regular.java
  53. 9
      DEV_LOG.md
  54. 22
      README.md
  55. 9
      app/src/main/AndroidManifest.xml
  56. 18
      app/src/main/assets/aria_config.xml
  57. 11
      app/src/main/java/com/arialyy/simple/download/FtpDownloadActivity.java
  58. 9
      app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
  59. 5
      app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java
  60. 2
      app/src/main/java/com/arialyy/simple/download/group/GroupModule.java
  61. 4
      app/src/main/java/com/arialyy/simple/download/multi_download/DownloadAdapter.java
  62. 6
      app/src/main/java/com/arialyy/simple/download/multi_download/MultiDownloadActivity.java
  63. 2
      app/src/main/java/com/arialyy/simple/download/multi_download/MultiTaskActivity.java
  64. 16
      app/src/main/java/com/arialyy/simple/test/AnyRunActivity.java
  65. 6
      app/src/main/java/com/arialyy/simple/test/AnyRunnModule.java
  66. 8
      app/src/main/java/com/arialyy/simple/test/TestActivity.java
  67. 9
      app/src/main/res/values/strings.xml
  68. 1
      aria/src/main/AndroidManifest.xml
  69. 25
      aria/src/main/java/com/arialyy/aria/core/Configuration.java
  70. 2
      build.gradle

@ -28,6 +28,6 @@ dependencies {
compile project(':AriaAnnotations') compile project(':AriaAnnotations')
compile 'com.arialyy.aria:aria-ftp-plug:1.0.3' compile 'com.arialyy.aria:aria-ftp-plug:1.0.3'
// compile project(':AriaFtpPlug') // compile project(':AriaFtpPlug')
} }
apply from: 'bintray-release.gradle' apply from: 'bintray-release.gradle'

@ -59,9 +59,6 @@ class ConfigHelper extends DefaultHandler {
String value = attributes.getValue("value"); String value = attributes.getValue("value");
switch (qName) { switch (qName) {
case "openDynamicFile":
loadOpenDynamicFile(value);
break;
case "threadNum": case "threadNum":
loadThreadNum(value); loadThreadNum(value);
break; break;
@ -117,12 +114,6 @@ class ConfigHelper extends DefaultHandler {
} }
} }
private void loadOpenDynamicFile(String value) {
if (isDownloadConfig) {
mDownloadConfig.openDynamicFile = checkBoolean(value) ? Boolean.valueOf(value) : false;
}
}
private void loadNotNetRetry(String value) { private void loadNotNetRetry(String value) {
if (isDownloadConfig) { if (isDownloadConfig) {
mDownloadConfig.notNetRetry = checkBoolean(value) ? Boolean.valueOf(value) : false; mDownloadConfig.notNetRetry = checkBoolean(value) ? Boolean.valueOf(value) : false;

@ -19,7 +19,7 @@ import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
/** /**
* Created by AriaL on 2017/6/29. * Created by AriaL on 2017/6/29.
* 删除任务组 * 删除任务组子任务
*/ */
class GroupCancelCmd<T extends AbsGroupTaskEntity> extends AbsGroupCmd<T> { class GroupCancelCmd<T extends AbsGroupTaskEntity> extends AbsGroupCmd<T> {
/** /**

@ -90,10 +90,12 @@ public abstract class AbsNormalCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
} }
/** /**
* 删除所有任务 * 发送等待状态
*/ */
void removeAll() { void sendWaitState(AbsTask task) {
mQueue.removeAllTask(); if (task != null) {
task.getOutHandler().obtainMessage(ISchedulers.WAIT, task).sendToTarget();
}
} }
/** /**
@ -119,6 +121,17 @@ public abstract class AbsNormalCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
mQueue.cancelTask(tempTask); mQueue.cancelTask(tempTask);
} }
/**
* 删除任务
*/
void removeTask(AbsTaskEntity taskEntity) {
AbsTask tempTask = getTask(taskEntity.getEntity());
if (tempTask == null){
tempTask = createTask(taskEntity);
}
mQueue.cancelTask(tempTask);
}
/** /**
* 启动任务 * 启动任务
*/ */

@ -16,7 +16,19 @@
package com.arialyy.aria.core.command.normal; package com.arialyy.aria.core.command.normal;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.orm.DbEntity;
import java.util.List;
/** /**
* Created by AriaL on 2017/6/27. * Created by AriaL on 2017/6/27.
@ -37,6 +49,64 @@ public class CancelAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
} }
@Override public void executeCmd() { @Override public void executeCmd() {
removeAll(); if (!canExeCmd) return;
if (isDownloadCmd) {
removeAllDTask();
removeAllDGTask();
} else {
removeUTask();
}
}
/**
* 删除所有普通下载任务
*/
private void removeAllDTask() {
List<DownloadEntity> entities =
DbEntity.findDatas(DownloadEntity.class, "isGroupChild=?", "false");
if (entities != null && !entities.isEmpty()) {
for (DownloadEntity entity : entities) {
remove(TEManager.getInstance().getTEntity(DownloadTaskEntity.class, entity.getKey()));
}
}
}
/**
* 删除所有下载任务组任务
*/
private void removeAllDGTask() {
List<DownloadGroupEntity> entities =
DbEntity.findDatas(DownloadGroupEntity.class, "state!=?", "-1");
if (entities != null && !entities.isEmpty()) {
for (DownloadGroupEntity entity : entities) {
remove(
TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, entity.getUrls()));
}
}
}
/**
* 删除所有普通上传任务
*/
private void removeUTask() {
List<UploadEntity> entities =
DbEntity.findDatas(UploadEntity.class, "isGroupChild=?", "false");
if (entities != null && !entities.isEmpty()) {
for (UploadEntity entity : entities) {
remove(TEManager.getInstance().getTEntity(UploadTaskEntity.class, entity.getKey()));
}
}
}
private void remove(AbsTaskEntity te) {
if (te instanceof DownloadTaskEntity) {
mQueue = DownloadTaskQueue.getInstance();
} else if (te instanceof UploadTaskEntity) {
mQueue = UploadTaskQueue.getInstance();
} else if (te instanceof DownloadGroupTaskEntity) {
mQueue = DownloadGroupTaskQueue.getInstance();
}
te.setRemoveFile(removeFile);
removeTask(te);
} }
} }

@ -1,17 +1,19 @@
package com.arialyy.aria.core.command.normal; package com.arialyy.aria.core.command.normal;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.download.wrapper.DGTEWrapper; import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.download.wrapper.DTEWrapper;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue; import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.core.queue.DownloadTaskQueue; import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.core.queue.UploadTaskQueue; import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity; import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.core.upload.wrapper.UTEWrapper;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
@ -42,10 +44,10 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
return; return;
} }
if (isDownloadCmd) { if (isDownloadCmd) {
resumeTask(findTaskData(1)); findTaskData(1);
resumeTask(findTaskData(2)); findTaskData(2);
} else { } else {
resumeTask(findTaskData(3)); findTaskData(3);
} }
resumeWaitTask(); resumeWaitTask();
} }
@ -55,54 +57,49 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
* *
* @param type {@code 1}单任务下载任务{@code 2}任务组下载任务{@code 3} 单任务上传任务 * @param type {@code 1}单任务下载任务{@code 2}任务组下载任务{@code 3} 单任务上传任务
*/ */
private List<AbsTaskEntity> findTaskData(int type) { private void findTaskData(int type) {
// TODO: 2018/4/20 需要测试
List<AbsTaskEntity> tempList = new ArrayList<>();
if (type == 1) { if (type == 1) {
List<DTEWrapper> wrappers = DbEntity.findRelationData(DTEWrapper.class, List<DownloadEntity> entities =
"DownloadTaskEntity.isGroupTask=? and DownloadTaskEntity.state!=?", "false", "1"); DbEntity.findDatas(DownloadEntity.class,
if (wrappers != null && !wrappers.isEmpty()) { "isGroupChild=? and state!=?", "false", "1");
for (DTEWrapper w : wrappers) { if (entities != null && !entities.isEmpty()) {
tempList.add(w.taskEntity); for (DownloadEntity entity : entities) {
resumeTask(TEManager.getInstance().getTEntity(DownloadTaskEntity.class, entity.getKey()));
} }
} }
} else if (type == 2) { } else if (type == 2) {
List<DGTEWrapper> wrappers = List<DownloadGroupEntity> entities =
DbEntity.findRelationData(DGTEWrapper.class, "DownloadGroupTaskEntity.state!=?", "1"); DbEntity.findDatas(DownloadGroupEntity.class, "state!=?", "1");
if (wrappers != null && !wrappers.isEmpty()) { if (entities != null && !entities.isEmpty()) {
for (DGTEWrapper w : wrappers) { for (DownloadGroupEntity entity : entities) {
tempList.add(w.taskEntity); resumeTask(
TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, entity.getUrls()));
} }
} }
} else if (type == 3) { } else if (type == 3) {
List<UTEWrapper> wrappers = List<UploadEntity> entities =
DbEntity.findRelationData(UTEWrapper.class, "UploadTaskEntity.state!=?", "1"); DbEntity.findDatas(UploadEntity.class, "state!=?", "1");
if (wrappers != null && !wrappers.isEmpty()) { if (entities != null && !entities.isEmpty()) {
for (UTEWrapper w : wrappers) { for (UploadEntity entity : entities) {
tempList.add(w.taskEntity); resumeTask(TEManager.getInstance().getTEntity(UploadTaskEntity.class, entity.getKey()));
} }
} }
} }
return tempList;
} }
/** /**
* 恢复任务 * 恢复任务
*/ */
private void resumeTask(List<AbsTaskEntity> taskList) { private void resumeTask(AbsTaskEntity te) {
if (taskList != null && !taskList.isEmpty()) { if (te == null || te.getEntity() == null) return;
for (AbsTaskEntity te : taskList) { int state = te.getState();
if (te == null || te.getEntity() == null) continue; if (state == IEntity.STATE_STOP || state == IEntity.STATE_OTHER) {
int state = te.getState(); resumeEntity(te);
if (state == IEntity.STATE_STOP || state == IEntity.STATE_OTHER) { } else if (state == IEntity.STATE_WAIT) {
resumeEntity(te); mWaitList.add(te);
} else if (state == IEntity.STATE_WAIT) { } else if (state == IEntity.STATE_RUNNING) {
mWaitList.add(te); if (!mQueue.taskIsRunning(te.getEntity().getKey())) {
} else if (state == IEntity.STATE_RUNNING) { resumeEntity(te);
if (!mQueue.taskIsRunning(te.getEntity().getKey())) {
resumeEntity(te);
}
}
} }
} }
} }
@ -117,6 +114,13 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
if (mQueue.getCurrentExePoolNum() < maxTaskNum) { if (mQueue.getCurrentExePoolNum() < maxTaskNum) {
startTask(createTask(te)); startTask(createTask(te));
} else { } else {
if (te instanceof DownloadTaskEntity) {
mQueue = DownloadTaskQueue.getInstance();
} else if (te instanceof UploadTaskEntity) {
mQueue = UploadTaskQueue.getInstance();
} else if (te instanceof DownloadGroupTaskEntity) {
mQueue = DownloadGroupTaskQueue.getInstance();
}
createTask(te); createTask(te);
} }
} }
@ -129,7 +133,8 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
*/ */
private void resumeEntity(AbsTaskEntity te) { private void resumeEntity(AbsTaskEntity te) {
if (te instanceof DownloadTaskEntity) { if (te instanceof DownloadTaskEntity) {
if (te.getRequestType() == AbsTaskEntity.D_FTP || te.getRequestType() == AbsTaskEntity.U_FTP) { if (te.getRequestType() == AbsTaskEntity.D_FTP
|| te.getRequestType() == AbsTaskEntity.U_FTP) {
te.setUrlEntity(CommonUtil.getFtpUrlInfo(te.getEntity().getKey())); te.setUrlEntity(CommonUtil.getFtpUrlInfo(te.getEntity().getKey()));
} }
mQueue = DownloadTaskQueue.getInstance(); mQueue = DownloadTaskQueue.getInstance();
@ -143,7 +148,8 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
startTask(createTask(te)); startTask(createTask(te));
} else { } else {
te.getEntity().setState(IEntity.STATE_WAIT); te.getEntity().setState(IEntity.STATE_WAIT);
createTask(te); AbsTask task = createTask(te);
sendWaitState(task);
} }
} }
} }

@ -86,8 +86,11 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
} }
} }
} else { } else {
if (!task.isRunning()) { //任务没执行并且执行队列中没有该任务,才认为任务没有运行中
if (!task.isRunning() && !mQueue.taskIsRunning(task.getKey())) {
resumeTask(); resumeTask();
}else {
ALog.w(TAG, String.format("任务【%s】已经在运行", task.getTaskName()));
} }
} }
if (mQueue.getCurrentCachePoolNum() == 0) { if (mQueue.getCurrentCachePoolNum() == 0) {
@ -114,7 +117,6 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
} }
private List<AbsTaskEntity> findWaitData(int type) { private List<AbsTaskEntity> findWaitData(int type) {
// TODO: 2018/4/20 需要测试
List<AbsTaskEntity> waitList = new ArrayList<>(); List<AbsTaskEntity> waitList = new ArrayList<>();
if (type == 1) { if (type == 1) {
List<DTEWrapper> wrappers = DbEntity.findRelationData(DTEWrapper.class, List<DTEWrapper> wrappers = DbEntity.findRelationData(DTEWrapper.class,

@ -16,7 +16,6 @@
package com.arialyy.aria.core.common; package com.arialyy.aria.core.common;
import android.content.Context; import android.content.Context;
import android.util.SparseArray;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.AbsNormalEntity; import com.arialyy.aria.core.inf.AbsNormalEntity;
@ -29,8 +28,10 @@ import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.DbHelper; import com.arialyy.aria.util.DbHelper;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.Timer; import java.util.Timer;
@ -44,8 +45,11 @@ import java.util.concurrent.Executors;
*/ */
public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>> public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable, IUtil { implements Runnable, IUtil {
public static final String STATE = "_state_"; private static final String STATE = "_state_";
public static final String RECORD = "_record_"; private static final String RECORD = "_record_";
/**
* 小于1m的文件不启用多线程
*/
protected static final long SUB_LEN = 1024 * 1024; protected static final long SUB_LEN = 1024 * 1024;
private final String TAG = "AbsFileer"; private final String TAG = "AbsFileer";
@ -57,24 +61,20 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
protected StateConstance mConstance; protected StateConstance mConstance;
private ExecutorService mFixedThreadPool; private ExecutorService mFixedThreadPool;
//总线程数 //总线程数
private int mTotalThreadNum; protected int mTotalThreadNum;
//启动线程数 //启动线程数
private int mStartThreadNum; private int mStartThreadNum;
//已完成的线程数 //已完成的线程数
private int mCompleteThreadNum; private int mCompleteThreadNum;
private SparseArray<AbsThreadTask> mTask = new SparseArray<>(); private Map<Integer, AbsThreadTask> mTask = new HashMap<>();
/**
* 小于1m的文件不启用多线程
*/
private Timer mTimer; private Timer mTimer;
@Deprecated @Deprecated private File mConfigFile;
private File mConfigFile;
/** /**
* 进度刷新间隔 * 进度刷新间隔
*/ */
private long mUpdateInterval = 1000; private long mUpdateInterval = 1000;
protected TaskRecord mRecord; private TaskRecord mRecord;
protected AbsFileer(IEventListener listener, TASK_ENTITY taskEntity) { protected AbsFileer(IEventListener listener, TASK_ENTITY taskEntity) {
mListener = listener; mListener = listener;
@ -124,6 +124,16 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
handleBreakpoint(); handleBreakpoint();
} }
mConstance.START_THREAD_NUM = mTotalThreadNum; mConstance.START_THREAD_NUM = mTotalThreadNum;
/*
* mTaskEntity.getEntity().getFileSize() != mTempFile.length()为兼容以前老版本代码
* 动态长度条件
* 1总线程数为1并且是新任务
* 2总线程数为1不是新任务但是长度不是文件全长度
*/
if (mTotalThreadNum == 1 && (mTaskEntity.isNewTask()
|| mTaskEntity.getEntity().getFileSize() != mTempFile.length())) {
mConstance.isOpenDynamicFile = true;
}
startTimer(); startTimer();
} }
@ -177,7 +187,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
} }
/** /**
* 获取当前下载位置 * 获取当前任务位置
*/ */
@Override public long getCurrentLocation() { @Override public long getCurrentLocation() {
return mConstance.CURRENT_LOCATION; return mConstance.CURRENT_LOCATION;
@ -233,11 +243,11 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
* 检查任务检查线程数 * 检查任务检查线程数
* 新任务条件 * 新任务条件
* 1文件不存在 * 1文件不存在
* 2下载记录文件缺失或不匹配 * 2任务记录文件缺失或不匹配
* 3数据库记录不存在 * 3数据库记录不存在
* 4不支持断点则是新任务 * 4不支持断点则是新任务
*/ */
protected void checkTask() { private void checkTask() {
mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName())); mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
if (mConfigFile.exists()) { if (mConfigFile.exists()) {
convertDb(); convertDb();
@ -307,14 +317,14 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
tRecord.key = mRecord.filePath; tRecord.key = mRecord.filePath;
Object state = pro.getProperty(mTempFile.getName() + STATE + i); Object state = pro.getProperty(mTempFile.getName() + STATE + i);
Object record = pro.getProperty(mTempFile.getName() + RECORD + i); Object record = pro.getProperty(mTempFile.getName() + RECORD + i);
if (state != null && Integer.parseInt(state + "") == 1) { if (state != null && Integer.parseInt(String.valueOf(state)) == 1) {
mCompleteThreadNum++; mCompleteThreadNum++;
tRecord.isComplete = true; tRecord.isComplete = true;
continue; continue;
} }
mStartThreadNum++; mStartThreadNum++;
if (record != null) { if (record != null) {
Long temp = Long.parseLong(record + ""); Long temp = Long.parseLong(String.valueOf(record));
tRecord.startLocation = temp > 0 ? temp : 0; tRecord.startLocation = temp > 0 ? temp : 0;
} else { } else {
tRecord.startLocation = 0; tRecord.startLocation = 0;
@ -334,8 +344,6 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
mRecord.filePath = mTaskEntity.getKey(); mRecord.filePath = mTaskEntity.getKey();
mRecord.threadRecords = new ArrayList<>(); mRecord.threadRecords = new ArrayList<>();
mRecord.isGroupRecord = mTaskEntity.getEntity().isGroupChild(); mRecord.isGroupRecord = mTaskEntity.getEntity().isGroupChild();
mRecord.isOpenDynamicFile =
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().isOpenDynamicFile();
if (mRecord.isGroupRecord) { if (mRecord.isGroupRecord) {
if (mTaskEntity.getEntity() instanceof DownloadEntity) { if (mTaskEntity.getEntity() instanceof DownloadEntity) {
mRecord.dGroupName = ((DownloadEntity) mTaskEntity.getEntity()).getGroupName(); mRecord.dGroupName = ((DownloadEntity) mTaskEntity.getEntity()).getGroupName();
@ -347,6 +355,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
* 保存任务记录 * 保存任务记录
*/ */
private void saveRecord() { private void saveRecord() {
mRecord.threadNum = mRecord.threadRecords.size();
mRecord.save(); mRecord.save();
for (ThreadRecord tr : mRecord.threadRecords) { for (ThreadRecord tr : mRecord.threadRecords) {
tr.save(); tr.save();
@ -364,7 +373,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
*/ */
private boolean resumeRecordLocation(int i, long startL, long endL) { private boolean resumeRecordLocation(int i, long startL, long endL) {
mConstance.CURRENT_LOCATION += endL - startL; mConstance.CURRENT_LOCATION += endL - startL;
ALog.d(TAG, "任务【" + mTaskEntity.getEntity().getFileName() + "】线程__" + i + "__已完成"); ALog.d(TAG, String.format("任务【%s】线程__%s__已完成", mTaskEntity.getEntity().getFileName(), i));
mConstance.COMPLETE_THREAD_NUM = mCompleteThreadNum; mConstance.COMPLETE_THREAD_NUM = mCompleteThreadNum;
mConstance.STOP_NUM++; mConstance.STOP_NUM++;
mConstance.CANCEL_NUM++; mConstance.CANCEL_NUM++;
@ -430,7 +439,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
continue; continue;
} }
//如果有记录,则恢复下载 //如果有记录,则恢复任务
if (tr.startLocation >= 0) { if (tr.startLocation >= 0) {
Long r = tr.startLocation; Long r = tr.startLocation;
//记录的位置需要在线程区间中 //记录的位置需要在线程区间中
@ -438,7 +447,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
mConstance.CURRENT_LOCATION += r - startL; mConstance.CURRENT_LOCATION += r - startL;
startL = r; startL = r;
} }
ALog.d(TAG, "任务【" + mEntity.getFileName() + "】线程__" + i + "__恢复下载"); ALog.d(TAG, String.format("任务【%s】线程__%s__恢复任务", mEntity.getFileName(), i));
} }
//最后一个线程的结束位置即为文件的总长度 //最后一个线程的结束位置即为文件的总长度
if (i == (mTotalThreadNum - 1)) { if (i == (mTotalThreadNum - 1)) {
@ -456,12 +465,17 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
threadId[rl] = i; threadId[rl] = i;
rl++; rl++;
} }
if (mConstance.CURRENT_LOCATION != 0
&& mConstance.CURRENT_LOCATION != mEntity.getCurrentProgress()) {
ALog.d(TAG, "进度修正");
mEntity.setCurrentProgress(mConstance.CURRENT_LOCATION);
}
saveRecord(); saveRecord();
startThreadTask(threadId); startThreadTask(threadId);
} }
/** /**
* 启动单线程下载任务 * 启动单线程任务
*/ */
private void startThreadTask(int[] recordL) { private void startThreadTask(int[] recordL) {
if (mConstance.CURRENT_LOCATION > 0) { if (mConstance.CURRENT_LOCATION > 0) {
@ -479,6 +493,34 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
} }
} }
/**
* 重试线程任务只有线程创建成功才能重试
*/
public void retryThreadTask() {
if (mTask == null || mTask.size() == 0) {
ALog.w(TAG, "没有线程任务");
return;
}
Set<Integer> keys = mTask.keySet();
for (Integer key : keys) {
AbsThreadTask task = mTask.get(key);
if (task != null && !task.isThreadComplete()) {
task.getConfig().START_LOCATION = task.getCurrentLocation();
mConstance.isStop = false;
mConstance.isCancel = false;
mConstance.isRunning = true;
ALog.d(TAG, String.format("任务【%s】开始重试,线程__%s__【开始位置:%s,结束位置:%s】", mEntity.getFileName(),
key, task.getConfig().START_LOCATION, task.getConfig().END_LOCATION));
if (!mFixedThreadPool.isShutdown()) {
mFixedThreadPool.execute(task);
} else {
ALog.w(TAG, "线程池已关闭");
mListener.onFail(true);
}
}
}
}
/** /**
* 处理新任务 * 处理新任务
* *
@ -487,7 +529,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
protected abstract boolean handleNewTask(); protected abstract boolean handleNewTask();
/** /**
* 处理不支持断点的下载 * 处理不支持断点的任务
*/ */
private void handleNoSupportBP() { private void handleNoSupportBP() {
SubThreadConfig<TASK_ENTITY> config = new SubThreadConfig<>(); SubThreadConfig<TASK_ENTITY> config = new SubThreadConfig<>();

@ -26,6 +26,7 @@ import com.arialyy.aria.util.Regular;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTP;
@ -72,7 +73,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
try { try {
client = createFtpClient(); client = createFtpClient();
if (client == null) { if (client == null) {
failDownload("创建FTP客户端失败", true); ALog.e(TAG, String.format("任务【%s】失败", mTaskEntity.getUrlEntity().url));
return; return;
} }
String remotePath = String remotePath =
@ -82,8 +83,8 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
ALog.i(TAG, s); ALog.i(TAG, s);
boolean isExist = files.length != 0; boolean isExist = files.length != 0;
if (!isExist && !isUpload) { if (!isExist && !isUpload) {
failDownload("文件不存在,任务链接【" + mTaskEntity.getUrlEntity().url + "】,remotePath:" + remotePath, failDownload(String.format("文件不存在,任务链接【%s】,remotePath:%s", mTaskEntity.getUrlEntity().url,
false); remotePath), false);
int i = remotePath.lastIndexOf(File.separator); int i = remotePath.lastIndexOf(File.separator);
FTPFile[] files1; FTPFile[] files1;
if (i == -1) { if (i == -1) {
@ -92,7 +93,8 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
files1 = client.listFiles(remotePath.substring(0, i + 1)); files1 = client.listFiles(remotePath.substring(0, i + 1));
} }
if (files1.length > 0) { if (files1.length > 0) {
ALog.i(TAG, "路径【" + setRemotePath() + "】下的文件列表 ==================================="); ALog.i(TAG,
String.format("路径【%s】下的文件列表 ===================================", setRemotePath()));
for (FTPFile file : files1) { for (FTPFile file : files1) {
ALog.d(TAG, file.toString()); ALog.d(TAG, file.toString());
} }
@ -114,7 +116,8 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
mTaskEntity.setNewTask(true); mTaskEntity.setNewTask(true);
} else { } else {
client.disconnect(); client.disconnect();
failDownload("获取文件信息错误,错误码为:" + reply + ",msg:" + client.getReplyString(), true); failDownload(String.format("获取文件信息错误,错误码为:%s,msg:%s", reply, client.getReplyString()),
true);
return; return;
} }
} }
@ -171,11 +174,14 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
if (m.find() && m.groupCount() > 0) { if (m.find() && m.groupCount() > 0) {
client = new FTPClient(); client = new FTPClient();
InetAddress ip = InetAddress.getByName(urlEntity.hostName); InetAddress ip = InetAddress.getByName(urlEntity.hostName);
client.setConnectTimeout(10000); // 连接10s超时 client.setConnectTimeout(mConnectTimeOut); // 连接10s超时
client.connect(ip, Integer.parseInt(urlEntity.port)); client.connect(ip, Integer.parseInt(urlEntity.port));
mTaskEntity.getUrlEntity().validAddr = ip; mTaskEntity.getUrlEntity().validAddr = ip;
} else { } else {
InetAddress[] ips = InetAddress.getAllByName(urlEntity.hostName); DNSQueryThread dnsThread = new DNSQueryThread(urlEntity.hostName);
dnsThread.start();
dnsThread.join(mConnectTimeOut);
InetAddress[] ips = dnsThread.getIps();
client = connect(new FTPClient(), ips, 0, Integer.parseInt(urlEntity.port)); client = connect(new FTPClient(), ips, 0, Integer.parseInt(urlEntity.port));
} }
@ -206,7 +212,8 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
int reply = client.getReplyCode(); int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) { if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect(); client.disconnect();
failDownload("无法连接到ftp服务器,错误码为:" + reply + ",msg:" + client.getReplyString(), true); failDownload(String.format("无法连接到ftp服务器,错误码为:%s,msg:%s", reply, client.getReplyString()),
true);
return null; return null;
} }
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码 // 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
@ -221,9 +228,10 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
client.setDataTimeout(10 * 1000); client.setDataTimeout(10 * 1000);
client.enterLocalPassiveMode(); client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE); client.setFileType(FTP.BINARY_FILE_TYPE);
client.setConnectTimeout(mConnectTimeOut);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} }
return client; return client;
} }
@ -232,7 +240,12 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
* 连接到ftp服务器 * 连接到ftp服务器
*/ */
private FTPClient connect(FTPClient client, InetAddress[] ips, int index, int port) { private FTPClient connect(FTPClient client, InetAddress[] ips, int index, int port) {
if (ips == null || ips.length == 0) {
ALog.w(TAG, "无可用ip");
return null;
}
try { try {
client.setConnectTimeout(mConnectTimeOut); //需要先设置超时,这样才不会出现阻塞
client.connect(ips[index], port); client.connect(ips[index], port);
mTaskEntity.getUrlEntity().validAddr = ips[index]; mTaskEntity.getUrlEntity().validAddr = ips[index];
return client; return client;
@ -295,4 +308,29 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
mCallback.onFail(mEntity.getKey(), errorMsg, needRetry); mCallback.onFail(mEntity.getKey(), errorMsg, needRetry);
} }
} }
/**
* 获取可用IP的超时线程InetAddress.getByName没有超时功能需要自己处理超时
*/
private static class DNSQueryThread extends Thread {
private String hostName;
private InetAddress[] ips;
DNSQueryThread(String hostName) {
this.hostName = hostName;
}
@Override public void run() {
try {
ips = InetAddress.getAllByName(hostName);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
synchronized InetAddress[] getIps() {
return ips;
}
}
} }

@ -87,8 +87,8 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
int reply = client.getReplyCode(); int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) { if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect(); client.disconnect();
fail(STATE.CURRENT_LOCATION, fail(mChildCurrentLocation,
"无法连接到ftp服务器,错误码为:" + reply + ",msg:" + client.getReplyString(), null); String.format("无法连接到ftp服务器,错误码为:%s,msg:%s", reply, client.getReplyString()), null);
return null; return null;
} }
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码 // 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码

@ -24,7 +24,6 @@ import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.ErrorHelp; import com.arialyy.aria.util.ErrorHelp;
import com.arialyy.aria.util.NetUtils; import com.arialyy.aria.util.NetUtils;
import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@ -53,23 +52,19 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
protected SubThreadConfig<TASK_ENTITY> mConfig; protected SubThreadConfig<TASK_ENTITY> mConfig;
protected ENTITY mEntity; protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity; protected TASK_ENTITY mTaskEntity;
private int mFailNum = 0; private int mFailTimes = 0;
private String mTaskType;
private Timer mFailTimer; private Timer mFailTimer;
private long mLastSaveTime; private long mLastSaveTime;
private ExecutorService mConfigThreadPool; private ExecutorService mConfigThreadPool;
protected int mConnectTimeOut; //连接超时时间 protected int mConnectTimeOut; //连接超时时间
protected int mReadTimeOut; //流读取的超时时间 protected int mReadTimeOut; //流读取的超时时间
protected boolean isNotNetRetry = false; //断网情况是否重试 protected boolean isNotNetRetry = false; //断网情况是否重试
private boolean taskBreak = false; //任务中断
private Thread mConfigThread = new Thread(new Runnable() { private Thread mConfigThread = new Thread(new Runnable() {
@Override public void run() { @Override public void run() {
final long currentTemp = mChildCurrentLocation; final long currentTemp = mChildCurrentLocation;
try { writeConfig(false, currentTemp);
writeConfig(false, currentTemp);
} catch (IOException e) {
e.printStackTrace();
}
} }
}); });
@ -80,13 +75,10 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
mConfig = info; mConfig = info;
mTaskEntity = mConfig.TASK_ENTITY; mTaskEntity = mConfig.TASK_ENTITY;
mEntity = mTaskEntity.getEntity(); mEntity = mTaskEntity.getEntity();
mTaskType = getTaskType();
mLastSaveTime = System.currentTimeMillis(); mLastSaveTime = System.currentTimeMillis();
mConfigThreadPool = Executors.newCachedThreadPool(); mConfigThreadPool = Executors.newCachedThreadPool();
} }
protected abstract String getTaskType();
public void setMaxSpeed(double maxSpeed) { public void setMaxSpeed(double maxSpeed) {
if (-0.9999 < maxSpeed && maxSpeed < 0.00001) { if (-0.9999 < maxSpeed && maxSpeed < 0.00001) {
mSleepTime = 0; mSleepTime = 0;
@ -97,6 +89,28 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
} }
} }
/**
* 当前线程是否完成对于不支持断点的任务一律未完成
* {@code true} 完成{@code false} 未完成
*/
public boolean isThreadComplete() {
return mConfig.THREAD_RECORD.isComplete;
}
/**
* 获取线程配置信息
*/
public SubThreadConfig getConfig() {
return mConfig;
}
/**
* 当前线程下载进度
*/
public long getCurrentLocation() {
return mChildCurrentLocation;
}
private boolean filterVersion() { private boolean filterVersion() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
} }
@ -108,35 +122,38 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
} }
} }
/**
* 任务是否中断中断条件
* 1任务取消
* 2任务停止
* 3手动中断 {@link #taskBreak}
*
* @return {@code true} 中断{@code false} 不是中断
*/
protected boolean isBreak() {
return STATE.isCancel || STATE.isStop || taskBreak;
}
/** /**
* 停止任务 * 停止任务
*/ */
public void stop() { public void stop() {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
try { if (mConfig.SUPPORT_BP) {
if (mConfig.SUPPORT_BP) { final long currentTemp = mChildCurrentLocation;
final long currentTemp = mChildCurrentLocation; STATE.STOP_NUM++;
STATE.STOP_NUM++; ALog.d(TAG, String.format("任务【%s】thread__%s__停止【停止位置:%s】", mConfig.TEMP_FILE.getName(),
ALog.d(TAG, "任务【" mConfig.THREAD_ID, currentTemp));
+ mConfig.TEMP_FILE.getName() writeConfig(false, currentTemp);
+ "】thread__" if (STATE.isStop()) {
+ mConfig.THREAD_ID ALog.i(TAG, String.format("任务【%s】已停止", mConfig.TEMP_FILE.getName()));
+ "__停止【停止位置: "
+ currentTemp
+ "】");
writeConfig(false, currentTemp);
if (STATE.isStop()) {
ALog.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止");
STATE.isRunning = false;
mListener.onStop(STATE.CURRENT_LOCATION);
}
} else {
ALog.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止");
STATE.isRunning = false; STATE.isRunning = false;
mListener.onStop(STATE.CURRENT_LOCATION); mListener.onStop(STATE.CURRENT_LOCATION);
} }
} catch (IOException e) { } else {
e.printStackTrace(); ALog.i(TAG, String.format("任务【%s】已停止", mConfig.TEMP_FILE.getName()));
STATE.isRunning = false;
mListener.onStop(STATE.CURRENT_LOCATION);
} }
} }
} }
@ -146,6 +163,11 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
*/ */
protected void progress(long len) { protected void progress(long len) {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
if (STATE.CURRENT_LOCATION > mEntity.getFileSize()) {
taskBreak = true;
fail(mChildCurrentLocation, "下载失败,下载长度超出文件大小", null, false);
return;
}
mChildCurrentLocation += len; mChildCurrentLocation += len;
STATE.CURRENT_LOCATION += len; STATE.CURRENT_LOCATION += len;
if (System.currentTimeMillis() - mLastSaveTime > 5000 if (System.currentTimeMillis() - mLastSaveTime > 5000
@ -165,44 +187,54 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
if (mConfig.SUPPORT_BP) { if (mConfig.SUPPORT_BP) {
STATE.CANCEL_NUM++; STATE.CANCEL_NUM++;
ALog.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__取消"); ALog.d(TAG,
String.format("任务【%s】thread__%s__取消", mConfig.TEMP_FILE.getName(), mConfig.THREAD_ID));
if (STATE.isCancel()) { if (STATE.isCancel()) {
if (mConfig.TEMP_FILE.exists() && !(mEntity instanceof UploadEntity)) { if (mConfig.TEMP_FILE.exists() && !(mEntity instanceof UploadEntity)) {
mConfig.TEMP_FILE.delete(); mConfig.TEMP_FILE.delete();
} }
ALog.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已取消"); ALog.d(TAG, String.format("任务【%s】已取消", mConfig.TEMP_FILE.getName()));
STATE.isRunning = false; STATE.isRunning = false;
mListener.onCancel(); mListener.onCancel();
} }
} else { } else {
ALog.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已取消"); ALog.d(TAG, String.format("任务【%s】已取消", mConfig.TEMP_FILE.getName()));
STATE.isRunning = false; STATE.isRunning = false;
mListener.onCancel(); mListener.onCancel();
} }
} }
} }
/**
* 线程任务失败
*
* @param subCurrentLocation 当前线程下载进度
* @param msg 自定义信息
* @param ex 异常信息
*/
protected void fail(final long subCurrentLocation, String msg, Exception ex) {
fail(subCurrentLocation, msg, ex, true);
}
/** /**
* 任务失败 * 任务失败
*
* @param subCurrentLocation 当前子线程进度
*/ */
protected void fail(final long currentLocation, String msg, Exception ex) { protected void fail(final long subCurrentLocation, String msg, Exception ex, boolean needRetry) {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
try { if (ex != null) {
if (ex != null) { ALog.e(TAG, msg + "\n" + ALog.getExceptionString(ex));
ALog.e(TAG, msg + "\n" + ALog.getExceptionString(ex)); } else {
} else { ALog.e(TAG, msg);
ALog.e(TAG, msg); }
} if (mConfig.SUPPORT_BP) {
if (mConfig.SUPPORT_BP) { writeConfig(false, subCurrentLocation);
writeConfig(false, currentLocation); retryThis(needRetry && STATE.START_THREAD_NUM != 1);
retryThis(STATE.START_THREAD_NUM != 1); } else {
} else { ALog.e(TAG, String.format("任务【%s】执行失败", mConfig.TEMP_FILE.getName()));
ALog.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败"); mListener.onFail(true);
mListener.onFail(true); ErrorHelp.saveError(TAG, "", ALog.getExceptionString(ex));
ErrorHelp.saveError(TAG, "", ALog.getExceptionString(ex));
}
} catch (IOException e) {
e.printStackTrace();
} }
} }
} }
@ -218,24 +250,21 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
mFailTimer.cancel(); mFailTimer.cancel();
} }
if (!NetUtils.isConnected(AriaManager.APP) && !isNotNetRetry) { if (!NetUtils.isConnected(AriaManager.APP) && !isNotNetRetry) {
ALog.w(TAG, ALog.w(TAG, String.format("任务【%s】thread__%s__重试失败,网络未连接", mConfig.TEMP_FILE.getName(),
"任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__重试失败,网络未连接"); mConfig.THREAD_ID));
} }
if (mFailNum < RETRY_NUM if (mFailTimes < RETRY_NUM
&& needRetry && needRetry
&& NetUtils.isConnected(AriaManager.APP) && (NetUtils.isConnected(AriaManager.APP) || isNotNetRetry)
&& !isNotNetRetry && isBreak()) {
&& !STATE.isCancel
&& !STATE.isStop) {
mFailTimer = new Timer(true); mFailTimer = new Timer(true);
mFailTimer.schedule(new TimerTask() { mFailTimer.schedule(new TimerTask() {
@Override public void run() { @Override public void run() {
mFailNum++; mFailTimes++;
ALog.w(TAG, ALog.w(TAG, String.format("任务【%s】thread__%s__正在重试", mConfig.TEMP_FILE.getName(),
"任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__正在重试"); mConfig.THREAD_ID));
final long retryLocation = final long temp = mChildCurrentLocation;
mChildCurrentLocation == 0 ? mConfig.START_LOCATION : mChildCurrentLocation; mConfig.START_LOCATION = mChildCurrentLocation == 0 ? mConfig.START_LOCATION : temp;
mConfig.START_LOCATION = retryLocation;
AbsThreadTask.this.run(); AbsThreadTask.this.run();
} }
}, RETRY_INTERVAL); }, RETRY_INTERVAL);
@ -244,7 +273,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
if (STATE.isFail()) { if (STATE.isFail()) {
STATE.isRunning = false; STATE.isRunning = false;
STATE.isStop = true; STATE.isStop = true;
ALog.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败"); ALog.e(TAG, String.format("任务【%s】执行失败", mConfig.TEMP_FILE.getName()));
mListener.onFail(true); mListener.onFail(true);
} }
} }
@ -252,8 +281,11 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
/** /**
* 将记录写入到配置文件 * 将记录写入到配置文件
*
* @param isComplete 当前线程是否完成 {@code true}完成
* @param record 当前下载进度
*/ */
protected void writeConfig(boolean isComplete, final long record) throws IOException { protected void writeConfig(boolean isComplete, final long record) {
if (mConfig.THREAD_RECORD != null) { if (mConfig.THREAD_RECORD != null) {
mConfig.THREAD_RECORD.isComplete = isComplete; mConfig.THREAD_RECORD.isComplete = isComplete;
if (0 < record && record < mConfig.END_LOCATION) { if (0 < record && record < mConfig.END_LOCATION) {

@ -16,7 +16,6 @@
package com.arialyy.aria.core.common; package com.arialyy.aria.core.common;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -29,7 +28,8 @@ import java.util.Set;
* 代理参数获取 * 代理参数获取
*/ */
public class ProxyHelper { public class ProxyHelper {
public Set<String> downloadCounter, uploadCounter, downloadGroupCounter, downloadGroupSubCounter; public Set<String> downloadCounter = new HashSet<>(), uploadCounter = new HashSet<>(),
downloadGroupCounter = new HashSet<>(), downloadGroupSubCounter = new HashSet<>();
public static volatile ProxyHelper INSTANCE = null; public static volatile ProxyHelper INSTANCE = null;
@ -47,11 +47,9 @@ public class ProxyHelper {
} }
private void init() { private void init() {
List<String> classes = CommonUtil.getClassName(AriaManager.APP, "com.arialyy.aria"); List<String> classes = CommonUtil.getClassName(AriaManager.APP,
"com.arialyy.aria.ProxyClassCounter");
for (String className : classes) { for (String className : classes) {
if (!className.startsWith("com.arialyy.aria.ProxyClassCounter")){
continue;
}
count(className); count(className);
} }
} }
@ -66,30 +64,18 @@ public class ProxyHelper {
Object object = clazz.newInstance(); Object object = clazz.newInstance();
Object dc = download.invoke(object); Object dc = download.invoke(object);
if (dc != null) { if (dc != null) {
if (downloadCounter == null) {
downloadCounter = new HashSet<>();
}
downloadCounter.addAll((Set<String>) dc); downloadCounter.addAll((Set<String>) dc);
} }
Object dgc = downloadGroup.invoke(object); Object dgc = downloadGroup.invoke(object);
if (dgc != null) { if (dgc != null) {
if (downloadGroupCounter == null) {
downloadGroupCounter = new HashSet<>();
}
downloadGroupCounter.addAll((Set<String>) dgc); downloadGroupCounter.addAll((Set<String>) dgc);
} }
Object dgsc = downloadGroupSub.invoke(object); Object dgsc = downloadGroupSub.invoke(object);
if (dgsc != null) { if (dgsc != null) {
if (downloadGroupSubCounter == null) {
downloadGroupSubCounter = new HashSet<>();
}
downloadGroupSubCounter.addAll((Set<String>) dgsc); downloadGroupSubCounter.addAll((Set<String>) dgsc);
} }
Object uc = upload.invoke(object); Object uc = upload.invoke(object);
if (uc != null) { if (uc != null) {
if (uploadCounter == null) {
uploadCounter = new HashSet<>();
}
uploadCounter.addAll((Set<String>) uc); uploadCounter.addAll((Set<String>) uc);
} }
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {

@ -30,6 +30,11 @@ public class StateConstance {
public boolean isCancel = false; public boolean isCancel = false;
public boolean isStop = false; public boolean isStop = false;
public TaskRecord TASK_RECORD; public TaskRecord TASK_RECORD;
/**
* 是否是使用虚拟文件下载的
* {@code true}{@code false}不是
*/
public boolean isOpenDynamicFile = false;
public StateConstance() { public StateConstance() {
} }

@ -73,10 +73,4 @@ public class TaskRecord extends DbEntity {
@Ignore @Ignore
@Deprecated @Deprecated
public String uGroupName; public String uGroupName;
/**
* 是否是使用虚拟文件下载的
* {@code true}{@code false}不是
*/
public boolean isOpenDynamicFile = false;
} }

@ -19,8 +19,6 @@ import android.os.Handler;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.TaskRecord; import com.arialyy.aria.core.common.TaskRecord;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsGroupEntity;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTask; import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener; import com.arialyy.aria.core.inf.IDownloadListener;
@ -36,13 +34,13 @@ import java.lang.ref.WeakReference;
class BaseDListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>, TASK extends AbsTask<TASK_ENTITY>> class BaseDListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>, TASK extends AbsTask<TASK_ENTITY>>
implements IDownloadListener { implements IDownloadListener {
private static final String TAG = "BaseDListener"; private static final String TAG = "BaseDListener";
protected WeakReference<Handler> outHandler; WeakReference<Handler> outHandler;
private int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度 private int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度
private long mLastLen = 0; //上一次发送长度 private long mLastLen = 0; //上一次发送长度
private boolean isFirst = true; private boolean isFirst = true;
protected ENTITY mEntity; protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity; protected TASK_ENTITY mTaskEntity;
protected TASK mTask; private TASK mTask;
private boolean isConvertSpeed = false; private boolean isConvertSpeed = false;
boolean isWait = false; boolean isWait = false;
private long mLastSaveTime; private long mLastSaveTime;
@ -158,14 +156,16 @@ class BaseDListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<
mEntity.setState(state); mEntity.setState(state);
mEntity.setComplete(state == IEntity.STATE_COMPLETE); mEntity.setComplete(state == IEntity.STATE_COMPLETE);
if (state == IEntity.STATE_CANCEL) { if (state == IEntity.STATE_CANCEL) {
if (mEntity instanceof AbsNormalEntity) { if (mEntity instanceof DownloadEntity) {
TaskRecord record = TaskRecord record =
DbEntity.findFirst(TaskRecord.class, "TaskRecord.filePath=?", mTaskEntity.getKey()); DbEntity.findFirst(TaskRecord.class, "TaskRecord.filePath=?", mTaskEntity.getKey());
if (record != null) { if (record != null) {
CommonUtil.delTaskRecord(record, mTaskEntity.isRemoveFile(), (AbsNormalEntity) mEntity); CommonUtil.delTaskRecord(record, mTaskEntity.isRemoveFile(), (DownloadEntity) mEntity);
} else {
mEntity.deleteData();
} }
} else if (mEntity instanceof AbsGroupEntity) { } else if (mEntity instanceof DownloadGroupEntity) {
CommonUtil.delGroupTaskRecord(mTaskEntity.isRemoveFile(), ((AbsGroupEntity) mEntity)); CommonUtil.delGroupTaskRecord(mTaskEntity.isRemoveFile(), ((DownloadGroupEntity) mEntity));
} }
//mEntity.deleteData(); //mEntity.deleteData();
return; return;

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.support.annotation.CheckResult;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.manager.SubTaskManager; import com.arialyy.aria.core.manager.SubTaskManager;
@ -49,6 +50,7 @@ abstract class BaseGroupTarget<TARGET extends BaseGroupTarget>
* *
* @return 子任务管理器 * @return 子任务管理器
*/ */
@CheckResult
public SubTaskManager getSubTaskManager() { public SubTaskManager getSubTaskManager() {
if (mSubTaskManager == null) { if (mSubTaskManager == null) {
mSubTaskManager = new SubTaskManager(mTargetName, mTaskEntity); mSubTaskManager = new SubTaskManager(mTargetName, mTaskEntity);
@ -59,6 +61,7 @@ abstract class BaseGroupTarget<TARGET extends BaseGroupTarget>
/** /**
* 设置任务组别名 * 设置任务组别名
*/ */
@CheckResult
public TARGET setGroupAlias(String alias) { public TARGET setGroupAlias(String alias) {
if (TextUtils.isEmpty(alias)) return (TARGET) this; if (TextUtils.isEmpty(alias)) return (TARGET) this;
mEntity.setAlias(alias); mEntity.setAlias(alias);
@ -76,6 +79,7 @@ abstract class BaseGroupTarget<TARGET extends BaseGroupTarget>
* @deprecated {@link #setDirPath(String)} 请使用这个api * @deprecated {@link #setDirPath(String)} 请使用这个api
*/ */
@Deprecated @Deprecated
@CheckResult
public TARGET setDownloadDirPath(String groupDirPath) { public TARGET setDownloadDirPath(String groupDirPath) {
return setDirPath(groupDirPath); return setDirPath(groupDirPath);
} }
@ -99,6 +103,7 @@ abstract class BaseGroupTarget<TARGET extends BaseGroupTarget>
* *
* @param dirPath 任务组保存文件夹路径 * @param dirPath 任务组保存文件夹路径
*/ */
@CheckResult
public TARGET setDirPath(String dirPath) { public TARGET setDirPath(String dirPath) {
mDirPathTemp = dirPath; mDirPathTemp = dirPath;
return (TARGET) this; return (TARGET) this;

@ -136,8 +136,12 @@ abstract class BaseNormalTarget<TARGET extends BaseNormalTarget>
} else if (getTargetType() == FTP) { } else if (getTargetType() == FTP) {
filePath += mEntity.getFileName(); filePath += mEntity.getFileName();
} }
} else {
// http文件名设置
if (TextUtils.isEmpty(mEntity.getFileName())) {
mEntity.setFileName(file.getName());
}
} }
mEntity.setFileName(file.getName());
//设置文件保存路径,如果新文件路径和就文件路径不同,则修改路径 //设置文件保存路径,如果新文件路径和就文件路径不同,则修改路径
if (!filePath.equals(mEntity.getDownloadPath())) { if (!filePath.equals(mEntity.getDownloadPath())) {

@ -19,6 +19,7 @@ import android.os.Handler;
import com.arialyy.aria.core.download.downloader.IDownloadGroupListener; import com.arialyy.aria.core.download.downloader.IDownloadGroupListener;
import com.arialyy.aria.core.inf.GroupSendParams; import com.arialyy.aria.core.inf.GroupSendParams;
import com.arialyy.aria.core.scheduler.ISchedulers; import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.util.ALog;
/** /**
* Created by Aria.Lao on 2017/7/20. * Created by Aria.Lao on 2017/7/20.
@ -85,10 +86,17 @@ class DownloadGroupListener
} }
private void saveCurrentLocation() { private void saveCurrentLocation() {
if (mEntity.getSubEntities() == null || mEntity.getSubEntities().isEmpty()) {
ALog.w(TAG, "保存进度失败,子任务为null");
return;
}
long location = 0; long location = 0;
for (DownloadEntity e : mEntity.getSubEntities()) { for (DownloadEntity e : mEntity.getSubEntities()) {
location += e.getCurrentProgress(); location += e.getCurrentProgress();
} }
if (location > mEntity.getFileSize()) {
location = mEntity.getFileSize();
}
mEntity.setCurrentProgress(location); mEntity.setCurrentProgress(location);
mEntity.update(); mEntity.update();
} }

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.support.annotation.CheckResult;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.manager.TEManager; import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
@ -40,7 +41,7 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
*/ */
private List<String> mSubNameTemp = new ArrayList<>(); private List<String> mSubNameTemp = new ArrayList<>();
DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) { public DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) {
this.mTargetName = targetName; this.mTargetName = targetName;
if (groupEntity.getUrls() != null && !groupEntity.getUrls().isEmpty()) { if (groupEntity.getUrls() != null && !groupEntity.getUrls().isEmpty()) {
this.mUrls.addAll(groupEntity.getUrls()); this.mUrls.addAll(groupEntity.getUrls());
@ -72,6 +73,7 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
* *
* @param fileSize 任务组总大小 * @param fileSize 任务组总大小
*/ */
@CheckResult
public DownloadGroupTarget setFileSize(long fileSize) { public DownloadGroupTarget setFileSize(long fileSize) {
if (fileSize <= 0) { if (fileSize <= 0) {
ALog.e(TAG, "文件大小不能小于 0"); ALog.e(TAG, "文件大小不能小于 0");
@ -86,6 +88,7 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
/** /**
* 如果你是使用{@link DownloadReceiver#load(DownloadGroupEntity)}进行下载操作那么你需要设置任务组的下载地址 * 如果你是使用{@link DownloadReceiver#load(DownloadGroupEntity)}进行下载操作那么你需要设置任务组的下载地址
*/ */
@CheckResult
public DownloadGroupTarget setGroupUrl(List<String> urls) { public DownloadGroupTarget setGroupUrl(List<String> urls) {
mUrls.clear(); mUrls.clear();
mUrls.addAll(urls); mUrls.addAll(urls);
@ -97,6 +100,7 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
* *
* @deprecated {@link #setSubFileName(List)} 请使用该api * @deprecated {@link #setSubFileName(List)} 请使用该api
*/ */
@CheckResult
@Deprecated public DownloadGroupTarget setSubTaskFileName(List<String> subTaskFileName) { @Deprecated public DownloadGroupTarget setSubTaskFileName(List<String> subTaskFileName) {
return setSubFileName(subTaskFileName); return setSubFileName(subTaskFileName);
} }
@ -104,6 +108,7 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
/** /**
* 设置子任务文件名该方法必须在{@link #setDirPath(String)}之后调用否则不生效 * 设置子任务文件名该方法必须在{@link #setDirPath(String)}之后调用否则不生效
*/ */
@CheckResult
public DownloadGroupTarget setSubFileName(List<String> subTaskFileName) { public DownloadGroupTarget setSubFileName(List<String> subTaskFileName) {
if (subTaskFileName == null || subTaskFileName.isEmpty()) { if (subTaskFileName == null || subTaskFileName.isEmpty()) {
ALog.e(TAG, "修改子任务的文件名失败:列表为null"); ALog.e(TAG, "修改子任务的文件名失败:列表为null");

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
@ -59,6 +60,7 @@ public class DownloadReceiver extends AbsReceiver {
* *
* @param entity 下载实体 * @param entity 下载实体
*/ */
@CheckResult
public DownloadTarget load(DownloadEntity entity) { public DownloadTarget load(DownloadEntity entity) {
return load(entity, false); return load(entity, false);
} }
@ -78,6 +80,7 @@ public class DownloadReceiver extends AbsReceiver {
* </code> * </code>
* </pre> * </pre>
*/ */
@CheckResult
@Deprecated public DownloadTarget load(DownloadEntity entity, boolean refreshInfo) { @Deprecated public DownloadTarget load(DownloadEntity entity, boolean refreshInfo) {
CheckUtil.checkDownloadEntity(entity); CheckUtil.checkDownloadEntity(entity);
return new DownloadTarget(entity, targetName, refreshInfo); return new DownloadTarget(entity, targetName, refreshInfo);
@ -88,6 +91,7 @@ public class DownloadReceiver extends AbsReceiver {
* *
* @param url 下载地址 * @param url 下载地址
*/ */
@CheckResult
public DownloadTarget load(@NonNull String url) { public DownloadTarget load(@NonNull String url) {
return load(url, false); return load(url, false);
} }
@ -108,6 +112,7 @@ public class DownloadReceiver extends AbsReceiver {
* </code> * </code>
* </pre> * </pre>
*/ */
@CheckResult
@Deprecated public DownloadTarget load(@NonNull String url, boolean refreshInfo) { @Deprecated public DownloadTarget load(@NonNull String url, boolean refreshInfo) {
CheckUtil.checkUrlInvalidThrow(url); CheckUtil.checkUrlInvalidThrow(url);
return new DownloadTarget(url, targetName, refreshInfo); return new DownloadTarget(url, targetName, refreshInfo);
@ -120,6 +125,7 @@ public class DownloadReceiver extends AbsReceiver {
* @deprecated {@link #loadGroup(DownloadGroupEntity)} * @deprecated {@link #loadGroup(DownloadGroupEntity)}
*/ */
@Deprecated @Deprecated
@CheckResult
public DownloadGroupTarget load(List<String> urls) { public DownloadGroupTarget load(List<String> urls) {
return loadGroup(urls); return loadGroup(urls);
} }
@ -127,6 +133,7 @@ public class DownloadReceiver extends AbsReceiver {
/** /**
* 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组 * 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组
*/ */
@CheckResult
public DownloadGroupTarget loadGroup(List<String> urls) { public DownloadGroupTarget loadGroup(List<String> urls) {
CheckUtil.checkDownloadUrls(urls); CheckUtil.checkDownloadUrls(urls);
return new DownloadGroupTarget(urls, targetName); return new DownloadGroupTarget(urls, targetName);
@ -137,6 +144,7 @@ public class DownloadReceiver extends AbsReceiver {
* *
* @param entity 下载实体 * @param entity 下载实体
*/ */
@CheckResult
public FtpDownloadTarget loadFtp(DownloadEntity entity) { public FtpDownloadTarget loadFtp(DownloadEntity entity) {
return loadFtp(entity, false); return loadFtp(entity, false);
} }
@ -156,6 +164,7 @@ public class DownloadReceiver extends AbsReceiver {
* </code> * </code>
* </pre> * </pre>
*/ */
@CheckResult
@Deprecated public FtpDownloadTarget loadFtp(DownloadEntity entity, boolean refreshInfo) { @Deprecated public FtpDownloadTarget loadFtp(DownloadEntity entity, boolean refreshInfo) {
CheckUtil.checkDownloadEntity(entity); CheckUtil.checkDownloadEntity(entity);
if (!entity.getUrl().startsWith("ftp")) { if (!entity.getUrl().startsWith("ftp")) {
@ -167,6 +176,7 @@ public class DownloadReceiver extends AbsReceiver {
/** /**
* 加载ftp单任务下载地址 * 加载ftp单任务下载地址
*/ */
@CheckResult
public FtpDownloadTarget loadFtp(@NonNull String url) { public FtpDownloadTarget loadFtp(@NonNull String url) {
return loadFtp(url, false); return loadFtp(url, false);
} }
@ -176,6 +186,7 @@ public class DownloadReceiver extends AbsReceiver {
* *
* @param refreshInfo 是否刷新下载信息 * @param refreshInfo 是否刷新下载信息
*/ */
@CheckResult
public FtpDownloadTarget loadFtp(@NonNull String url, boolean refreshInfo) { public FtpDownloadTarget loadFtp(@NonNull String url, boolean refreshInfo) {
CheckUtil.checkUrlInvalidThrow(url); CheckUtil.checkUrlInvalidThrow(url);
return new FtpDownloadTarget(url, targetName, refreshInfo); return new FtpDownloadTarget(url, targetName, refreshInfo);
@ -189,6 +200,7 @@ public class DownloadReceiver extends AbsReceiver {
* @deprecated 请使用 {@link #loadGroup(DownloadGroupEntity)} * @deprecated 请使用 {@link #loadGroup(DownloadGroupEntity)}
*/ */
@Deprecated @Deprecated
@CheckResult
public DownloadGroupTarget load(DownloadGroupEntity groupEntity) { public DownloadGroupTarget load(DownloadGroupEntity groupEntity) {
return loadGroup(groupEntity); return loadGroup(groupEntity);
} }
@ -199,6 +211,7 @@ public class DownloadReceiver extends AbsReceiver {
* @param groupEntity 如果加载的任务实体没有子项的下载地址 * @param groupEntity 如果加载的任务实体没有子项的下载地址
* 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址 * 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址
*/ */
@CheckResult
public DownloadGroupTarget loadGroup(DownloadGroupEntity groupEntity) { public DownloadGroupTarget loadGroup(DownloadGroupEntity groupEntity) {
return new DownloadGroupTarget(groupEntity, targetName); return new DownloadGroupTarget(groupEntity, targetName);
} }
@ -206,6 +219,7 @@ public class DownloadReceiver extends AbsReceiver {
/** /**
* 加载ftp文件夹下载地址 * 加载ftp文件夹下载地址
*/ */
@CheckResult
public FtpDirDownloadTarget loadFtpDir(@NonNull String dirUrl) { public FtpDirDownloadTarget loadFtpDir(@NonNull String dirUrl) {
CheckUtil.checkUrlInvalidThrow(dirUrl); CheckUtil.checkUrlInvalidThrow(dirUrl);
return new FtpDirDownloadTarget(dirUrl, targetName); return new FtpDirDownloadTarget(dirUrl, targetName);
@ -214,7 +228,7 @@ public class DownloadReceiver extends AbsReceiver {
/** /**
* 将当前类注册到Aria * 将当前类注册到Aria
*/ */
public DownloadReceiver register() { public void register() {
String className = obj.getClass().getName(); String className = obj.getClass().getName();
Set<String> dCounter = ProxyHelper.getInstance().downloadCounter; Set<String> dCounter = ProxyHelper.getInstance().downloadCounter;
Set<String> dgCounter = ProxyHelper.getInstance().downloadGroupCounter; Set<String> dgCounter = ProxyHelper.getInstance().downloadGroupCounter;
@ -226,7 +240,6 @@ public class DownloadReceiver extends AbsReceiver {
&& dgsCounter.contains(className))) { && dgsCounter.contains(className))) {
DownloadGroupSchedulers.getInstance().register(obj); DownloadGroupSchedulers.getInstance().register(obj);
} }
return this;
} }
/** /**
@ -265,7 +278,7 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果url错误或查找不到数据则返回null * @return 如果url错误或查找不到数据则返回null
*/ */
public DownloadEntity getDownloadEntity(String downloadUrl) { public DownloadEntity getDownloadEntity(String downloadUrl) {
if (CheckUtil.checkUrl(downloadUrl)) { if (!CheckUtil.checkUrl(downloadUrl)) {
return null; return null;
} }
return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl); return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl);
@ -278,7 +291,10 @@ public class DownloadReceiver extends AbsReceiver {
* @return 如果url错误或查找不到数据则返回null * @return 如果url错误或查找不到数据则返回null
*/ */
public DownloadTaskEntity getDownloadTask(String downloadUrl) { public DownloadTaskEntity getDownloadTask(String downloadUrl) {
if (CheckUtil.checkUrl(downloadUrl)) { if (!CheckUtil.checkUrl(downloadUrl)) {
return null;
}
if (!taskExists(downloadUrl)) {
return null; return null;
} }
return TEManager.getInstance().getTEntity(DownloadTaskEntity.class, downloadUrl); return TEManager.getInstance().getTEntity(DownloadTaskEntity.class, downloadUrl);
@ -295,6 +311,9 @@ public class DownloadReceiver extends AbsReceiver {
ALog.e(TAG, "获取任务组实体失败:任务组子任务下载地址列表为null"); ALog.e(TAG, "获取任务组实体失败:任务组子任务下载地址列表为null");
return null; return null;
} }
if (!taskExists(urls)) {
return null;
}
return TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, urls); return TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, urls);
} }
@ -309,6 +328,11 @@ public class DownloadReceiver extends AbsReceiver {
ALog.e(TAG, "获取FTP文件夹实体失败:下载路径为null"); ALog.e(TAG, "获取FTP文件夹实体失败:下载路径为null");
return null; return null;
} }
boolean b =
DownloadGroupEntity.findFirst(DownloadGroupEntity.class, "groupName=?", dirUrl) != null;
if (!b) {
return null;
}
return TEManager.getInstance().getFDTEntity(DownloadGroupTaskEntity.class, dirUrl); return TEManager.getInstance().getFDTEntity(DownloadGroupTaskEntity.class, dirUrl);
} }
@ -319,6 +343,20 @@ public class DownloadReceiver extends AbsReceiver {
return DownloadEntity.findFirst(DownloadEntity.class, "url=?", downloadUrl) != null; return DownloadEntity.findFirst(DownloadEntity.class, "url=?", downloadUrl) != null;
} }
/**
* 判断任务组是否存在
*
* @return {@code true} 存在{@code false} 不存在
*/
public boolean taskExists(List<String> urls) {
if (urls == null || urls.isEmpty()) {
return false;
}
String groupName = CommonUtil.getMd5Code(urls);
return DownloadGroupEntity.findFirst(DownloadGroupEntity.class, "groupName=?", groupName)
!= null;
}
/** /**
* 获取所有普通下载任务 * 获取所有普通下载任务
* 获取未完成的普通任务列表{@link #getAllNotCompletTask()} * 获取未完成的普通任务列表{@link #getAllNotCompletTask()}

@ -15,10 +15,12 @@
*/ */
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.delegate.HttpHeaderDelegate; import com.arialyy.aria.core.delegate.HttpHeaderDelegate;
import com.arialyy.aria.core.inf.IHttpHeaderTarget; import com.arialyy.aria.core.inf.IHttpHeaderTarget;
import java.net.Proxy;
import java.util.Map; import java.util.Map;
/** /**
@ -29,7 +31,7 @@ public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
implements IHttpHeaderTarget<DownloadTarget> { implements IHttpHeaderTarget<DownloadTarget> {
private HttpHeaderDelegate<DownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate; private HttpHeaderDelegate<DownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate;
DownloadTarget(DownloadEntity entity, String targetName) { public DownloadTarget(DownloadEntity entity, String targetName) {
this(entity, targetName, false); this(entity, targetName, false);
} }
@ -52,11 +54,23 @@ public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
* *
* @param use {@code true} 使用 * @param use {@code true} 使用
*/ */
@CheckResult
public DownloadTarget useServerFileName(boolean use) { public DownloadTarget useServerFileName(boolean use) {
mTaskEntity.setUseServerFileName(use); mTaskEntity.setUseServerFileName(use);
return this; return this;
} }
/**
* 设置URL的代理
*
* @param proxy {@link Proxy}
*/
@CheckResult
public DownloadTarget setUrlProxy(Proxy proxy) {
mTaskEntity.setProxy(proxy);
return this;
}
/** /**
* 设置文件存储路径 * 设置文件存储路径
* 该api后续版本会删除 * 该api后续版本会删除
@ -64,6 +78,7 @@ public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
* @param downloadPath 文件保存路径 * @param downloadPath 文件保存路径
* @deprecated {@link #setFilePath(String)} 请使用这个api * @deprecated {@link #setFilePath(String)} 请使用这个api
*/ */
@CheckResult
@Deprecated public DownloadTarget setDownloadPath(@NonNull String downloadPath) { @Deprecated public DownloadTarget setDownloadPath(@NonNull String downloadPath) {
return setFilePath(downloadPath); return setFilePath(downloadPath);
} }
@ -75,6 +90,7 @@ public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
* *
* @param filePath 路径必须为文件路径不能为文件夹路径 * @param filePath 路径必须为文件路径不能为文件夹路径
*/ */
@CheckResult
public DownloadTarget setFilePath(@NonNull String filePath) { public DownloadTarget setFilePath(@NonNull String filePath) {
mTempFilePath = filePath; mTempFilePath = filePath;
return this; return this;
@ -91,14 +107,17 @@ public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
return HTTP; return HTTP;
} }
@CheckResult
@Override public DownloadTarget addHeader(@NonNull String key, @NonNull String value) { @Override public DownloadTarget addHeader(@NonNull String key, @NonNull String value) {
return mDelegate.addHeader(key, value); return mDelegate.addHeader(key, value);
} }
@CheckResult
@Override public DownloadTarget addHeaders(Map<String, String> headers) { @Override public DownloadTarget addHeaders(Map<String, String> headers) {
return mDelegate.addHeaders(headers); return mDelegate.addHeaders(headers);
} }
@CheckResult
@Override public DownloadTarget setRequestMode(RequestEnum requestEnum) { @Override public DownloadTarget setRequestMode(RequestEnum requestEnum) {
return mDelegate.setRequestMode(requestEnum); return mDelegate.setRequestMode(requestEnum);
} }

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.support.annotation.CheckResult;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.delegate.FtpDelegate; import com.arialyy.aria.core.delegate.FtpDelegate;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
@ -89,15 +90,15 @@ public class FtpDirDownloadTarget extends BaseGroupTarget<FtpDirDownloadTarget>
} }
return true; return true;
} }
@CheckResult
@Override public FtpDirDownloadTarget charSet(String charSet) { @Override public FtpDirDownloadTarget charSet(String charSet) {
return mDelegate.charSet(charSet); return mDelegate.charSet(charSet);
} }
@CheckResult
@Override public FtpDirDownloadTarget login(String userName, String password) { @Override public FtpDirDownloadTarget login(String userName, String password) {
return mDelegate.login(userName, password); return mDelegate.login(userName, password);
} }
@CheckResult
@Override public FtpDirDownloadTarget login(String userName, String password, String account) { @Override public FtpDirDownloadTarget login(String userName, String password, String account) {
return mDelegate.login(userName, password, account); return mDelegate.login(userName, password, account);
} }

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.arialyy.aria.core.delegate.FtpDelegate; import com.arialyy.aria.core.delegate.FtpDelegate;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
@ -29,7 +30,7 @@ public class FtpDownloadTarget extends BaseNormalTarget<FtpDownloadTarget>
implements IFtpTarget<FtpDownloadTarget> { implements IFtpTarget<FtpDownloadTarget> {
private FtpDelegate<FtpDownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate; private FtpDelegate<FtpDownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate;
FtpDownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) { public FtpDownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) {
this(entity.getUrl(), targetName, refreshInfo); this(entity.getUrl(), targetName, refreshInfo);
} }
@ -59,6 +60,7 @@ public class FtpDownloadTarget extends BaseNormalTarget<FtpDownloadTarget>
* @deprecated {@link #setFilePath(String)} 请使用这个api * @deprecated {@link #setFilePath(String)} 请使用这个api
*/ */
@Deprecated @Deprecated
@CheckResult
public FtpDownloadTarget setDownloadPath(@NonNull String filePath) { public FtpDownloadTarget setDownloadPath(@NonNull String filePath) {
return setFilePath(filePath); return setFilePath(filePath);
} }
@ -69,6 +71,7 @@ public class FtpDownloadTarget extends BaseNormalTarget<FtpDownloadTarget>
* 1如果保存路径是该文件的保存路径/mnt/sdcard/file.zip则使用路径中的文件名file.zip * 1如果保存路径是该文件的保存路径/mnt/sdcard/file.zip则使用路径中的文件名file.zip
* 2如果保存路径是文件夹路径/mnt/sdcard/则使用FTP服务器该文件的文件名 * 2如果保存路径是文件夹路径/mnt/sdcard/则使用FTP服务器该文件的文件名
*/ */
@CheckResult
public FtpDownloadTarget setFilePath(@NonNull String filePath) { public FtpDownloadTarget setFilePath(@NonNull String filePath) {
mTempFilePath = filePath; mTempFilePath = filePath;
return this; return this;
@ -78,14 +81,17 @@ public class FtpDownloadTarget extends BaseNormalTarget<FtpDownloadTarget>
return FTP; return FTP;
} }
@CheckResult
@Override public FtpDownloadTarget charSet(String charSet) { @Override public FtpDownloadTarget charSet(String charSet) {
return mDelegate.charSet(charSet); return mDelegate.charSet(charSet);
} }
@CheckResult
@Override public FtpDownloadTarget login(String userName, String password) { @Override public FtpDownloadTarget login(String userName, String password) {
return mDelegate.login(userName, password); return mDelegate.login(userName, password);
} }
@CheckResult
@Override public FtpDownloadTarget login(String userName, String password, String account) { @Override public FtpDownloadTarget login(String userName, String password, String account) {
return mDelegate.login(userName, password, account); return mDelegate.login(userName, password, account);
} }

@ -39,15 +39,16 @@ import java.util.concurrent.Executors;
* 任务组核心逻辑 * 任务组核心逻辑
*/ */
public abstract class AbsGroupUtil implements IUtil { public abstract class AbsGroupUtil implements IUtil {
private static final Object LOCK = new Object();
private final String TAG = "AbsGroupUtil"; private final String TAG = "AbsGroupUtil";
/** /**
* FTP文件夹 * FTP文件夹
*/ */
protected int FTP_DIR = 0xa1; int FTP_DIR = 0xa1;
/** /**
* HTTP 任务组 * HTTP 任务组
*/ */
protected int HTTP_GROUP = 0xa2; int HTTP_GROUP = 0xa2;
/** /**
* 任务组所有任务总长度 * 任务组所有任务总长度
@ -56,7 +57,7 @@ public abstract class AbsGroupUtil implements IUtil {
long mCurrentLocation = 0; long mCurrentLocation = 0;
private ExecutorService mExePool; private ExecutorService mExePool;
protected IDownloadGroupListener mListener; protected IDownloadGroupListener mListener;
protected DownloadGroupTaskEntity mGTEntity; DownloadGroupTaskEntity mGTEntity;
private boolean isRunning = false; private boolean isRunning = false;
private Timer mTimer; private Timer mTimer;
/** /**
@ -158,6 +159,9 @@ public abstract class AbsGroupUtil implements IUtil {
DownloadTaskEntity det = mTasksMap.get(url); DownloadTaskEntity det = mTasksMap.get(url);
if (det != null) { if (det != null) {
mTotalLen -= det.getEntity().getFileSize(); mTotalLen -= det.getEntity().getFileSize();
mCurrentLocation -= det.getEntity().getCurrentProgress();
mExeMap.remove(det.getKey());
mFailMap.remove(det.getKey());
mGroupSize--; mGroupSize--;
if (mGroupSize == 0) { if (mGroupSize == 0) {
closeTimer(false); closeTimer(false);
@ -255,6 +259,9 @@ public abstract class AbsGroupUtil implements IUtil {
dt.stop(); dt.stop();
} }
} }
if (mDownloaderMap.size() == 0){
mListener.onStop(mCurrentLocation);
}
} }
protected void onStop() { protected void onStop() {
@ -262,7 +269,7 @@ public abstract class AbsGroupUtil implements IUtil {
} }
/** /**
* 预处理操作由于属性的不同http任务组在构造函数中就可以完成了 * 预处理操作
* 而FTP文件夹的需要获取完成所有子任务信息才算预处理完成 * 而FTP文件夹的需要获取完成所有子任务信息才算预处理完成
*/ */
protected void onPre() { protected void onPre() {
@ -284,7 +291,6 @@ public abstract class AbsGroupUtil implements IUtil {
} }
mTasksMap.put(te.getUrl(), te); mTasksMap.put(te.getUrl(), te);
} }
updateFileSize();
} }
@Override public void start() { @Override public void start() {
@ -299,19 +305,18 @@ public abstract class AbsGroupUtil implements IUtil {
@Override public void resume() { @Override public void resume() {
start(); start();
mListener.onResume(mCurrentLocation);
} }
@Override public void setMaxSpeed(double maxSpeed) { @Override public void setMaxSpeed(double maxSpeed) {
} }
private void clearState(){ private void clearState() {
mDownloaderMap.clear(); mDownloaderMap.clear();
mFailMap.clear(); mFailMap.clear();
} }
private void closeTimer(boolean isRunning) { void closeTimer(boolean isRunning) {
this.isRunning = isRunning; this.isRunning = isRunning;
if (mTimer != null) { if (mTimer != null) {
mTimer.purge(); mTimer.purge();
@ -326,7 +331,11 @@ public abstract class AbsGroupUtil implements IUtil {
void startRunningFlow() { void startRunningFlow() {
closeTimer(true); closeTimer(true);
mListener.onPostPre(mTotalLen); mListener.onPostPre(mTotalLen);
mListener.onStart(mCurrentLocation); if (mCurrentLocation > 0) {
mListener.onResume(mCurrentLocation);
} else {
mListener.onStart(mCurrentLocation);
}
startTimer(); startTimer();
} }
@ -337,7 +346,16 @@ public abstract class AbsGroupUtil implements IUtil {
if (!isRunning) { if (!isRunning) {
closeTimer(false); closeTimer(false);
} else if (mCurrentLocation >= 0) { } else if (mCurrentLocation >= 0) {
mListener.onProgress(mCurrentLocation); long t = 0;
for (DownloadTaskEntity te : mGTEntity.getSubTaskEntities()) {
if (te.getState() == IEntity.STATE_COMPLETE) {
t += te.getEntity().getFileSize();
} else {
t += te.getEntity().getCurrentProgress();
}
}
mCurrentLocation = t;
mListener.onProgress(t);
} }
} }
}, 0, mUpdateInterval); }, 0, mUpdateInterval);
@ -346,8 +364,8 @@ public abstract class AbsGroupUtil implements IUtil {
/** /**
* 创建子任务下载器默认创建完成自动启动 * 创建子任务下载器默认创建完成自动启动
*/ */
Downloader createChildDownload(DownloadTaskEntity taskEntity) { void createChildDownload(DownloadTaskEntity taskEntity) {
return createChildDownload(taskEntity, true); createChildDownload(taskEntity, true);
} }
/** /**
@ -375,6 +393,8 @@ public abstract class AbsGroupUtil implements IUtil {
private int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度 private int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度
private long lastSaveTime; private long lastSaveTime;
private long lastLen = 0; private long lastLen = 0;
private Timer timer;
private boolean isNotNetRetry = false;
ChildDownloadListener(DownloadTaskEntity entity) { ChildDownloadListener(DownloadTaskEntity entity) {
subTaskEntity = entity; subTaskEntity = entity;
@ -382,6 +402,7 @@ public abstract class AbsGroupUtil implements IUtil {
subEntity.setFailNum(0); subEntity.setFailNum(0);
lastLen = subEntity.getCurrentProgress(); lastLen = subEntity.getCurrentProgress();
lastSaveTime = System.currentTimeMillis(); lastSaveTime = System.currentTimeMillis();
isNotNetRetry = AriaManager.getInstance(AriaManager.APP).getDownloadConfig().isNotNetRetry();
} }
@Override public void onPre() { @Override public void onPre() {
@ -409,7 +430,7 @@ public abstract class AbsGroupUtil implements IUtil {
@Override public void onProgress(long currentLocation) { @Override public void onProgress(long currentLocation) {
long speed = currentLocation - lastLen; long speed = currentLocation - lastLen;
mCurrentLocation += speed; //mCurrentLocation += speed;
subEntity.setCurrentProgress(currentLocation); subEntity.setCurrentProgress(currentLocation);
handleSpeed(speed); handleSpeed(speed);
mListener.onSubRunning(subEntity); mListener.onSubRunning(subEntity);
@ -424,7 +445,7 @@ public abstract class AbsGroupUtil implements IUtil {
saveData(IEntity.STATE_STOP, stopLocation); saveData(IEntity.STATE_STOP, stopLocation);
handleSpeed(0); handleSpeed(0);
mListener.onSubStop(subEntity); mListener.onSubStop(subEntity);
synchronized (AbsGroupUtil.class) { synchronized (AbsGroupUtil.LOCK) {
mStopNum++; mStopNum++;
if (mStopNum + mCompleteNum + mFailMap.size() == mGroupSize) { if (mStopNum + mCompleteNum + mFailMap.size() == mGroupSize) {
closeTimer(false); closeTimer(false);
@ -440,16 +461,17 @@ public abstract class AbsGroupUtil implements IUtil {
} }
@Override public void onComplete() { @Override public void onComplete() {
subEntity.setComplete(true);
saveData(IEntity.STATE_COMPLETE, subEntity.getFileSize()); saveData(IEntity.STATE_COMPLETE, subEntity.getFileSize());
handleSpeed(0); handleSpeed(0);
mListener.onSubComplete(subEntity); mListener.onSubComplete(subEntity);
synchronized (ChildDownloadListener.class) { synchronized (AbsGroupUtil.LOCK) {
mCompleteNum++; mCompleteNum++;
//如果子任务完成的数量和总任务数一致,表示任务组任务已经完成 //如果子任务完成的数量和总任务数一致,表示任务组任务已经完成
if (mCompleteNum >= mGroupSize) { if (mCompleteNum == mGroupSize) {
closeTimer(false); closeTimer(false);
mListener.onComplete(); mListener.onComplete();
} else if (mFailMap.size() > 0 && mStopNum + mCompleteNum + mFailMap.size() >= mGroupSize) { } else if (mFailMap.size() > 0 && mStopNum + mCompleteNum + mFailMap.size() == mGroupSize) {
//如果子任务完成数量加上失败的数量和总任务数一致,则任务组停止下载 //如果子任务完成数量加上失败的数量和总任务数一致,则任务组停止下载
closeTimer(false); closeTimer(false);
mListener.onStop(mCurrentLocation); mListener.onStop(mCurrentLocation);
@ -465,41 +487,48 @@ public abstract class AbsGroupUtil implements IUtil {
} }
/** /**
* 重试下载 * 重试下载只有全部都下载失败才会执行任务组的整体重试否则只会执行单个子任务的重试
*/ */
private void reTry(boolean needRetry) { private void reTry(boolean needRetry) {
synchronized (ChildDownloadListener.class) { synchronized (AbsGroupUtil.LOCK) {
if (subEntity.getFailNum() < 5 && needRetry && NetUtils.isConnected(AriaManager.APP)) { if (subEntity.getFailNum() < 5
&& needRetry && (NetUtils.isConnected(AriaManager.APP) || isNotNetRetry)) {
reStartTask(); reStartTask();
} else { } else {
mFailMap.put(subTaskEntity.getUrl(), subTaskEntity); mFailMap.put(subTaskEntity.getUrl(), subTaskEntity);
mListener.onSubFail(subEntity); mListener.onSubFail(subEntity);
//如果失败的任务数大于实际的下载任务数,任务组停止下载 if (mFailMap.size() == mExeMap.size() || mFailMap.size() + mCompleteNum == mGroupSize) {
if (mFailMap.size() >= mExeMap.size()) {
closeTimer(false); closeTimer(false);
if (mFailMap.size() == mGroupSize) { //所有任务都失败了,则认为该任务组已经失败 }
mListener.onFail(true); if (mFailMap.size() == mGroupSize) {
} else { mListener.onFail(true);
mListener.onStop(mCurrentLocation); } else if (mFailMap.size() + mCompleteNum >= mExeMap.size()) {
} mListener.onStop(mCurrentLocation);
} }
} }
} }
} }
private void reStartTask() { private void reStartTask() {
Timer timer = new Timer(); if (timer != null) {
timer.purge();
timer.cancel();
}
timer = new Timer();
timer.schedule(new TimerTask() { timer.schedule(new TimerTask() {
@Override public void run() { @Override public void run() {
Downloader dt = mDownloaderMap.get(subEntity.getUrl()); Downloader dt = mDownloaderMap.get(subEntity.getUrl());
dt.start(); if (dt != null) {
dt.retryThreadTask();
}
} }
}, 3000); }, 3000);
} }
private void handleSpeed(long speed) { private void handleSpeed(long speed) {
subEntity.setSpeed(speed); subEntity.setSpeed(speed);
subEntity.setConvertSpeed(speed <= 0 ? "" : CommonUtil.formatFileSize(speed) + "/s"); subEntity.setConvertSpeed(
speed <= 0 ? "" : String.format("%s/s", CommonUtil.formatFileSize(speed)));
subEntity.setPercent((int) (subEntity.getFileSize() <= 0 ? 0 subEntity.setPercent((int) (subEntity.getFileSize() <= 0 ? 0
: subEntity.getCurrentProgress() * 100 / subEntity.getFileSize())); : subEntity.getCurrentProgress() * 100 / subEntity.getFileSize()));
} }

@ -16,7 +16,9 @@
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.util.SSLContextUtil; import com.arialyy.aria.util.SSLContextUtil;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -44,7 +46,7 @@ class ConnectionHelp {
* @throws IOException * @throws IOException
*/ */
static InputStream convertInputStream(HttpURLConnection connection) throws IOException { static InputStream convertInputStream(HttpURLConnection connection) throws IOException {
String encoding = connection.getContentEncoding(); String encoding = connection.getHeaderField("Content-Encoding");
if (TextUtils.isEmpty(encoding)) { if (TextUtils.isEmpty(encoding)) {
return connection.getInputStream(); return connection.getInputStream();
} }
@ -62,9 +64,14 @@ class ConnectionHelp {
* *
* @throws IOException * @throws IOException
*/ */
static HttpURLConnection handleConnection(URL url) throws IOException { static HttpURLConnection handleConnection(URL url, AbsTaskEntity taskEntity) throws IOException {
HttpURLConnection conn; HttpURLConnection conn;
URLConnection urlConn = url.openConnection(); URLConnection urlConn;
if (taskEntity.getProxy() != null) {
urlConn = url.openConnection(taskEntity.getProxy());
} else {
urlConn = url.openConnection();
}
if (urlConn instanceof HttpsURLConnection) { if (urlConn instanceof HttpsURLConnection) {
conn = (HttpsURLConnection) urlConn; conn = (HttpsURLConnection) urlConn;
SSLContext sslContext = SSLContext sslContext =
@ -86,9 +93,10 @@ class ConnectionHelp {
* *
* @throws ProtocolException * @throws ProtocolException
*/ */
static HttpURLConnection setConnectParam(DownloadTaskEntity entity, HttpURLConnection conn) static HttpURLConnection setConnectParam(DownloadTaskEntity entity, HttpURLConnection conn) {
throws ProtocolException { if (entity.getRequestEnum() == RequestEnum.POST) {
conn.setRequestMethod(entity.getRequestEnum().name); conn.setDoInput(true);
}
Set<String> keys = null; Set<String> keys = null;
if (entity.getHeaders() != null && entity.getHeaders().size() > 0) { if (entity.getHeaders() != null && entity.getHeaders().size() > 0) {
keys = entity.getHeaders().keySet(); keys = entity.getHeaders().keySet();

@ -34,7 +34,17 @@ import java.util.concurrent.Executors;
public class DownloadGroupUtil extends AbsGroupUtil implements IUtil { public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
private final String TAG = "DownloadGroupUtil"; private final String TAG = "DownloadGroupUtil";
private ExecutorService mInfoPool; private ExecutorService mInfoPool;
private int mInitCompleteNum, mInitFailNum; /**
* 初始化完成的任务数
*/
private int mInitCompleteNum;
/**
* 初始化失败的任务数
*/
private int mInitFailNum;
private boolean isStop = false;
private boolean isStart = false;
private int mExeNum;
/** /**
* 文件信息回调组 * 文件信息回调组
@ -44,7 +54,6 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
public DownloadGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) { public DownloadGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) {
super(listener, taskEntity); super(listener, taskEntity);
mInfoPool = Executors.newCachedThreadPool(); mInfoPool = Executors.newCachedThreadPool();
onPre();
} }
@Override int getTaskType() { @Override int getTaskType() {
@ -53,6 +62,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
@Override public void onCancel() { @Override public void onCancel() {
super.onCancel(); super.onCancel();
isStop = true;
if (!mInfoPool.isShutdown()) { if (!mInfoPool.isShutdown()) {
mInfoPool.shutdown(); mInfoPool.shutdown();
} }
@ -60,13 +70,15 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
@Override protected void onStop() { @Override protected void onStop() {
super.onStop(); super.onStop();
isStop = true;
if (!mInfoPool.isShutdown()) { if (!mInfoPool.isShutdown()) {
mInfoPool.shutdown(); mInfoPool.shutdown();
} }
} }
@Override protected void onStart() { @Override protected void onStart() {
super.onStart(); onPre();
isStop = false;
if (mCompleteNum == mGroupSize) { if (mCompleteNum == mGroupSize) {
mListener.onComplete(); mListener.onComplete();
return; return;
@ -78,12 +90,15 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
return; return;
} }
Set<String> keys = mExeMap.keySet(); Set<String> keys = mExeMap.keySet();
mExeNum = mExeMap.size();
for (String key : keys) { for (String key : keys) {
DownloadTaskEntity taskEntity = mExeMap.get(key); DownloadTaskEntity taskEntity = mExeMap.get(key);
if (taskEntity != null) { if (taskEntity != null) {
if (taskEntity.getState() != IEntity.STATE_FAIL if (taskEntity.getState() != IEntity.STATE_FAIL
&& taskEntity.getState() != IEntity.STATE_WAIT) { && taskEntity.getState() != IEntity.STATE_WAIT) {
mInitCompleteNum++;
createChildDownload(taskEntity); createChildDownload(taskEntity);
checkStartFlow();
} else { } else {
mInfoPool.execute(createFileInfoThread(taskEntity)); mInfoPool.execute(createFileInfoThread(taskEntity));
} }
@ -105,6 +120,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
int failNum = 0; int failNum = 0;
@Override public void onComplete(String url, CompleteInfo info) { @Override public void onComplete(String url, CompleteInfo info) {
if (isStop) return;
DownloadTaskEntity te = mExeMap.get(url); DownloadTaskEntity te = mExeMap.get(url);
if (te != null) { if (te != null) {
if (isNeedLoadFileSize) { if (isNeedLoadFileSize) {
@ -112,16 +128,14 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
} }
createChildDownload(te); createChildDownload(te);
} }
mInitCompleteNum ++; mInitCompleteNum++;
if (mInitCompleteNum + mInitFailNum >= mGroupSize || !isNeedLoadFileSize) { checkStartFlow();
startRunningFlow();
updateFileSize();
}
} }
@Override public void onFail(String url, String errorMsg, boolean needRetry) { @Override public void onFail(String url, String errorMsg, boolean needRetry) {
ALog.e(TAG, "任务【" + url + "】初始化失败。"); if (isStop) return;
ALog.e(TAG, String.format("任务【%s】初始化失败", url));
DownloadTaskEntity te = mExeMap.get(url); DownloadTaskEntity te = mExeMap.get(url);
if (te != null) { if (te != null) {
mFailMap.put(url, te); mFailMap.put(url, te);
@ -136,14 +150,28 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
// mInitFailNum++; // mInitFailNum++;
//} //}
//failNum++; //failNum++;
mInitFailNum ++; mInitFailNum++;
if (mInitCompleteNum + mInitFailNum >= mGroupSize || !isNeedLoadFileSize) { checkStartFlow();
startRunningFlow();
updateFileSize();
}
} }
}; };
} }
return new HttpFileInfoThread(taskEntity, callback); return new HttpFileInfoThread(taskEntity, callback);
} }
/**
* 检查能否启动下载流程
*/
private void checkStartFlow() {
synchronized (DownloadGroupUtil.class) {
if (mInitFailNum == mExeNum) {
closeTimer(false);
mListener.onFail(true);
}
if (!isStart && mInitCompleteNum + mInitFailNum == mExeNum || !isNeedLoadFileSize) {
startRunningFlow();
updateFileSize();
isStart = true;
}
}
}
} }

@ -45,23 +45,26 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
} }
@Override protected int setNewTaskThreadNum() { @Override protected int setNewTaskThreadNum() {
int threadNum = AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum();
return return
// 小于1m的文件或是任务组的子任务、使用虚拟文件,线程数都是1 // 小于1m的文件或是任务组的子任务、使用虚拟文件,线程数都是1
mEntity.getFileSize() <= SUB_LEN mEntity.getFileSize() <= SUB_LEN
|| mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP_DIR || mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP_DIR
|| mTaskEntity.getRequestType() == AbsTaskEntity.DG_HTTP || mTaskEntity.getRequestType() == AbsTaskEntity.DG_HTTP
|| mRecord.isOpenDynamicFile || threadNum == 1
? 1 ? 1
: AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum(); : threadNum;
} }
@Override protected boolean handleNewTask() { @Override protected boolean handleNewTask() {
CommonUtil.createFile(mTempFile.getPath()); CommonUtil.createFile(mTempFile.getPath());
BufferedRandomAccessFile file = null; BufferedRandomAccessFile file = null;
try { try {
file = new BufferedRandomAccessFile(new File(mTempFile.getPath()), "rwd", 8192); if (mTotalThreadNum > 1) {
//设置文件长度 file = new BufferedRandomAccessFile(new File(mTempFile.getPath()), "rwd", 8192);
file.setLength(mRecord.isOpenDynamicFile ? 1 : mEntity.getFileSize()); //设置文件长度
file.setLength(mEntity.getFileSize());
}
return true; return true;
} catch (IOException e) { } catch (IOException e) {
failDownload("下载失败【downloadUrl:" failDownload("下载失败【downloadUrl:"

@ -24,8 +24,13 @@ import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener; import com.arialyy.aria.core.inf.IDownloadListener;
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 java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply; import org.apache.commons.net.ftp.FTPReply;
@ -36,10 +41,6 @@ import org.apache.commons.net.ftp.FTPReply;
class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity> { class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity> {
private final String TAG = "FtpThreadTask"; private final String TAG = "FtpThreadTask";
private boolean isOpenDynamicFile; private boolean isOpenDynamicFile;
/**
* 2M的动态长度
*/
private final int LEN_INTERVAL = 1024 * 1024 * 2;
FtpThreadTask(StateConstance constance, IDownloadListener listener, FtpThreadTask(StateConstance constance, IDownloadListener listener,
SubThreadConfig<DownloadTaskEntity> downloadInfo) { SubThreadConfig<DownloadTaskEntity> downloadInfo) {
@ -49,7 +50,7 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
mReadTimeOut = manager.getDownloadConfig().getIOTimeOut(); mReadTimeOut = manager.getDownloadConfig().getIOTimeOut();
mBufSize = manager.getDownloadConfig().getBuffSize(); mBufSize = manager.getDownloadConfig().getBuffSize();
isNotNetRetry = manager.getDownloadConfig().isNotNetRetry(); isNotNetRetry = manager.getDownloadConfig().isNotNetRetry();
isOpenDynamicFile = STATE.TASK_RECORD.isOpenDynamicFile; isOpenDynamicFile = STATE.isOpenDynamicFile;
setMaxSpeed(manager.getDownloadConfig().getMaxSpeed()); setMaxSpeed(manager.getDownloadConfig().getMaxSpeed());
} }
@ -58,17 +59,11 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
mChildCurrentLocation = mConfig.START_LOCATION; mChildCurrentLocation = mConfig.START_LOCATION;
FTPClient client = null; FTPClient client = null;
InputStream is = null; InputStream is = null;
BufferedRandomAccessFile file = null;
try { try {
ALog.d(TAG, "任务【" ALog.d(TAG,
+ mConfig.TEMP_FILE.getName() String.format("任务【%s】线程__%s__开始下载【开始位置 : %s,结束位置:%s】", mConfig.TEMP_FILE.getName(),
+ "】线程__" mConfig.THREAD_ID, mConfig.START_LOCATION, mConfig.END_LOCATION));
+ mConfig.THREAD_ID
+ "__开始下载【开始位置 : "
+ mConfig.START_LOCATION
+ ",结束位置:"
+ mConfig.END_LOCATION
+ "】");
client = createClient(); client = createClient();
if (client == null) return; if (client == null) return;
if (mConfig.START_LOCATION > 0) { if (mConfig.START_LOCATION > 0) {
@ -77,51 +72,37 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
//发送第二次指令时,还需要再做一次判断 //发送第二次指令时,还需要再做一次判断
int reply = client.getReplyCode(); int reply = client.getReplyCode();
if (!FTPReply.isPositivePreliminary(reply) && reply != FTPReply.COMMAND_OK) { if (!FTPReply.isPositivePreliminary(reply) && reply != FTPReply.COMMAND_OK) {
fail(mChildCurrentLocation, "获取文件信息错误,错误码为:" + reply + ",msg:" + client.getReplyString(), fail(mChildCurrentLocation,
String.format("获取文件信息错误,错误码为:%s,msg:%s", reply, client.getReplyString()),
null); null);
client.disconnect(); client.disconnect();
return; return;
} }
String remotePath = String remotePath =
new String(mTaskEntity.getUrlEntity().remotePath.getBytes(charSet), SERVER_CHARSET); new String(mTaskEntity.getUrlEntity().remotePath.getBytes(charSet), SERVER_CHARSET);
ALog.i(TAG, "remotePath【" + remotePath + "】"); ALog.i(TAG, String.format("remotePath【%s】", remotePath));
is = client.retrieveFileStream(remotePath); is = client.retrieveFileStream(remotePath);
reply = client.getReplyCode(); reply = client.getReplyCode();
if (!FTPReply.isPositivePreliminary(reply)) { if (!FTPReply.isPositivePreliminary(reply)) {
fail(mChildCurrentLocation, "获取流失败,错误码为:" + reply + ",msg:" + client.getReplyString(), fail(mChildCurrentLocation,
String.format("获取流失败,错误码为:%s,msg:%s", reply, client.getReplyString()),
null); null);
client.disconnect(); client.disconnect();
return; return;
} }
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize); if (isOpenDynamicFile) {
file.seek(mConfig.START_LOCATION); readDynamicFile(is);
byte[] buffer = new byte[mBufSize]; } else {
int len; readNormal(is);
}
while ((len = is.read(buffer)) != -1) { if (isBreak()) {
if (STATE.isCancel || STATE.isStop) { return;
break;
}
if (mSleepTime > 0) Thread.sleep(mSleepTime);
if (isOpenDynamicFile) {
file.setLength(
STATE.CURRENT_LOCATION + LEN_INTERVAL < mEntity.getFileSize() ? STATE.CURRENT_LOCATION
+ LEN_INTERVAL : mEntity.getFileSize());
}
if (mChildCurrentLocation + len >= mConfig.END_LOCATION) {
len = (int) (mConfig.END_LOCATION - mChildCurrentLocation);
file.write(buffer, 0, len);
progress(len);
break;
} else {
file.write(buffer, 0, len);
progress(len);
}
} }
if (STATE.isCancel || STATE.isStop) return; ALog.i(TAG,
ALog.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕"); String.format("任务【%s】线程__%s__下载完毕", mConfig.TEMP_FILE.getName(), mConfig.THREAD_ID));
writeConfig(true, 1); writeConfig(true, mConfig.END_LOCATION);
STATE.COMPLETE_THREAD_NUM++; STATE.COMPLETE_THREAD_NUM++;
if (STATE.isComplete()) { if (STATE.isComplete()) {
STATE.TASK_RECORD.deleteData(); STATE.TASK_RECORD.deleteData();
@ -133,14 +114,11 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
mListener.onFail(false); mListener.onFail(false);
} }
} catch (IOException e) { } catch (IOException e) {
fail(mChildCurrentLocation, "下载失败【" + mConfig.URL + "】", e); fail(mChildCurrentLocation, String.format("下载失败【%s】", mConfig.URL), e);
} catch (Exception e) { } catch (Exception e) {
fail(mChildCurrentLocation, "获取流失败", e); fail(mChildCurrentLocation, "获取流失败", e);
} finally { } finally {
try { try {
if (file != null) {
file.close();
}
if (is != null) { if (is != null) {
is.close(); is.close();
} }
@ -153,7 +131,89 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
} }
} }
@Override protected String getTaskType() { /**
return "FTP_DOWNLOAD"; * 动态长度文件读取方式
*/
private void readDynamicFile(InputStream is) {
FileOutputStream fos = null;
FileChannel foc = null;
ReadableByteChannel fic = null;
try {
int len;
fos = new FileOutputStream(mConfig.TEMP_FILE, true);
foc = fos.getChannel();
fic = Channels.newChannel(is);
ByteBuffer bf = ByteBuffer.allocate(mBufSize);
while ((len = fic.read(bf)) != -1) {
if (isBreak()) {
break;
}
if (mSleepTime > 0) {
Thread.sleep(mSleepTime);
}
bf.flip();
foc.write(bf);
bf.compact();
progress(len);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
fail(mChildCurrentLocation, String.format("下载失败【%s】", mConfig.URL), e);
} finally {
try {
if (fos != null) {
fos.close();
}
if (foc != null) {
foc.close();
}
if (fic != null) {
fic.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 多线程写文件方式
*/
private void readNormal(InputStream is) {
BufferedRandomAccessFile file = null;
try {
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize);
file.seek(mConfig.START_LOCATION);
byte[] buffer = new byte[mBufSize];
int len;
while ((len = is.read(buffer)) != -1) {
if (isBreak()) {
break;
}
if (mSleepTime > 0) Thread.sleep(mSleepTime);
if (mChildCurrentLocation + len >= mConfig.END_LOCATION) {
len = (int) (mConfig.END_LOCATION - mChildCurrentLocation);
file.write(buffer, 0, len);
progress(len);
break;
} else {
file.write(buffer, 0, len);
progress(len);
}
}
} catch (IOException e) {
fail(mChildCurrentLocation, String.format("下载失败【%s】", mConfig.URL), e);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
if (file != null) {
file.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
} }
} }

@ -54,7 +54,7 @@ class HttpFileInfoThread implements Runnable {
HttpURLConnection conn = null; HttpURLConnection conn = null;
try { try {
URL url = new URL(CommonUtil.convertUrl(mEntity.getUrl())); URL url = new URL(CommonUtil.convertUrl(mEntity.getUrl()));
conn = ConnectionHelp.handleConnection(url); conn = ConnectionHelp.handleConnection(url, mTaskEntity);
conn = ConnectionHelp.setConnectParam(mTaskEntity, conn); conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
conn.setRequestProperty("Range", "bytes=" + 0 + "-"); conn.setRequestProperty("Range", "bytes=" + 0 + "-");
conn.setConnectTimeout(mConnectTimeOut); conn.setConnectTimeout(mConnectTimeOut);
@ -133,7 +133,11 @@ class HttpFileInfoThread implements Runnable {
mTaskEntity.setSupportBP(true); mTaskEntity.setSupportBP(true);
end = true; end = true;
} else if (code == HttpURLConnection.HTTP_OK) { } else if (code == HttpURLConnection.HTTP_OK) {
if (conn.getHeaderField("Content-Type").equals("text/html")) { String contentType = conn.getHeaderField("Content-Type");
if (TextUtils.isEmpty(contentType)) {
return;
}
if (contentType.equals("text/html")) {
BufferedReader reader = BufferedReader reader =
new BufferedReader(new InputStreamReader(ConnectionHelp.convertInputStream(conn))); new BufferedReader(new InputStreamReader(ConnectionHelp.convertInputStream(conn)));
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -155,7 +159,8 @@ class HttpFileInfoThread implements Runnable {
failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:404", true); failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:404", true);
} else if (code == HttpURLConnection.HTTP_MOVED_TEMP } else if (code == HttpURLConnection.HTTP_MOVED_TEMP
|| code == HttpURLConnection.HTTP_MOVED_PERM || code == HttpURLConnection.HTTP_MOVED_PERM
|| code == HttpURLConnection.HTTP_SEE_OTHER) { || code == HttpURLConnection.HTTP_SEE_OTHER
|| code == 307) {
handleUrlReTurn(conn, conn.getHeaderField("Location")); handleUrlReTurn(conn, conn.getHeaderField("Location"));
} else { } else {
failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:" + code, true); failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:" + code, true);

@ -26,11 +26,16 @@ import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile; import com.arialyy.aria.util.BufferedRandomAccessFile;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
/** /**
* Created by lyy on 2017/1/18. * Created by lyy on 2017/1/18.
@ -38,10 +43,6 @@ import java.net.URL;
*/ */
final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEntity> { final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEntity> {
private final String TAG = "HttpThreadTask"; private final String TAG = "HttpThreadTask";
/**
* 2M的动态长度
*/
private final int LEN_INTERVAL = 1024 * 1024 * 2;
private boolean isOpenDynamicFile; private boolean isOpenDynamicFile;
HttpThreadTask(StateConstance constance, IDownloadListener listener, HttpThreadTask(StateConstance constance, IDownloadListener listener,
@ -52,7 +53,7 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
mReadTimeOut = manager.getDownloadConfig().getIOTimeOut(); mReadTimeOut = manager.getDownloadConfig().getIOTimeOut();
mBufSize = manager.getDownloadConfig().getBuffSize(); mBufSize = manager.getDownloadConfig().getBuffSize();
isNotNetRetry = manager.getDownloadConfig().isNotNetRetry(); isNotNetRetry = manager.getDownloadConfig().isNotNetRetry();
isOpenDynamicFile = STATE.TASK_RECORD.isOpenDynamicFile; isOpenDynamicFile = STATE.isOpenDynamicFile;
setMaxSpeed(manager.getDownloadConfig().getMaxSpeed()); setMaxSpeed(manager.getDownloadConfig().getMaxSpeed());
} }
@ -64,47 +65,44 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
mChildCurrentLocation = mConfig.START_LOCATION; mChildCurrentLocation = mConfig.START_LOCATION;
try { try {
URL url = new URL(CommonUtil.convertUrl(mConfig.URL)); URL url = new URL(CommonUtil.convertUrl(mConfig.URL));
conn = ConnectionHelp.handleConnection(url); conn = ConnectionHelp.handleConnection(url, mTaskEntity);
if (mConfig.SUPPORT_BP) { if (mConfig.SUPPORT_BP) {
ALog.d(TAG, "任务【" ALog.d(TAG,
+ mConfig.TEMP_FILE.getName() String.format("任务【%s】线程__%s__开始下载【开始位置 : %s,结束位置:%s】", mConfig.TEMP_FILE.getName(),
+ "】线程__" mConfig.THREAD_ID, mConfig.START_LOCATION, mConfig.END_LOCATION));
+ mConfig.THREAD_ID
+ "__开始下载【开始位置 : "
+ mConfig.START_LOCATION
+ ",结束位置:"
+ mConfig.END_LOCATION
+ "】");
//在头里面请求下载开始位置和结束位置 //在头里面请求下载开始位置和结束位置
conn.setRequestProperty("Range", conn.setRequestProperty("Range",
"bytes=" + mConfig.START_LOCATION + "-" + (mConfig.END_LOCATION - 1)); String.format("bytes=%s-%s", mConfig.START_LOCATION, (mConfig.END_LOCATION - 1)));
} else { } else {
ALog.w(TAG, "该下载不支持断点"); ALog.w(TAG, "该下载不支持断点");
} }
conn = ConnectionHelp.setConnectParam(mConfig.TASK_ENTITY, conn); conn = ConnectionHelp.setConnectParam(mConfig.TASK_ENTITY, conn);
conn.setConnectTimeout(mConnectTimeOut); conn.setConnectTimeout(mConnectTimeOut);
conn.setReadTimeout(mReadTimeOut); //设置读取流的等待时间,必须设置该参数 conn.setReadTimeout(mReadTimeOut); //设置读取流的等待时间,必须设置该参数
conn.connect();
is = new BufferedInputStream(ConnectionHelp.convertInputStream(conn)); is = new BufferedInputStream(ConnectionHelp.convertInputStream(conn));
//创建可设置位置的文件 if (isOpenDynamicFile) {
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize); readDynamicFile(is);
//设置每条线程写入文件的位置
file.seek(mConfig.START_LOCATION);
if (mTaskEntity.isChunked()) {
readChunk(is, file);
} else { } else {
readNormal(is, file); //创建可设置位置的文件
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize);
//设置每条线程写入文件的位置
file.seek(mConfig.START_LOCATION);
if (mTaskEntity.isChunked()) {
readChunk(is, file);
} else {
readNormal(is, file);
}
} }
if (STATE.isCancel || STATE.isStop) { if (isBreak()) {
return; return;
} }
handleComplete(); handleComplete();
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
fail(mChildCurrentLocation, "下载链接异常", e); fail(mChildCurrentLocation, "下载链接异常", e);
} catch (IOException e) { } catch (IOException e) {
fail(mChildCurrentLocation, "下载失败【" + mConfig.URL + "】", e); fail(mChildCurrentLocation, String.format("下载失败【%s】", mConfig.URL), e);
} catch (Exception e) { } catch (Exception e) {
fail(mChildCurrentLocation, "获取流失败", e); fail(mChildCurrentLocation, "获取流失败", e);
} finally { } finally {
@ -124,6 +122,52 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
} }
} }
/**
* 动态长度文件读取方式
*/
private void readDynamicFile(InputStream is) {
FileOutputStream fos = null;
FileChannel foc = null;
ReadableByteChannel fic = null;
try {
int len;
fos = new FileOutputStream(mConfig.TEMP_FILE, true);
foc = fos.getChannel();
fic = Channels.newChannel(is);
ByteBuffer bf = ByteBuffer.allocate(mBufSize);
while ((len = fic.read(bf)) != -1) {
if (isBreak()) {
break;
}
if (mSleepTime > 0) {
Thread.sleep(mSleepTime);
}
bf.flip();
foc.write(bf);
bf.compact();
progress(len);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
fail(mChildCurrentLocation, String.format("下载失败【%s】", mConfig.URL), e);
} finally {
try {
if (fos != null) {
fos.close();
}
if (foc != null) {
foc.close();
}
if (fic != null) {
fic.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/** /**
* 读取chunk模式的文件流 * 读取chunk模式的文件流
* *
@ -142,17 +186,12 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
byte[] buffer = new byte[mBufSize]; byte[] buffer = new byte[mBufSize];
int len; int len;
while ((len = is.read(buffer)) != -1) { while ((len = is.read(buffer)) != -1) {
if (STATE.isCancel || STATE.isStop) { if (isBreak()) {
break; break;
} }
if (mSleepTime > 0) { if (mSleepTime > 0) {
Thread.sleep(mSleepTime); Thread.sleep(mSleepTime);
} }
if (isOpenDynamicFile) {
file.setLength(
STATE.CURRENT_LOCATION + LEN_INTERVAL < mEntity.getFileSize() ? STATE.CURRENT_LOCATION
+ LEN_INTERVAL : mEntity.getFileSize());
}
file.write(buffer, 0, len); file.write(buffer, 0, len);
progress(len); progress(len);
} }
@ -160,15 +199,14 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
/** /**
* 处理完成配置文件的更新或事件回调 * 处理完成配置文件的更新或事件回调
*
* @throws IOException
*/ */
private void handleComplete() throws IOException { private void handleComplete() {
//支持断点的处理 //支持断点的处理
if (mConfig.SUPPORT_BP) { if (mConfig.SUPPORT_BP) {
if (mChildCurrentLocation == mConfig.END_LOCATION) { if (mChildCurrentLocation == mConfig.END_LOCATION) {
ALog.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕"); ALog.i(TAG,
writeConfig(true, 1); String.format("任务【%s】线程__%s__下载完毕", mConfig.TEMP_FILE.getName(), mConfig.THREAD_ID));
writeConfig(true, mConfig.END_LOCATION);
STATE.COMPLETE_THREAD_NUM++; STATE.COMPLETE_THREAD_NUM++;
if (STATE.isComplete()) { if (STATE.isComplete()) {
STATE.TASK_RECORD.deleteData(); STATE.TASK_RECORD.deleteData();
@ -188,8 +226,4 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
mListener.onComplete(); mListener.onComplete();
} }
} }
@Override protected String getTaskType() {
return "HTTP_DOWNLOAD";
}
} }

@ -50,6 +50,9 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
*/ */
private String convertFileSize; private String convertFileSize;
/**
* 任务状态{@link IEntity}
*/
private int state = STATE_WAIT; private int state = STATE_WAIT;
/** /**
* 当前下载进度 * 当前下载进度

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.inf;
import android.support.annotation.CheckResult;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.ICmd; import com.arialyy.aria.core.command.ICmd;
@ -34,7 +35,7 @@ import java.util.List;
*/ */
public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity> public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
implements ITarget<TARGET> { implements ITarget<TARGET> {
protected String TAG = ""; protected String TAG ;
protected ENTITY mEntity; protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity; protected TASK_ENTITY mTaskEntity;
protected String mTargetName; protected String mTargetName;
@ -48,6 +49,7 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
* 注意如果在后续方法调用链中没有调用 {@link #start()}{@link #stop()}{@link #cancel()}{@link #resume()} * 注意如果在后续方法调用链中没有调用 {@link #start()}{@link #stop()}{@link #cancel()}{@link #resume()}
* 等操作任务的方法那么你需要调用{@link #save()}才能将修改保存到数据库 * 等操作任务的方法那么你需要调用{@link #save()}才能将修改保存到数据库
*/ */
@CheckResult(suggest = "after use #start()、#stop()、#cancel()、#resume()、#save()?")
public TARGET resetState() { public TARGET resetState() {
mTaskEntity.getEntity().setState(IEntity.STATE_WAIT); mTaskEntity.getEntity().setState(IEntity.STATE_WAIT);
mTaskEntity.setRefreshInfo(true); mTaskEntity.setRefreshInfo(true);
@ -102,12 +104,13 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
* *
* @param str 扩展数据 * @param str 扩展数据
*/ */
@CheckResult(suggest = "after use #start()、#stop()、#cancel()、#resume()、#save()?")
public TARGET setExtendField(String str) { public TARGET setExtendField(String str) {
if (TextUtils.isEmpty(str)) return (TARGET) this; if (TextUtils.isEmpty(str)) return (TARGET) this;
if (TextUtils.isEmpty(mEntity.getStr()) || !mEntity.getStr().equals(str)) { if (TextUtils.isEmpty(mEntity.getStr()) || !mEntity.getStr().equals(str)) {
mEntity.setStr(str); mEntity.setStr(str);
} else { } else {
ALog.e(TAG, "设置扩展字段失败,扩展字段为null"); ALog.e(TAG, "设置扩展字段失败,扩展字段为一致");
} }
return (TARGET) this; return (TARGET) this;

@ -19,6 +19,7 @@ import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.annotation.Ignore; import com.arialyy.aria.orm.annotation.Ignore;
import java.net.Proxy;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -124,6 +125,8 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
*/ */
private int code; private int code;
@Ignore private Proxy proxy;
public abstract ENTITY getEntity(); public abstract ENTITY getEntity();
/** /**
@ -135,6 +138,14 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
return getEntity().getState(); return getEntity().getState();
} }
public Proxy getProxy() {
return proxy;
}
public void setProxy(Proxy proxy) {
this.proxy = proxy;
}
public abstract String getKey(); public abstract String getKey();
public abstract void setKey(String key); public abstract void setKey(String key);

@ -15,6 +15,8 @@
*/ */
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.inf;
import android.support.annotation.CheckResult;
/** /**
* Created by laoyuyu on 2018/3/9. * Created by laoyuyu on 2018/3/9.
*/ */
@ -22,6 +24,7 @@ public interface IFtpTarget<TARGET extends ITarget> {
/** /**
* 设置字符编码 * 设置字符编码
*/ */
@CheckResult
TARGET charSet(String charSet); TARGET charSet(String charSet);
/** /**
@ -30,6 +33,7 @@ public interface IFtpTarget<TARGET extends ITarget> {
* @param userName ftp用户名 * @param userName ftp用户名
* @param password ftp用户密码 * @param password ftp用户密码
*/ */
@CheckResult
TARGET login(String userName, String password); TARGET login(String userName, String password);
/** /**
@ -39,5 +43,6 @@ public interface IFtpTarget<TARGET extends ITarget> {
* @param password ftp用户密码 * @param password ftp用户密码
* @param account ftp账号 * @param account ftp账号
*/ */
@CheckResult
TARGET login(String userName, String password, String account); TARGET login(String userName, String password, String account);
} }

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.inf;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
@ -33,6 +34,7 @@ public interface IHttpHeaderTarget<TARGET extends ITarget> {
* @param key header对应的key * @param key header对应的key
* @param value header对应的value * @param value header对应的value
*/ */
@CheckResult
TARGET addHeader(@NonNull String key, @NonNull String value); TARGET addHeader(@NonNull String key, @NonNull String value);
/** /**
@ -41,6 +43,7 @@ public interface IHttpHeaderTarget<TARGET extends ITarget> {
* *
* @param headers 一组http header数据 * @param headers 一组http header数据
*/ */
@CheckResult
TARGET addHeaders(Map<String, String> headers); TARGET addHeaders(Map<String, String> headers);
/** /**
@ -48,5 +51,6 @@ public interface IHttpHeaderTarget<TARGET extends ITarget> {
* *
* @param requestEnum {@link RequestEnum} * @param requestEnum {@link RequestEnum}
*/ */
@CheckResult
TARGET setRequestMode(RequestEnum requestEnum); TARGET setRequestMode(RequestEnum requestEnum);
} }

@ -23,6 +23,7 @@ import com.arialyy.aria.core.download.wrapper.DGEWrapper;
import com.arialyy.aria.core.download.wrapper.DGTEWrapper; import com.arialyy.aria.core.download.wrapper.DGTEWrapper;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -156,10 +157,12 @@ class DGTEFactory implements IGTEFactory<DownloadGroupEntity, DownloadGroupTaskE
private List<DownloadEntity> createSubTask(String groupName, List<String> urls) { private List<DownloadEntity> createSubTask(String groupName, List<String> urls) {
List<DownloadEntity> list = new ArrayList<>(); List<DownloadEntity> list = new ArrayList<>();
for (int i = 0, len = urls.size(); i < len; i++) { for (int i = 0, len = urls.size(); i < len; i++) {
String url = urls.get(i);
DownloadEntity entity = new DownloadEntity(); DownloadEntity entity = new DownloadEntity();
entity.setUrl(urls.get(i)); entity.setUrl(url);
entity.setDownloadPath(groupName + "_" + i); entity.setDownloadPath(groupName + "_" + i);
entity.setFileName(groupName + "_" + i); int lastIndex = url.lastIndexOf(File.separator);
entity.setFileName(url.substring(lastIndex + 1, url.length()));
entity.setGroupName(groupName); entity.setGroupName(groupName);
entity.setGroupChild(true); entity.setGroupChild(true);
list.add(entity); list.add(entity);

@ -165,7 +165,7 @@ public class TEManager {
/** /**
* 从缓存中获取单任务实体如果任务实体不存在则创建任务实体 * 从缓存中获取单任务实体如果任务实体不存在则创建任务实体
* *
* @return 创建失败返回null * @return 创建失败返回null成功返回{@link DownloadTaskEntity}或者{@link UploadTaskEntity}
*/ */
public <TE extends AbsTaskEntity> TE getTEntity(Class<TE> clazz, String key) { public <TE extends AbsTaskEntity> TE getTEntity(Class<TE> clazz, String key) {
final Lock lock = this.lock; final Lock lock = this.lock;
@ -185,7 +185,7 @@ public class TEManager {
/** /**
* 从缓存中获取FTP文件夹任务实体如果任务实体不存在则创建任务实体 * 从缓存中获取FTP文件夹任务实体如果任务实体不存在则创建任务实体
* *
* @return 创建失败返回null * @return 创建失败返回null成功返回{@link DownloadTaskEntity}
*/ */
public <TE extends AbsTaskEntity> TE getFDTEntity(Class<TE> clazz, String key) { public <TE extends AbsTaskEntity> TE getFDTEntity(Class<TE> clazz, String key) {
final Lock lock = this.lock; final Lock lock = this.lock;
@ -204,9 +204,10 @@ public class TEManager {
/** /**
* 从缓存中获取HTTP任务组的任务实体如果任务实体不存在则创建任务实体 * 从缓存中获取HTTP任务组的任务实体如果任务实体不存在则创建任务实体
* 获取{}
* *
* @param urls HTTP任务组的子任务下载地址列表 * @param urls HTTP任务组的子任务下载地址列表
* @return 地址列表为null或创建实体失败返回null * @return 地址列表为null或创建实体失败返回null成功返回{@link DownloadGroupTaskEntity}
*/ */
public <TE extends AbsTaskEntity> TE getGTEntity(Class<TE> clazz, List<String> urls) { public <TE extends AbsTaskEntity> TE getGTEntity(Class<TE> clazz, List<String> urls) {
if (urls == null || urls.isEmpty()) { if (urls == null || urls.isEmpty()) {

@ -46,16 +46,6 @@ abstract class AbsTaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
return mExecutePool.getTask(key) != null; return mExecutePool.getTask(key) != null;
} }
@Override public void removeAllTask() {
for (String key : mExecutePool.getAllTask().keySet()) {
TASK task = mExecutePool.getAllTask().get(key);
if (task != null) task.cancel();
}
for (String key : mCachePool.getAllTask().keySet()) {
mCachePool.removeTask(key);
}
}
/** /**
* 恢复任务 * 恢复任务
* 如果执行队列任务未满则直接启动任务 * 如果执行队列任务未满则直接启动任务
@ -165,12 +155,14 @@ abstract class AbsTaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
} }
@Override public void stopTask(TASK task) { @Override public void stopTask(TASK task) {
if (!task.isRunning()) ALog.w(TAG, "停止任务【" + task.getTaskName() + "】失败,原因:已停止"); if (!task.isRunning()) {
ALog.w(TAG, String.format("停止任务【%s】失败,原因:已停止", task.getTaskName()));
}
if (mExecutePool.removeTask(task)) { if (mExecutePool.removeTask(task)) {
task.stop(); task.stop();
} else { } else {
task.stop(); task.stop();
ALog.w(TAG, "删除任务【" + task.getTaskName() + "】失败,原因:执行队列中没有该任务"); ALog.w(TAG, String.format("删除任务【%s】失败,原因:执行队列中没有该任务", task.getTaskName()));
} }
} }
@ -178,13 +170,13 @@ abstract class AbsTaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
//TEManager.getInstance().removeTEntity(key); //TEManager.getInstance().removeTEntity(key);
TASK task = mExecutePool.getTask(key); TASK task = mExecutePool.getTask(key);
if (task != null) { if (task != null) {
ALog.d(TAG, ALog.d(TAG, String.format("从执行池删除任务【%s】%s", task.getTaskName(),
"从执行池删除任务【" + task.getTaskName() + "】" + (mExecutePool.removeTask(task) ? "成功" : "失败")); (mExecutePool.removeTask(task) ? "成功" : "失败")));
} }
task = mCachePool.getTask(key); task = mCachePool.getTask(key);
if (task != null) { if (task != null) {
ALog.d(TAG, ALog.d(TAG, String.format("从缓存池删除任务【%s】%s", task.getTaskName(),
"从缓存池删除任务【" + task.getTaskName() + "】" + (mCachePool.removeTask(task) ? "成功" : "失败")); (mCachePool.removeTask(task) ? "成功" : "失败")));
} }
} }
@ -201,7 +193,7 @@ abstract class AbsTaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
task.start(); task.start();
} else { } else {
task.stop(); task.stop();
ALog.e(TAG, "任务【" + task.getTaskName() + "】重试失败,原因:任务没有完全停止,"); ALog.e(TAG, String.format("任务【%s】重试失败,原因:任务没有完全停止", task.getTaskName()));
} }
} }

@ -52,11 +52,6 @@ public interface ITaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
*/ */
void stopAllTask(); void stopAllTask();
/**
* 删除所有任务
*/
void removeAllTask();
/** /**
* 开始任务 * 开始任务
* *

@ -17,6 +17,7 @@ package com.arialyy.aria.core.scheduler;
import android.os.CountDownTimer; import android.os.CountDownTimer;
import android.os.Message; import android.os.Message;
import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadGroupTask; import com.arialyy.aria.core.download.DownloadGroupTask;
import com.arialyy.aria.core.download.DownloadTask; import com.arialyy.aria.core.download.DownloadTask;
@ -157,7 +158,7 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
} }
/** /**
* 处理普通任务事件 * 处理普通任务和任务组的事件
*/ */
private void handleNormalEvent(TASK task, int what) { private void handleNormalEvent(TASK task, int what) {
switch (what) { switch (what) {
@ -292,7 +293,7 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
@Override public void onFinish() { @Override public void onFinish() {
AbsEntity entity = task.getTaskEntity().getEntity(); AbsEntity entity = task.getTaskEntity().getEntity();
if (entity.getFailNum() <= reTryNum) { if (entity.getFailNum() <= reTryNum) {
ALog.d(TAG, "任务【" + task.getTaskName() + "】开始重试"); ALog.d(TAG, String.format("任务【%s】开始重试", task.getTaskName()));
TASK task = mQueue.getTask(entity.getKey()); TASK task = mQueue.getTask(entity.getKey());
mQueue.reTryStart(task); mQueue.reTryStart(task);
} else { } else {
@ -311,7 +312,9 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
private void startNextTask() { private void startNextTask() {
TASK newTask = mQueue.getNextTask(); TASK newTask = mQueue.getNextTask();
if (newTask == null) { if (newTask == null) {
ALog.i(TAG, "没有下一任务"); if (mQueue.getCurrentExePoolNum() == 0) {
ALog.i(TAG, "没有下一任务");
}
return; return;
} }
if (newTask.getState() == IEntity.STATE_WAIT) { if (newTask.getState() == IEntity.STATE_WAIT) {

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.upload; package com.arialyy.aria.core.upload;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.manager.TEManager; import com.arialyy.aria.core.manager.TEManager;
@ -44,6 +45,7 @@ abstract class BaseNormalTarget<TARGET extends AbsUploadTarget>
* *
* @param uploadUrl 上传路径 * @param uploadUrl 上传路径
*/ */
@CheckResult
public TARGET setUploadUrl(@NonNull String uploadUrl) { public TARGET setUploadUrl(@NonNull String uploadUrl) {
mTempUrl = uploadUrl; mTempUrl = uploadUrl;
return (TARGET) this; return (TARGET) this;

@ -144,15 +144,16 @@ class BaseUListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<
mEntity.setState(state); mEntity.setState(state);
mEntity.setComplete(state == IEntity.STATE_COMPLETE); mEntity.setComplete(state == IEntity.STATE_COMPLETE);
if (state == IEntity.STATE_CANCEL) { if (state == IEntity.STATE_CANCEL) {
if (mEntity instanceof AbsNormalEntity) { if (mEntity instanceof UploadEntity) {
TaskRecord record = TaskRecord record =
DbEntity.findFirst(TaskRecord.class, "TaskRecord.filePath=?", mTaskEntity.getKey()); DbEntity.findFirst(TaskRecord.class, "TaskRecord.filePath=?", mTaskEntity.getKey());
if (record != null) { if (record != null) {
CommonUtil.delTaskRecord(record, mTaskEntity.isRemoveFile(), (AbsNormalEntity) mEntity); CommonUtil.delTaskRecord(record, mTaskEntity.isRemoveFile(), (UploadEntity) mEntity);
} }
} else if (mEntity instanceof AbsGroupEntity) {
CommonUtil.delGroupTaskRecord(mTaskEntity.isRemoveFile(), ((AbsGroupEntity) mEntity));
} }
//else if (mEntity instanceof AbsGroupEntity) {
// CommonUtil.delGroupTaskRecord(mTaskEntity.isRemoveFile(), ((AbsGroupEntity) mEntity));
//}
return; return;
} else if (mEntity.isComplete()) { } else if (mEntity.isComplete()) {
mEntity.setCompleteTime(System.currentTimeMillis()); mEntity.setCompleteTime(System.currentTimeMillis());

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.upload; package com.arialyy.aria.core.upload;
import android.support.annotation.CheckResult;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.normal.NormalCmdFactory; import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.delegate.FtpDelegate; import com.arialyy.aria.core.delegate.FtpDelegate;
@ -69,6 +70,7 @@ public class FtpUploadTarget extends BaseNormalTarget<FtpUploadTarget>
return true; return true;
} }
@CheckResult
@Override public FtpUploadTarget charSet(String charSet) { @Override public FtpUploadTarget charSet(String charSet) {
return mDelegate.charSet(charSet); return mDelegate.charSet(charSet);
} }

@ -15,12 +15,13 @@
*/ */
package com.arialyy.aria.core.upload; package com.arialyy.aria.core.upload;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.ICmd; import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory; import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.ProxyHelper; import com.arialyy.aria.core.common.ProxyHelper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.AbsReceiver; import com.arialyy.aria.core.inf.AbsReceiver;
import com.arialyy.aria.core.scheduler.UploadSchedulers; import com.arialyy.aria.core.scheduler.UploadSchedulers;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
@ -41,6 +42,7 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
* *
* @param filePath 文件路径 * @param filePath 文件路径
*/ */
@CheckResult
public UploadTarget load(@NonNull String filePath) { public UploadTarget load(@NonNull String filePath) {
CheckUtil.checkUploadPath(filePath); CheckUtil.checkUploadPath(filePath);
return new UploadTarget(filePath, targetName); return new UploadTarget(filePath, targetName);
@ -51,6 +53,7 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
* *
* @param filePath 文件路径 * @param filePath 文件路径
*/ */
@CheckResult
public FtpUploadTarget loadFtp(@NonNull String filePath) { public FtpUploadTarget loadFtp(@NonNull String filePath) {
CheckUtil.checkUploadPath(filePath); CheckUtil.checkUploadPath(filePath);
return new FtpUploadTarget(filePath, targetName); return new FtpUploadTarget(filePath, targetName);
@ -58,8 +61,12 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
/** /**
* 通过上传路径获取上传实体 * 通过上传路径获取上传实体
* 如果任务不存在方便null
*/ */
public UploadEntity getUploadEntity(String filePath) { public UploadEntity getUploadEntity(String filePath) {
if (TextUtils.isEmpty(filePath)) {
return null;
}
return DbEntity.findFirst(UploadEntity.class, "filePath=?", filePath); return DbEntity.findFirst(UploadEntity.class, "filePath=?", filePath);
} }
@ -95,7 +102,6 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
"isGroupChild=? and isComplete=?", "false", "true"); "isGroupChild=? and isComplete=?", "false", "true");
} }
@Override public void stopAllTask() { @Override public void stopAllTask() {
AriaManager.getInstance(AriaManager.APP) AriaManager.getInstance(AriaManager.APP)
.setCmd(NormalCmdFactory.getInstance() .setCmd(NormalCmdFactory.getInstance()
@ -129,13 +135,12 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
/** /**
* 将当前类注册到Aria * 将当前类注册到Aria
*/ */
public UploadReceiver register() { public void register() {
String className = obj.getClass().getName(); String className = obj.getClass().getName();
Set<String> cCounter = ProxyHelper.getInstance().uploadCounter; Set<String> cCounter = ProxyHelper.getInstance().uploadCounter;
if (cCounter != null && cCounter.contains(className)) { if (cCounter != null && cCounter.contains(className)) {
UploadSchedulers.getInstance().register(obj); UploadSchedulers.getInstance().register(obj);
} }
return this;
} }
/** /**

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.upload; package com.arialyy.aria.core.upload;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.delegate.HttpHeaderDelegate; import com.arialyy.aria.core.delegate.HttpHeaderDelegate;
@ -47,6 +48,7 @@ public class UploadTarget extends BaseNormalTarget<UploadTarget>
/** /**
* 设置userAgent * 设置userAgent
*/ */
@CheckResult
public UploadTarget setUserAngent(@NonNull String userAgent) { public UploadTarget setUserAngent(@NonNull String userAgent) {
mTaskEntity.setUserAgent(userAgent); mTaskEntity.setUserAgent(userAgent);
return this; return this;
@ -57,6 +59,7 @@ public class UploadTarget extends BaseNormalTarget<UploadTarget>
* *
* @param attachment 附件key * @param attachment 附件key
*/ */
@CheckResult
public UploadTarget setAttachment(@NonNull String attachment) { public UploadTarget setAttachment(@NonNull String attachment) {
mTaskEntity.setAttachment(attachment); mTaskEntity.setAttachment(attachment);
return this; return this;
@ -67,19 +70,23 @@ public class UploadTarget extends BaseNormalTarget<UploadTarget>
* *
* @param contentType tipmultipart/form-data * @param contentType tipmultipart/form-data
*/ */
@CheckResult
public UploadTarget setContentType(String contentType) { public UploadTarget setContentType(String contentType) {
mTaskEntity.setContentType(contentType); mTaskEntity.setContentType(contentType);
return this; return this;
} }
@CheckResult
@Override public UploadTarget addHeader(@NonNull String key, @NonNull String value) { @Override public UploadTarget addHeader(@NonNull String key, @NonNull String value) {
return mDelegate.addHeader(key, value); return mDelegate.addHeader(key, value);
} }
@CheckResult
@Override public UploadTarget addHeaders(Map<String, String> headers) { @Override public UploadTarget addHeaders(Map<String, String> headers) {
return mDelegate.addHeaders(headers); return mDelegate.addHeaders(headers);
} }
@CheckResult
@Override public UploadTarget setRequestMode(RequestEnum requestEnum) { @Override public UploadTarget setRequestMode(RequestEnum requestEnum) {
return mDelegate.setRequestMode(requestEnum); return mDelegate.setRequestMode(requestEnum);
} }

@ -54,15 +54,9 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
FTPClient client = null; FTPClient client = null;
BufferedRandomAccessFile file = null; BufferedRandomAccessFile file = null;
try { try {
ALog.d(TAG, "任务【" ALog.d(TAG,
+ mConfig.TEMP_FILE.getName() String.format("任务【%s】线程__%s__开始上传【开始位置 : %s,结束位置:%s】", mConfig.TEMP_FILE.getName(),
+ "】线程__" mConfig.THREAD_ID, mConfig.START_LOCATION, mConfig.END_LOCATION));
+ mConfig.THREAD_ID
+ "__开始上传【开始位置 : "
+ mConfig.START_LOCATION
+ ",结束位置:"
+ mConfig.END_LOCATION
+ "】");
client = createClient(); client = createClient();
if (client == null) return; if (client == null) return;
initPath(); initPath();
@ -82,9 +76,12 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
file.seek(mConfig.START_LOCATION); file.seek(mConfig.START_LOCATION);
} }
upload(client, file); upload(client, file);
if (STATE.isCancel || STATE.isStop) return; if (isBreak()) {
ALog.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__上传完毕"); return;
writeConfig(true, 1); }
ALog.i(TAG,
String.format("任务【%s】线程__%s__上传完毕", mConfig.TEMP_FILE.getName(), mConfig.THREAD_ID));
writeConfig(true, mConfig.END_LOCATION);
STATE.COMPLETE_THREAD_NUM++; STATE.COMPLETE_THREAD_NUM++;
if (STATE.isComplete()) { if (STATE.isComplete()) {
STATE.TASK_RECORD.deleteData(); STATE.TASK_RECORD.deleteData();
@ -96,7 +93,7 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
mListener.onFail(false); mListener.onFail(false);
} }
} catch (IOException e) { } catch (IOException e) {
fail(mChildCurrentLocation, "上传失败【" + mConfig.URL + "】", e); fail(mChildCurrentLocation, String.format("上传失败【%s】", mConfig.URL), e);
} catch (Exception e) { } catch (Exception e) {
fail(mChildCurrentLocation, "获取流失败", e); fail(mChildCurrentLocation, "获取流失败", e);
} finally { } finally {
@ -125,13 +122,13 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
throws IOException { throws IOException {
try { try {
ALog.d(TAG, "remotePath【" + remotePath + "】"); ALog.d(TAG, String.format("remotePath【%s】", remotePath));
client.storeFile(remotePath, new FtpFISAdapter(bis), new OnFtpInputStreamListener() { client.storeFile(remotePath, new FtpFISAdapter(bis), new OnFtpInputStreamListener() {
boolean isStoped = false; boolean isStoped = false;
@Override public void onFtpInputStream(FTPClient client, long totalBytesTransferred, @Override public void onFtpInputStream(FTPClient client, long totalBytesTransferred,
int bytesTransferred, long streamSize) { int bytesTransferred, long streamSize) {
if ((STATE.isCancel || STATE.isStop) && !isStoped) { if (isBreak() && !isStoped) {
try { try {
isStoped = true; isStoped = true;
client.abor(); client.abor();
@ -153,7 +150,8 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
int reply = client.getReplyCode(); int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) { if (!FTPReply.isPositiveCompletion(reply)) {
if (reply != FTPReply.TRANSFER_ABORTED) { if (reply != FTPReply.TRANSFER_ABORTED) {
fail(mChildCurrentLocation, "上传文件错误,错误码为:" + reply + ",msg:" + client.getReplyString(), fail(mChildCurrentLocation,
String.format("上传文件错误,错误码为:%s,msg:%s", reply, client.getReplyString()),
null); null);
} }
if (client.isConnected()) { if (client.isConnected()) {
@ -161,8 +159,4 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
} }
} }
} }
@Override protected String getTaskType() {
return "FTP_UPLOAD";
}
} }

@ -62,7 +62,7 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
@Override public void run() { @Override public void run() {
File uploadFile = new File(mEntity.getFilePath()); File uploadFile = new File(mEntity.getFilePath());
if (!uploadFile.exists()) { if (!uploadFile.exists()) {
ALog.e(TAG, "【" + mEntity.getFilePath() + "】,文件不存在。"); ALog.e(TAG, String.format("【%s】,文件不存在。", mEntity.getFilePath()));
fail(); fail();
return; return;
} }
@ -212,8 +212,4 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
mOutputStream.close(); mOutputStream.close();
return response.toString(); return response.toString();
} }
@Override protected String getTaskType() {
return "HTTP_UPLOAD";
}
} }

@ -48,7 +48,7 @@ abstract class AbsDelegate {
* @param type {@link DelegateWrapper} * @param type {@link DelegateWrapper}
*/ */
static void print(int type, String sql) { static void print(int type, String sql) {
if (!ALog.DEBUG) { if (ALog.DEBUG) {
return; return;
} }
String str = ""; String str = "";

@ -30,6 +30,7 @@ import java.lang.reflect.Field;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -217,8 +218,8 @@ class DelegateFind extends AbsDelegate {
} }
List<T> wrappers = new ArrayList<>(); List<T> wrappers = new ArrayList<>();
Map<Object, P> tempParent = new WeakHashMap<>(); // 所有父表元素,key为父表主键的值 Map<Object, P> tempParent = new LinkedHashMap<>(); // 所有父表元素,key为父表主键的值
Map<Object, List<C>> tempChild = new WeakHashMap<>(); // 所有的字表元素,key为父表主键的值 Map<Object, List<C>> tempChild = new LinkedHashMap<>(); // 所有的字表元素,key为父表主键的值
Object old = null; Object old = null;
while (cursor.moveToNext()) { while (cursor.moveToNext()) {

@ -117,6 +117,9 @@ public class ALog {
* 将异常信息转换为字符串 * 将异常信息转换为字符串
*/ */
public static String getExceptionString(Throwable ex) { public static String getExceptionString(Throwable ex) {
if (ex == null) {
return "";
}
StringBuilder err = new StringBuilder(); StringBuilder err = new StringBuilder();
err.append("ExceptionDetailed:\n"); err.append("ExceptionDetailed:\n");
err.append("====================Exception Info====================\n"); err.append("====================Exception Info====================\n");

@ -23,6 +23,7 @@ import android.net.Uri;
import android.os.Environment; import android.os.Environment;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Base64; import android.util.Base64;
import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.FtpUrlEntity; import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.command.ICmd; import com.arialyy.aria.core.command.ICmd;
@ -33,7 +34,6 @@ import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.TaskRecord; import com.arialyy.aria.core.common.TaskRecord;
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.AbsGroupEntity;
import com.arialyy.aria.core.inf.AbsGroupTaskEntity; import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
import com.arialyy.aria.core.inf.AbsNormalEntity; import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
@ -53,17 +53,14 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.net.URLEncoder;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -77,34 +74,55 @@ public class CommonUtil {
/** /**
* 获取某包下所有类 * 获取某包下所有类
* *
* @param packageName * @param className 过滤的类
* @return 类的完整名称 * @return 类的完整名称
*/ */
public static List<String> getClassName(Context context, String packageName) { public static List<String> getClassName(Context context, String className) {
List<String> classNameList = new ArrayList<>(); List<String> classNameList = new ArrayList<>();
try { String pPath = context.getPackageCodePath();
String pPath = context.getPackageCodePath(); File dir = new File(pPath).getParentFile();
File dir = new File(pPath).getParentFile(); String[] paths = dir.list();
if (paths == null) {
classNameList.addAll(getPkgClassName(pPath, className));
} else {
String dPath = dir.getPath(); String dPath = dir.getPath();
for (String path : dir.list()) { for (String path : dir.list()) {
String fPath = dPath + "/" + path; String fPath = dPath + "/" + path;
if (!fPath.endsWith(".apk")) { if (!fPath.endsWith(".apk")) {
continue; continue;
} }
DexFile df = new DexFile(fPath);//通过DexFile查找当前的APK中可执行文件 classNameList.addAll(getPkgClassName(fPath, className));
Enumeration<String> enumeration = df.entries();//获取df中的元素 这里包含了所有可执行的类名 该类名包含了包名+类名的方式 }
while (enumeration.hasMoreElements()) {//遍历 }
String className = enumeration.nextElement(); return classNameList;
if (className.contains(packageName)) {//在当前所有可执行的类里面查找包含有该包名的所有类 }
classNameList.add(className);
} /**
* 获取指定包名下的所有类
*
* @param path dex路径
* @param filterClass 需要过滤的类
*/
public static List<String> getPkgClassName(String path, String filterClass) {
List<String> list = new ArrayList<>();
try {
DexFile df = new DexFile(path);//通过DexFile查找当前的APK中可执行文件
Enumeration<String> enumeration = df.entries();//获取df中的元素 这里包含了所有可执行的类名 该类名包含了包名+类名的方式
while (enumeration.hasMoreElements()) {
String _className = enumeration.nextElement();
if (!_className.contains(filterClass)) {
continue;
}
if (_className.contains(filterClass)) {
list.add(_className);
} }
df.close();
} }
df.close();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
return classNameList; return list;
} }
/** /**
@ -246,53 +264,30 @@ public class CommonUtil {
* @param url 输入的url{@code String url = "ftp://z:z@dygod18.com:21211/[电影天堂www.dy2018.com]猩球崛起3:终极之战BD国英双语中英双字.mkv";} * @param url 输入的url{@code String url = "ftp://z:z@dygod18.com:21211/[电影天堂www.dy2018.com]猩球崛起3:终极之战BD国英双语中英双字.mkv";}
*/ */
public static FtpUrlEntity getFtpUrlInfo(String url) { public static FtpUrlEntity getFtpUrlInfo(String url) {
Uri uri = Uri.parse(url);
String userInfo = uri.getUserInfo(), remotePath = uri.getPath();
ALog.d(TAG,
String.format("scheme = %s, user = %s, host = %s, port = %s, path = %s", uri.getScheme(),
userInfo, uri.getHost(), uri.getPort(), remotePath));
FtpUrlEntity entity = new FtpUrlEntity(); FtpUrlEntity entity = new FtpUrlEntity();
entity.url = url; entity.url = url;
//String regex = "(\\w+)://(.*):(\\d*)/(.*)"; entity.hostName = uri.getHost();
String regex = Regular.REG_FTP_URL; entity.port = uri.getPort() == -1 ? "21" : String.valueOf(uri.getPort());
Pattern p = Pattern.compile(regex); if (!TextUtils.isEmpty(userInfo)) {
Matcher m = p.matcher(url); String[] temp = userInfo.split(":");
if (m.find() && m.groupCount() > 0) { if (temp.length == 2) {
entity.protocol = m.group(1); entity.user = temp[0];
String str = m.group(2); entity.password = temp[1];
if (str.contains("@")) {
entity.needLogin = true;
//String hostReg = "(\\w+):?(\\w+)?@(.*)";
String hostReg = Regular.REG_FTP_HOST_NAME;
Pattern hp = Pattern.compile(hostReg);
Matcher hm = hp.matcher(str);
if (hm.find() && hm.groupCount() > 0) {
entity.user = hm.group(1);
entity.password = TextUtils.isEmpty(hm.group(2)) ? "" : hm.group(2);
entity.hostName = hm.group(3);
}
} else { } else {
entity.hostName = str; entity.user = userInfo;
} }
entity.port = m.group(3);
//entity.remotePath = TextUtils.isEmpty(m.group(4)) ? "/" : "/" + m.group(4);
entity.remotePath = TextUtils.isEmpty(m.group(4)) ? "/" : m.group(4);
} }
entity.remotePath = TextUtils.isEmpty(remotePath) ? "/" : remotePath;
return entity; return entity;
} }
/**
* 通过url获取FTP文件的remotePath
*
* @return remotePath如果没有找到返回""
*/
public static String getRemotePath(String url) {
String remotePath = null;
String regex = Regular.REG_FTP_URL;
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(url);
if (m.find() && m.groupCount() > 0) {
return TextUtils.isEmpty(m.group(4)) ? "" : "/" + m.group(4);
}
ALog.w(TAG, "链接【" + url + "】没有找到remotePath");
return "";
}
/** /**
* 转换Url * 转换Url
* *
@ -300,25 +295,27 @@ public class CommonUtil {
* @return 转换后的地址 * @return 转换后的地址
*/ */
public static String convertUrl(String url) { public static String convertUrl(String url) {
if (hasDoubleCharacter(url)) { Uri uri = Uri.parse(url);
//预先处理空格,URLEncoder只会把空格转换为+ url = uri.toString();
url = url.replaceAll(" ", "%20"); //if (hasDoubleCharacter(url)) {
//匹配双字节字符(包括汉字在内) // //预先处理空格,URLEncoder只会把空格转换为+
String regex = Regular.REG_DOUBLE_CHAR_AND_SPACE; // url = url.replaceAll(" ", "%20");
Pattern p = Pattern.compile(regex); // //匹配双字节字符(包括汉字在内)
Matcher m = p.matcher(url); // String regex = Regular.REG_DOUBLE_CHAR_AND_SPACE;
Set<String> strs = new HashSet<>(); // Pattern p = Pattern.compile(regex);
while (m.find()) { // Matcher m = p.matcher(url);
strs.add(m.group()); // Set<String> strs = new HashSet<>();
} // while (m.find()) {
try { // strs.add(m.group());
for (String str : strs) { // }
url = url.replaceAll(str, URLEncoder.encode(str, "UTF-8")); // try {
} // for (String str : strs) {
} catch (UnsupportedEncodingException e) { // url = url.replaceAll(str, URLEncoder.encode(str, "UTF-8"));
e.printStackTrace(); // }
} // } catch (UnsupportedEncodingException e) {
} // e.printStackTrace();
// }
//}
return url; return url;
} }
@ -399,33 +396,34 @@ public class CommonUtil {
* @param removeFile {@code true} 不仅删除任务数据库记录还会删除已经删除完成的文件 * @param removeFile {@code true} 不仅删除任务数据库记录还会删除已经删除完成的文件
* {@code false}如果任务已经完成只删除任务数据库记录 * {@code false}如果任务已经完成只删除任务数据库记录
*/ */
public static void delGroupTaskRecord(boolean removeFile, AbsGroupEntity groupEntity) { public static void delGroupTaskRecord(boolean removeFile, DownloadGroupEntity groupEntity) {
if (groupEntity == null) { if (groupEntity == null) {
ALog.e(TAG, "删除下载任务组记录失败,任务组实体为null"); ALog.e(TAG, "删除下载任务组记录失败,任务组实体为null");
return; return;
} }
List<TaskRecord> records = DbEntity.findDatas(TaskRecord.class, List<TaskRecord> records =
groupEntity instanceof DownloadGroupEntity ? "dGroupName=?" : "uGroupName=?", DbEntity.findDatas(TaskRecord.class, "dGroupName=?", groupEntity.getGroupName());
groupEntity.getGroupName());
if (records == null || records.isEmpty()) { if (records == null || records.isEmpty()) {
ALog.w(TAG, "组任务记录删除失败,记录为null"); ALog.w(TAG, "组任务记录删除失败,记录为null");
return; } else {
for (TaskRecord tr : records) {
tr.deleteData();
}
} }
for (TaskRecord tr : records) { List<DownloadEntity> subs = groupEntity.getSubEntities();
tr.deleteData(); if (subs != null) {
for (DownloadEntity sub : subs) {
File file = new File(sub.getDownloadPath());
if (file.exists() && (removeFile || !sub.isComplete())) {
file.delete();
}
}
} }
File dir = new File(groupEntity.getDirPath()); File dir = new File(groupEntity.getDirPath());
if (removeFile) { if (dir.exists() && (removeFile || !groupEntity.isComplete())) {
if (dir.exists()) { dir.delete();
dir.delete();
}
} else {
if (!groupEntity.isComplete()) {
dir.delete();
}
} }
groupEntity.deleteData(); groupEntity.deleteData();
} }
@ -436,8 +434,7 @@ public class CommonUtil {
* @param removeFile {@code true} 不仅删除任务数据库记录还会删除已经完成的文件 * @param removeFile {@code true} 不仅删除任务数据库记录还会删除已经完成的文件
* {@code false}如果任务已经完成只删除任务数据库记录 * {@code false}如果任务已经完成只删除任务数据库记录
*/ */
public static void delTaskRecord(TaskRecord record, boolean removeFile, public static void delTaskRecord(TaskRecord record, boolean removeFile, AbsNormalEntity dEntity) {
AbsNormalEntity dEntity) {
if (dEntity == null) return; if (dEntity == null) return;
File file; File file;
if (dEntity instanceof DownloadEntity) { if (dEntity instanceof DownloadEntity) {
@ -448,16 +445,8 @@ public class CommonUtil {
ALog.w(TAG, "删除记录失败,未知类型"); ALog.w(TAG, "删除记录失败,未知类型");
return; return;
} }
if (removeFile) { if (file.exists() && (removeFile || !dEntity.isComplete())) {
if (file.exists()) { file.delete();
file.delete();
}
} else {
if (!dEntity.isComplete()) {
if (file.exists()) {
file.delete();
}
}
} }
if (record != null) { if (record != null) {
@ -889,14 +878,11 @@ public class CommonUtil {
ALog.w(TAG, "修改任务记录失败,新文件路径和旧文件路径一致"); ALog.w(TAG, "修改任务记录失败,新文件路径和旧文件路径一致");
return; return;
} }
File oldFile = new File(oldPath);
if (!oldFile.exists()) {
ALog.w(TAG, "修改任务记录失败,文件【" + oldPath + "】不存在");
return;
}
TaskRecord record = DbHelper.getTaskRecord(oldPath); TaskRecord record = DbHelper.getTaskRecord(oldPath);
if (record == null) { if (record == null) {
ALog.w(TAG, "修改任务记录失败,文件【" + oldPath + "】对应的任务记录不存在"); if (new File(oldPath).exists()) {
ALog.w(TAG, "修改任务记录失败,文件【" + oldPath + "】对应的任务记录不存在");
}
return; return;
} }
record.filePath = newPath; record.filePath = newPath;

@ -5,15 +5,6 @@ package com.arialyy.aria.util;
* 正则表达式 * 正则表达式
*/ */
public interface Regular { public interface Regular {
/**
* ftp地址
*/
String REG_FTP_URL = "(\\w+)://(.*):(\\d*)/(.*)";
/**
* ftp主机用户密码分割
*/
String REG_FTP_HOST_NAME = "(\\w+):?(\\w+)?@(.*)";
/** /**
* 获取文件名 * 获取文件名

@ -1,4 +1,13 @@
## 开发日志 ## 开发日志
+ v_3.4.2
- fix bug https://github.com/AriaLyy/Aria/issues/248
- fix bug https://github.com/AriaLyy/Aria/issues/247
- fix bug https://github.com/AriaLyy/Aria/issues/250
- 添加任务判断是否存在的api
- 添加代理api
- 修复删除所有没有进出等待的问题
- 进度有时出错的问题
- FTP添加超时处理
+ v_3.4.1 + v_3.4.1
- 移除记录配置文件,改用数据库记录任务记录 - 移除记录配置文件,改用数据库记录任务记录
- 上传配置添加io超时时间、缓存大小配置 - 上传配置添加io超时时间、缓存大小配置

@ -30,8 +30,8 @@ Aria有以下特点:
[![Download](https://api.bintray.com/packages/arialyy/maven/AriaApi/images/download.svg)](https://bintray.com/arialyy/maven/AriaApi/_latestVersion) [![Download](https://api.bintray.com/packages/arialyy/maven/AriaApi/images/download.svg)](https://bintray.com/arialyy/maven/AriaApi/_latestVersion)
[![Download](https://api.bintray.com/packages/arialyy/maven/AriaCompiler/images/download.svg)](https://bintray.com/arialyy/maven/AriaCompiler/_latestVersion) [![Download](https://api.bintray.com/packages/arialyy/maven/AriaCompiler/images/download.svg)](https://bintray.com/arialyy/maven/AriaCompiler/_latestVersion)
```java ```java
compile 'com.arialyy.aria:aria-core:3.4.1' compile 'com.arialyy.aria:aria-core:3.4.2'
annotationProcessor 'com.arialyy.aria:aria-compiler:3.4.1' annotationProcessor 'com.arialyy.aria:aria-compiler:3.4.2'
``` ```
如果出现android support,请将 `compile 'com.arialyy.aria:aria-core:<last-version>'`替换为 如果出现android support,请将 `compile 'com.arialyy.aria:aria-core:<last-version>'`替换为
``` ```
@ -99,13 +99,15 @@ protected void onCreate(Bundle savedInstanceState) {
### 版本日志 ### 版本日志
+ v_3.4.1 + v_3.4.2
- 移除记录配置文件,改用数据库记录任务记录 - fix bug https://github.com/AriaLyy/Aria/issues/248
- 上传配置添加io超时时间、缓存大小配置 - fix bug https://github.com/AriaLyy/Aria/issues/247
- 添加没有网络也会重试的开关 - fix bug https://github.com/AriaLyy/Aria/issues/250
- 修复多次删除记录的bug - 添加任务判断是否存在的api
- 文件长度现在可动态增加,详情见 https://aria.laoyuyu.me/aria_doc/start/config.html - 添加代理api
- 修复多module同时引用Aria导致打正式包出错的问题 https://github.com/AriaLyy/Aria/issues/240 - 修复删除所有没有进出等待的问题
- 进度有时出错的问题
- FTP添加超时处理
[更多版本记录](https://github.com/AriaLyy/Aria/blob/master/DEV_LOG.md) [更多版本记录](https://github.com/AriaLyy/Aria/blob/master/DEV_LOG.md)
@ -126,7 +128,7 @@ protected void onCreate(Bundle savedInstanceState) {
## 其他 ## 其他
有任何问题,可以在[issues](https://github.com/AriaLyy/Aria/issues)给我留言反馈。</br> 有任何问题,可以在[issues](https://github.com/AriaLyy/Aria/issues)给我留言反馈。</br>
在提交问题前,希望你已经查看过[wiki](https://github.com/AriaLyy/Aria/wiki)或搜索过[issues](https://github.com/AriaLyy/Aria/issues)。</br> 在提交问题前,希望你已经查看过[wiki](https://aria.laoyuyu.me/aria_doc/)或搜索过[issues](https://github.com/AriaLyy/Aria/issues)。</br>
*** ***
License License

@ -2,7 +2,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.arialyy.simple"> package="com.arialyy.simple">
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
@ -14,11 +13,13 @@
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme.NoActionBar"> android:theme="@style/AppTheme.NoActionBar">
<!--android:name=".test.TestActivity"-->
<!--android:name=".test.AnyRunActivity"-->
<!--android:name=".test.TestGroupActivity"--> <!--android:name=".test.TestGroupActivity"-->
<!--android:name=".test.AnyRunActivity"--> <!--android:name=".test.AnyRunActivity"-->
<!--android:name=".test.TestActivity"--> <!--android:name=".download.group.DownloadGroupActivity"-->
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:label="@string/app_name"> android:label="@string/app_name">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
@ -34,7 +35,7 @@
<activity android:name=".download.multi_download.MultiDownloadActivity"/> <activity android:name=".download.multi_download.MultiDownloadActivity"/>
<activity android:name=".download.HighestPriorityActivity"/> <activity android:name=".download.HighestPriorityActivity"/>
<activity android:name=".test.TestMutilTaskSysDownload"/> <activity android:name=".test.TestMutilTaskSysDownload"/>
<activity android:name=".download.group.DownloadGroupActivity"/> <!--<activity android:name=".download.group.DownloadGroupActivity"/>-->
<activity android:name=".download.FtpDownloadActivity"/> <activity android:name=".download.FtpDownloadActivity"/>
<activity android:name=".download.group.FTPDirDownloadActivity"/> <activity android:name=".download.group.FTPDirDownloadActivity"/>
<activity android:name=".upload.HttpUploadActivity"/> <activity android:name=".upload.HttpUploadActivity"/>

@ -11,21 +11,21 @@
<!--注意,修改该配置文件中的属性会覆盖代码中所设置的属性--> <!--注意,修改该配置文件中的属性会覆盖代码中所设置的属性-->
<download> <download>
<!--是否开启动态文件,开启动态文件后初始化时将不占用磁盘空间,下载多少byte,占多少空间,效果见chrome的下载。-->
<!--注意:
1、使用该功能,将自动关闭多线程下载;
2、对于已经采用了多线程的任务,依然采用原来的下载方式;
3、原本参数是true,任务没下载完成,就参数改为false,那么没下载完成的任务还是会按照参数修改前的方式下载;只有新任务才会根据参数调用不同的下载方式。-->
<openDynamicFile value="true"/>
<!--断网的时候是否重试,true:断网也重试;false:断网不重试,直接走失败的回调--> <!--断网的时候是否重试,true:断网也重试;false:断网不重试,直接走失败的回调-->
<notNetRetry value="true"/> <notNetRetry value="true"/>
<!--设置下载线程,线程下载数改变后,新的下载任务才会生效,如果任务大小小于1m,该设置也不会生效--> <!--设置下载线程数,下载线程数不能小于1
<threadNum value="3"/> 注意:
1、线程下载数改变后,新的下载任务才会生效;
2、如果任务大小小于1m,该设置不会生效;
3、从3.4.1开始,如果线程数为1,文件初始化时将不再预占用对应长度的空间,下载多少byte,则占多大的空间;
对于采用多线程的任务或旧任务,依然采用原来的文件空间占用方式;
-->
<threadNum value="1"/>
<!--设置下载队列最大任务数, 默认为2--> <!--设置下载队列最大任务数, 默认为2-->
<maxTaskNum value="2"/> <maxTaskNum value="1"/>
<!--设置下载失败,重试次数,默认为10--> <!--设置下载失败,重试次数,默认为10-->
<reTryNum value="2"/> <reTryNum value="2"/>

@ -37,11 +37,7 @@ import java.io.File;
public class FtpDownloadActivity extends BaseActivity<ActivityFtpDownloadBinding> { public class FtpDownloadActivity extends BaseActivity<ActivityFtpDownloadBinding> {
//private final String URL = "ftp://192.168.1.9:21/下载/AriaPrj.zip"; //private final String URL = "ftp://192.168.1.9:21/下载/AriaPrj.zip";
//private final String URL = "ftp://182.92.180.213:21/video/572fed5c2ad48_1024.jpg"; //private final String URL = "ftp://182.92.180.213:21/video/572fed5c2ad48_1024.jpg";
<<<<<<< HEAD
private final String URL = "ftp://182.92.180.213:21/DATA/20180205/rar/1111.rar"; private final String URL = "ftp://182.92.180.213:21/DATA/20180205/rar/1111.rar";
=======
private final String URL = "ftp://192.168.1.7:21/download//AriaPrj.zip";
>>>>>>> v_3.4
//private final String URL = "ftp://d:d@dygodj8.com:12311/咖啡风暴HD大陆公映意语中字[飘花www.piaohua.com].mp4"; //private final String URL = "ftp://d:d@dygodj8.com:12311/咖啡风暴HD大陆公映意语中字[飘花www.piaohua.com].mp4";
@Override protected void init(Bundle savedInstanceState) { @Override protected void init(Bundle savedInstanceState) {
@ -64,18 +60,13 @@ public class FtpDownloadActivity extends BaseActivity<ActivityFtpDownloadBinding
switch (view.getId()) { switch (view.getId()) {
case R.id.start: case R.id.start:
Aria.download(this).loadFtp(URL, true) Aria.download(this).loadFtp(URL, true)
<<<<<<< HEAD
.login("sxf", "B34VdGsJ") .login("sxf", "B34VdGsJ")
//.login("lao", "123456") //.login("lao", "123456")
.setDownloadPath("/mnt/sdcard/").start();
=======
//.login("sxf", "B34VdGsJ")
.login("lao", "123456") .login("lao", "123456")
.setFilePath("/mnt/sdcard/").start(); .setFilePath("/mnt/sdcard/").start();
>>>>>>> v_3.4
break; break;
case R.id.stop: case R.id.stop:
Aria.download(this).loadFtp(URL).stop(); Aria.download(this).loadFtp(URL);
break; break;
case R.id.cancel: case R.id.cancel:
Aria.download(this).loadFtp(URL).cancel(); Aria.download(this).loadFtp(URL).cancel();

@ -49,8 +49,9 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
//"http://58.210.9.131/tpk/sipgt//TDLYZTGH.tpk"; //chunked 下载 //"http://58.210.9.131/tpk/sipgt//TDLYZTGH.tpk"; //chunked 下载
//"https://static.donguo.me//video/ip/course/pfys_1.mp4"; //"https://static.donguo.me//video/ip/course/pfys_1.mp4";
//"https://www.baidu.com/link?url=_LFCuTPtnzFxVJByJ504QymRywIA1Z_T5xUxe9ZLuxcGM0C_RcdpWyB1eGjbJC-e5wv5wAKM4WmLMAS5KeF6EZJHB8Va3YqZUiaErqK_pxm&wd=&eqid=e8583fe70002d126000000065a99f864"; //"https://www.baidu.com/link?url=_LFCuTPtnzFxVJByJ504QymRywIA1Z_T5xUxe9ZLuxcGM0C_RcdpWyB1eGjbJC-e5wv5wAKM4WmLMAS5KeF6EZJHB8Va3YqZUiaErqK_pxm&wd=&eqid=e8583fe70002d126000000065a99f864";
"https://d.pcs.baidu.com/file/a02c89a2d479d4fd2756f3313d42491d?fid=4232431903-250528-1114369760340736&dstime=1525491372&rt=sh&sign=FDtAERVY-DCb740ccc5511e5e8fedcff06b081203-3C13vkOkuk4TqXvVYW05zj1K0ao%3D&expires=8h&chkv=1&chkbd=0&chkpc=et&dp-logid=8651730921842106225&dp-callid=0&r=165533013"; //"https://d.pcs.baidu.com/file/a02c89a2d479d4fd2756f3313d42491d?fid=4232431903-250528-1114369760340736&dstime=1525491372&rt=sh&sign=FDtAERVY-DCb740ccc5511e5e8fedcff06b081203-3C13vkOkuk4TqXvVYW05zj1K0ao%3D&expires=8h&chkv=1&chkbd=0&chkpc=et&dp-logid=8651730921842106225&dp-callid=0&r=165533013";
//"http://apk500.bce.baidu-mgame.com/game/67000/67734/20170622040827_oem_5502845.apk?r=1";
"https://dl.genymotion.com/releases/genymotion-2.12.1/genymotion-2.12.1-vbox.exe";
@Bind(R.id.start) Button mStart; @Bind(R.id.start) Button mStart;
@Bind(R.id.stop) Button mStop; @Bind(R.id.stop) Button mStop;
@Bind(R.id.cancel) Button mCancel; @Bind(R.id.cancel) Button mCancel;
@ -238,8 +239,8 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
//.addHeader("Accept-Encoding", "gzip, deflate") //.addHeader("Accept-Encoding", "gzip, deflate")
//.addHeader("DNT", "1") //.addHeader("DNT", "1")
//.addHeader("Cookie", "BAIDUID=648E5FF020CC69E8DD6F492D1068AAA9:FG=1; BIDUPSID=648E5FF020CC69E8DD6F492D1068AAA9; PSTM=1519099573; BD_UPN=12314753; locale=zh; BDSVRTM=0") //.addHeader("Cookie", "BAIDUID=648E5FF020CC69E8DD6F492D1068AAA9:FG=1; BIDUPSID=648E5FF020CC69E8DD6F492D1068AAA9; PSTM=1519099573; BD_UPN=12314753; locale=zh; BDSVRTM=0")
.useServerFileName(true) //.useServerFileName(true)
.setRequestMode(RequestEnum.GET) //.setRequestMode(RequestEnum.GET)
.setFilePath(Environment.getExternalStorageDirectory().getPath() + "/ggsg3.apk") .setFilePath(Environment.getExternalStorageDirectory().getPath() + "/ggsg3.apk")
//.resetState() //.resetState()
.start(); .start();

@ -84,7 +84,7 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
.setDirPath( .setDirPath(
Environment.getExternalStorageDirectory().getPath() + "/Download/group_test_3") Environment.getExternalStorageDirectory().getPath() + "/Download/group_test_3")
.setGroupAlias("任务组测试") .setGroupAlias("任务组测试")
.setSubFileName(getModule(GroupModule.class).getSubName()) //.setSubFileName(getModule(GroupModule.class).getSubName())
//.setFileSize(32895492) //.setFileSize(32895492)
.start(); .start();
break; break;
@ -92,7 +92,8 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
Aria.download(this).load(mUrls).stop(); Aria.download(this).load(mUrls).stop();
break; break;
case R.id.cancel: case R.id.cancel:
Aria.download(this).load(mUrls).cancel(true); //Aria.download(this).load(mUrls).cancel(true);
Aria.download(this).removeAllTask(true);
//mUrls = getModule(GroupModule.class).getUrls1(); //mUrls = getModule(GroupModule.class).getUrls1();
//Aria.download(this) //Aria.download(this)
// .load(mUrls) // .load(mUrls)

@ -32,7 +32,7 @@ public class GroupModule extends BaseModule {
public List<String> getUrls() { public List<String> getUrls() {
List<String> urls = new ArrayList<>(); List<String> urls = new ArrayList<>();
String[] str = getContext().getResources().getStringArray(R.array.group_urls_1); String[] str = getContext().getResources().getStringArray(R.array.group_url4);
Collections.addAll(urls, str); Collections.addAll(urls, str);
return urls; return urls;
} }

@ -297,7 +297,7 @@ public class DownloadAdapter extends AbsRVAdapter<AbsEntity, DownloadAdapter.Sim
Aria.download(getContext()).load((DownloadEntity) entity).start(); Aria.download(getContext()).load((DownloadEntity) entity).start();
break; break;
case AbsTaskEntity.DG_HTTP: case AbsTaskEntity.DG_HTTP:
Aria.download(getContext()).load((DownloadGroupEntity) entity).start(); Aria.download(getContext()).loadGroup((DownloadGroupEntity) entity).start();
break; break;
} }
} }
@ -314,7 +314,7 @@ public class DownloadAdapter extends AbsRVAdapter<AbsEntity, DownloadAdapter.Sim
Aria.download(getContext()).load((DownloadEntity) entity).stop(); Aria.download(getContext()).load((DownloadEntity) entity).stop();
break; break;
case AbsTaskEntity.DG_HTTP: case AbsTaskEntity.DG_HTTP:
Aria.download(getContext()).load((DownloadGroupEntity) entity).stop(); Aria.download(getContext()).loadGroup((DownloadGroupEntity) entity).stop();
break; break;
} }
} }

@ -29,6 +29,7 @@ import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.download.DownloadGroupTask; import com.arialyy.aria.core.download.DownloadGroupTask;
import com.arialyy.aria.core.download.DownloadTask; import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.simple.R; import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseActivity; import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.databinding.ActivityMultiDownloadBinding; import com.arialyy.simple.databinding.ActivityMultiDownloadBinding;
@ -115,6 +116,11 @@ public class MultiDownloadActivity extends BaseActivity<ActivityMultiDownloadBin
mAdapter.updateState(task.getEntity()); mAdapter.updateState(task.getEntity());
} }
@DownloadGroup.onWait void groupTaskWait(DownloadGroupTask task) {
ALog.d(TAG, String.format("group【%s】wait", task.getTaskName()));
mAdapter.updateState(task.getEntity());
}
@DownloadGroup.onTaskResume void groupTaskResume(DownloadGroupTask task) { @DownloadGroup.onTaskResume void groupTaskResume(DownloadGroupTask task) {
mAdapter.updateState(task.getEntity()); mAdapter.updateState(task.getEntity());
} }

@ -121,6 +121,7 @@ public class MultiTaskActivity extends BaseActivity<ActivityMultiBinding> {
@DownloadGroup.onTaskStop void groupTaskStop(DownloadGroupTask task) { @DownloadGroup.onTaskStop void groupTaskStop(DownloadGroupTask task) {
mAdapter.updateBtState(task.getKey(), true); mAdapter.updateBtState(task.getKey(), true);
Log.d(TAG, String.format("group【%s】stop", task.getTaskName()));
} }
@DownloadGroup.onTaskCancel void groupTaskCancel(DownloadGroupTask task) { @DownloadGroup.onTaskCancel void groupTaskCancel(DownloadGroupTask task) {
@ -129,6 +130,7 @@ public class MultiTaskActivity extends BaseActivity<ActivityMultiBinding> {
@DownloadGroup.onTaskFail void groupTaskFail(DownloadGroupTask task) { @DownloadGroup.onTaskFail void groupTaskFail(DownloadGroupTask task) {
mAdapter.updateBtState(task.getKey(), true); mAdapter.updateBtState(task.getKey(), true);
Log.d(TAG, String.format("group【%s】fail", task.getTaskName()));
} }
@DownloadGroup.onTaskComplete void taskComplete(DownloadGroupTask task) { @DownloadGroup.onTaskComplete void taskComplete(DownloadGroupTask task) {

@ -1,8 +1,11 @@
package com.arialyy.simple.test; package com.arialyy.simple.test;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import android.view.View; import android.view.View;
import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.simple.R; import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseActivity; import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.databinding.ActivityTestBinding; import com.arialyy.simple.databinding.ActivityTestBinding;
@ -16,9 +19,13 @@ public class AnyRunActivity extends BaseActivity<ActivityTestBinding> {
String[] urls; String[] urls;
int index = 0; int index = 0;
//String URL = "http://static.gaoshouyou.com/d/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk"; //String URL = "http://static.gaoshouyou.com/d/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk";
//String URL = "http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk"; //String URL = "http://58.213.157.242:8081/sims_file/rest/v1/file/mshd_touchscreen_ms/guideFile/41c33556-dc4a-4d78-bb76-b9f627f94448.mp4/%E5%85%AB%E5%8D%A6%E6%B4%B2%E5%8D%97%E4%BA%AC%E5%86%9C%E4%B8%9A%E5%98%89%E5%B9%B4%E5%8D%8E0511.mp4";
private final String URL = "ftp://192.168.29.140:21/download/AriaPrj.rar"; //String URL = "http://d1.showself.com/download/showself_android-s236279_release.apk";
String URL = "http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk";
//private final String URL = "ftp://192.168.29.140:21/download/AriaPrj.rar";
//String URL = "https://dl.genymotion.com/releases/genymotion-2.12.1/genymotion-2.12.1-vbox.exe"; //String URL = "https://dl.genymotion.com/releases/genymotion-2.12.1/genymotion-2.12.1-vbox.exe";
//String URL = "ftp://192.168.29.140:21/download/SDK_Demo-release.apk";
//String URL = "ftp://z:z@dygod18.com:21211/[电影天堂www.dy2018.com]猩球崛起3:终极之战BD国英双语中英双字.mkv";
@Override protected int setLayoutId() { @Override protected int setLayoutId() {
return R.layout.activity_test; return R.layout.activity_test;
@ -30,6 +37,8 @@ public class AnyRunActivity extends BaseActivity<ActivityTestBinding> {
mBar.setVisibility(View.GONE); mBar.setVisibility(View.GONE);
module = new AnyRunnModule(this); module = new AnyRunnModule(this);
urls = getResources().getStringArray(R.array.group_urls); urls = getResources().getStringArray(R.array.group_urls);
DownloadTaskEntity entity = Aria.download(this).getDownloadTask(URL);
Log.d(TAG, entity + "");
} }
public void onClick(View view) { public void onClick(View view) {
@ -42,7 +51,8 @@ public class AnyRunActivity extends BaseActivity<ActivityTestBinding> {
//} //}
//for (int i = 0; i < 10; i++) { //for (int i = 0; i < 10; i++) {
module.startFtp(URL); //module.startFtp(URL);
module.start(URL);
//} //}
//List<AbsEntity> list = Aria.download(this).getTotalTaskList(); //List<AbsEntity> list = Aria.download(this).getTotalTaskList();
//ALog.d(TAG, "size ==> " + list.size()); //ALog.d(TAG, "size ==> " + list.size());

@ -10,6 +10,7 @@ import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import com.arialyy.frame.util.show.L; import com.arialyy.frame.util.show.L;
import java.io.File; import java.io.File;
import java.net.Proxy;
/** /**
* Created by laoyuyu on 2018/4/13. * Created by laoyuyu on 2018/4/13.
@ -38,7 +39,7 @@ public class AnyRunnModule {
} }
@Download.onTaskRunning protected void running(DownloadTask task) { @Download.onTaskRunning protected void running(DownloadTask task) {
Log.d(TAG, "running"); Log.d(TAG, "running;Percent = " + task.getPercent());
} }
@Download.onTaskResume void taskResume(DownloadTask task) { @Download.onTaskResume void taskResume(DownloadTask task) {
@ -68,7 +69,8 @@ public class AnyRunnModule {
.load(url) .load(url)
//.addHeader("Accept-Encoding", "gzip") //.addHeader("Accept-Encoding", "gzip")
.setRequestMode(RequestEnum.GET) .setRequestMode(RequestEnum.GET)
.setFilePath(Environment.getExternalStorageDirectory().getPath() + "/ggsg123456.apk") .setUrlProxy(Proxy.NO_PROXY)
.setFilePath(Environment.getExternalStorageDirectory().getPath() + "/abcds.exe")
//.resetState() //.resetState()
.start(); .start();
//String[] urls = new String[] { //String[] urls = new String[] {

@ -1,5 +1,6 @@
package com.arialyy.simple.test; package com.arialyy.simple.test;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
@ -7,6 +8,7 @@ import com.arialyy.annotations.Upload;
import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.upload.UploadTask; import com.arialyy.aria.core.upload.UploadTask;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import com.arialyy.simple.R; import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseActivity; import com.arialyy.simple.base.BaseActivity;
@ -22,8 +24,8 @@ public class TestActivity extends BaseActivity<ActivityTestBinding> {
//String URL = "http://58.210.9.131/tpk/sipgt//TDLYZTGH.tpk"; //chunked 下载 //String URL = "http://58.210.9.131/tpk/sipgt//TDLYZTGH.tpk"; //chunked 下载
//private final String URL = "ftp://192.168.1.3:21/download//AriaPrj.rar"; //private final String URL = "ftp://192.168.1.3:21/download//AriaPrj.rar";
private final String FILE_PATH = "/mnt/sdcard/AriaPrj.rar"; private final String FILE_PATH = "/mnt/sdcard/AriaPrj.rar";
//private final String URL = "ftp://192.168.29.140:21/aa//你好"; private final String URL = "ftp://192.168.1.2:21/aa//你好";
private final String URL = "ftp://192.168.29.140:21/upload/";
@Override protected int setLayoutId() { @Override protected int setLayoutId() {
return R.layout.activity_test; return R.layout.activity_test;
@ -81,6 +83,8 @@ public class TestActivity extends BaseActivity<ActivityTestBinding> {
.setUploadUrl(URL) .setUploadUrl(URL)
.setExtendField("韩寒哈大双") .setExtendField("韩寒哈大双")
.start(); .start();
//Uri uri = Uri.parse("ftp://z:z@dygod18.com:21211/[电影天堂www.dy2018.com]猩球崛起3:终极之战BD国英双语中英双字.mkv");
//ALog.d(TAG, "sh = " + uri.getScheme() + ", user = " + uri.getUserInfo() + ", host = " + uri.getHost() + ", port = " + uri.getPort() + " remotePath = " + uri.getPath());
break; break;
case R.id.stop: case R.id.stop:
Aria.upload(this).loadFtp(FILE_PATH).stop(); Aria.upload(this).loadFtp(FILE_PATH).stop();

@ -64,7 +64,7 @@
</string-array> </string-array>
<string-array name="group_urls_1"> <string-array name="group_urls_1">
<!--<item>http://hzdown.muzhiwan.com/2017/05/08/nl.noio.kingdom_59104935e56f0.apk</item>--> <item>http://hzdown.muzhiwan.com/2017/05/08/nl.noio.kingdom_59104935e56f0.apk</item>
<!--<item>https://atom-installer.github.com/v1.13.0/AtomSetup.exe</item>--> <!--<item>https://atom-installer.github.com/v1.13.0/AtomSetup.exe</item>-->
<item>http://hzdown.muzhiwan.com/2017/09/05/com.mir.iphone.empire83jie.mzw_59ae6d5a3638d.apk</item> <item>http://hzdown.muzhiwan.com/2017/09/05/com.mir.iphone.empire83jie.mzw_59ae6d5a3638d.apk</item>
</string-array> </string-array>
@ -79,9 +79,14 @@
<item>http://static.gaoshouyou.com/d/92/12/5592a647b8126755647abbe8074fde39.apk</item> <item>http://static.gaoshouyou.com/d/92/12/5592a647b8126755647abbe8074fde39.apk</item>
</string-array> </string-array>
<string-array name="group_url4">
<item>http://120.79.135.3/img/20180601/VR Karts Sprint.ver.1.04.build.15_crack_align.apk</item>
<item>http://120.79.135.3/img/20180601/main.11.com.daydvr.acefishing.vr.freefull.google.global.android.common.obb</item>
</string-array>
<string-array name="group_names"> <string-array name="group_names">
<!--<item>王者荣耀.apk</item>--> <!--<item>王者荣耀.apk</item>-->
<!--<item>战斗吧剑灵.apk</item>--> <item>战斗吧剑灵.apk</item>
<item>天魔幻想.apk</item> <item>天魔幻想.apk</item>
</string-array> </string-array>

@ -1,6 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.arialyy.aria"> package="com.arialyy.aria">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application <application
android:allowBackup="true" android:allowBackup="true"
android:supportsRtl="true"> android:supportsRtl="true">

@ -366,6 +366,11 @@ class Configuration {
String caName; String caName;
/** /**
* 下载线程数下载线程数不能小于1 * 下载线程数下载线程数不能小于1
* 注意
* 1线程下载数改变后新的下载任务才会生效
* 2如果任务大小小于1m该设置不会生效
* 3从3.4.1开始如果线程数为1文件初始化时将不再预占用对应长度的空间下载多少byte则占多大的空间
* 对于采用多线程的任务或旧任务依然采用原来的文件空间占用方式
*/ */
int threadNum = 3; int threadNum = 3;
@ -374,26 +379,6 @@ class Configuration {
*/ */
int maxSpeed = 0; int maxSpeed = 0;
/**
* 是否开启动态文件开启动态文件后初始化时将不占用磁盘空间下载多少byte占多少空间效果见chrome的下载
* 注意
* 1使用该功能将自动关闭多线程下载
* 2对于已经采用了多线程的任务依然采用原来的下载方式
* 3原本参数是true任务没下载完成就参数改为false那么没下载完成的任务还是会按照参数修改前的方式下载只有新任务才会根据参数调用不同的下载方式
* {@code true}使用
*/
boolean openDynamicFile = true;
public DownloadConfig setOpenDynamicFile(boolean openDynamicFile) {
this.openDynamicFile = openDynamicFile;
saveKey("openDynamicFile", String.valueOf(openDynamicFile));
return this;
}
public boolean isOpenDynamicFile() {
return openDynamicFile;
}
public DownloadConfig setMaxTaskNum(int maxTaskNum) { public DownloadConfig setMaxTaskNum(int maxTaskNum) {
oldMaxTaskNum = this.maxTaskNum; oldMaxTaskNum = this.maxTaskNum;
this.maxTaskNum = maxTaskNum; this.maxTaskNum = maxTaskNum;

@ -39,7 +39,7 @@ task clean(type: Delete) {
ext { ext {
userOrg = 'arialyy' userOrg = 'arialyy'
groupId = 'com.arialyy.aria' groupId = 'com.arialyy.aria'
publishVersion = '3.4.1' publishVersion = '3.4.2_dev6'
// publishVersion = '1.0.3' //FTP插件 // publishVersion = '1.0.3' //FTP插件
repoName='maven' repoName='maven'
desc = 'android 下载框架' desc = 'android 下载框架'

Loading…
Cancel
Save