优化AbsThreadTask代码, 新增文件长度处理功能 https://github.com/AriaLyy/Aria/issues/393

v3.6.6
laoyuyu 6 years ago
parent 0c3e16cad7
commit 0dbc515cd3
  1. 1
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
  2. 257
      Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java
  3. 3
      Aria/src/main/java/com/arialyy/aria/core/common/OnFileInfoCallback.java
  4. 2
      Aria/src/main/java/com/arialyy/aria/core/common/ftp/AbsFtpInfoThread.java
  5. 10
      Aria/src/main/java/com/arialyy/aria/core/common/ftp/AbsFtpThreadTask.java
  6. 207
      Aria/src/main/java/com/arialyy/aria/core/common/http/HttpDelegate.java
  7. 38
      Aria/src/main/java/com/arialyy/aria/core/common/http/HttpHeaderDelegate.java
  8. 385
      Aria/src/main/java/com/arialyy/aria/core/common/http/HttpTaskDelegate.java
  9. 239
      Aria/src/main/java/com/arialyy/aria/core/download/AbsDGTarget.java
  10. 2
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java
  11. 15
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
  12. 303
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java
  13. 3
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java
  14. 66
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java
  15. 49
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
  16. 88
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
  17. 5
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java
  18. 20
      Aria/src/main/java/com/arialyy/aria/core/download/group/AbsGroupUtil.java
  19. 26
      Aria/src/main/java/com/arialyy/aria/core/download/group/DownloadGroupUtil.java
  20. 3
      Aria/src/main/java/com/arialyy/aria/core/download/group/FtpDirDownloadUtil.java
  21. 3
      Aria/src/main/java/com/arialyy/aria/core/download/group/SubDownloadLoader.java
  22. 10
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsHttpFileLenAdapter.java
  23. 688
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
  24. 36
      Aria/src/main/java/com/arialyy/aria/core/inf/IHttpFileLenAdapter.java
  25. 388
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java
  26. 35
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java
  27. 3
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/SimpleUploadUtil.java
  28. 2450
      Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
  29. 2
      DEV_LOG.md
  30. 3
      app/build.gradle
  31. 17
      app/src/main/java/com/arialyy/simple/base/BaseApplication.java
  32. 31
      app/src/main/java/com/arialyy/simple/core/download/SingleTaskActivity.java
  33. 15
      app/src/main/java/com/arialyy/simple/core/download/group/DownloadGroupActivity.java

@ -16,6 +16,7 @@
package com.arialyy.aria.core.common; package com.arialyy.aria.core.common;
import android.content.Context; import android.content.Context;
import android.os.Looper;
import android.util.SparseArray; import android.util.SparseArray;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.BaseDListener; import com.arialyy.aria.core.download.BaseDListener;

@ -58,22 +58,19 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
*/ */
protected long mChildCurrentLocation = 0; protected long mChildCurrentLocation = 0;
protected IEventListener mListener; protected IEventListener mListener;
protected StateConstance STATE; private StateConstance sState;
protected SubThreadConfig<TASK_WRAPPER> mConfig; private SubThreadConfig<TASK_WRAPPER> sConfig;
protected ENTITY mEntity; private ENTITY mEntity;
protected TASK_WRAPPER mTaskWrapper; private TASK_WRAPPER mTaskWrapper;
private int mFailTimes = 0; private int mFailTimes = 0;
private long mLastSaveTime; private long mLastSaveTime;
private ExecutorService mConfigThreadPool; private ExecutorService mConfigThreadPool;
protected boolean isNotNetRetry; //断网情况是否重试 private boolean isNotNetRetry; //断网情况是否重试
private boolean taskBreak = false; //任务跳出 private boolean taskBreak = false; //任务跳出
protected int mThreadNum; private int mThreadNum;
/** protected BandwidthLimiter mSpeedBandUtil; //速度限制工具
* 速度限制工具
*/
protected BandwidthLimiter mSpeedBandUtil;
protected AriaManager mAridManager; protected AriaManager mAridManager;
protected boolean isInterrupted = false; private boolean isInterrupted = false;
private Thread mConfigThread = new Thread(new Runnable() { private Thread mConfigThread = new Thread(new Runnable() {
@Override public void run() { @Override public void run() {
@ -85,14 +82,14 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
protected AbsThreadTask(StateConstance constance, IEventListener listener, protected AbsThreadTask(StateConstance constance, IEventListener listener,
SubThreadConfig<TASK_WRAPPER> config) { SubThreadConfig<TASK_WRAPPER> config) {
STATE = constance; sState = constance;
sConfig = config;
mListener = listener; mListener = listener;
mConfig = config; mTaskWrapper = getConfig().TASK_WRAPPER;
mTaskWrapper = mConfig.TASK_WRAPPER;
mEntity = mTaskWrapper.getEntity(); mEntity = mTaskWrapper.getEntity();
mLastSaveTime = System.currentTimeMillis(); mLastSaveTime = System.currentTimeMillis();
mConfigThreadPool = Executors.newCachedThreadPool(); mConfigThreadPool = Executors.newCachedThreadPool();
mThreadNum = STATE.TASK_RECORD.threadRecords.size(); mThreadNum = getState().TASK_RECORD.threadRecords.size();
mAridManager = AriaManager.getInstance(AriaManager.APP); mAridManager = AriaManager.getInstance(AriaManager.APP);
if (getMaxSpeed() > 0) { if (getMaxSpeed() > 0) {
mSpeedBandUtil = new BandwidthLimiter(getMaxSpeed(), mThreadNum); mSpeedBandUtil = new BandwidthLimiter(getMaxSpeed(), mThreadNum);
@ -122,21 +119,42 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
* 当前线程是否完成对于不支持断点的任务一律未完成 {@code true} 完成{@code false} 未完成 * 当前线程是否完成对于不支持断点的任务一律未完成 {@code true} 完成{@code false} 未完成
*/ */
boolean isThreadComplete() { boolean isThreadComplete() {
return mConfig.THREAD_RECORD.isComplete; return getConfig().THREAD_RECORD.isComplete;
}
/**
* 获取状态信息
*/
protected StateConstance getState() {
return sState;
}
/**
* 获取实体
*/
protected ENTITY getEntity() {
return mEntity;
}
/**
* 获取任务驱动对象
*/
protected TASK_WRAPPER getTaskWrapper() {
return mTaskWrapper;
} }
/** /**
* 获取任务记录 * 获取任务记录
*/ */
private TaskRecord getTaskRecord() { private TaskRecord getTaskRecord() {
return STATE.TASK_RECORD; return getState().TASK_RECORD;
} }
/** /**
* 获取线程记录 * 获取线程记录
*/ */
protected ThreadRecord getThreadRecord() { protected ThreadRecord getThreadRecord() {
return mConfig.THREAD_RECORD; return getConfig().THREAD_RECORD;
} }
/** /**
@ -170,19 +188,19 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
void breakTask() { void breakTask() {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
taskBreak = true; taskBreak = true;
if (mConfig.SUPPORT_BP) { if (getConfig().SUPPORT_BP) {
final long currentTemp = mChildCurrentLocation; final long currentTemp = mChildCurrentLocation;
STATE.STOP_NUM++; getState().STOP_NUM++;
ALog.d(TAG, String.format("任务【%s】thread__%s__中断【停止位置:%s】", mConfig.TEMP_FILE.getName(), ALog.d(TAG, String.format("任务【%s】thread__%s__中断【停止位置:%s】", getConfig().TEMP_FILE.getName(),
mConfig.THREAD_ID, currentTemp)); getConfig().THREAD_ID, currentTemp));
writeConfig(false, currentTemp); writeConfig(false, currentTemp);
if (STATE.isStop()) { if (getState().isStop()) {
ALog.i(TAG, String.format("任务【%s】已中断", mConfig.TEMP_FILE.getName())); ALog.i(TAG, String.format("任务【%s】已中断", getConfig().TEMP_FILE.getName()));
STATE.isRunning = false; getState().isRunning = false;
} }
} else { } else {
ALog.i(TAG, String.format("任务【%s】已中断", mConfig.TEMP_FILE.getName())); ALog.i(TAG, String.format("任务【%s】已中断", getConfig().TEMP_FILE.getName()));
STATE.isRunning = false; getState().isRunning = false;
} }
} }
} }
@ -193,7 +211,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
* @return {@code true}正在运行 * @return {@code true}正在运行
*/ */
public boolean isRunning() { public boolean isRunning() {
return STATE.isRunning; return getState().isRunning;
} }
public boolean isInterrupted() { public boolean isInterrupted() {
@ -203,8 +221,8 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
/** /**
* 获取线程配置信息 * 获取线程配置信息
*/ */
public SubThreadConfig getConfig() { protected SubThreadConfig<TASK_WRAPPER> getConfig() {
return mConfig; return sConfig;
} }
@Override protected void finalize() throws Throwable { @Override protected void finalize() throws Throwable {
@ -220,7 +238,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
* @return {@code true} 中断{@code false} 不是中断 * @return {@code true} 中断{@code false} 不是中断
*/ */
protected boolean isBreak() { protected boolean isBreak() {
return STATE.isCancel || STATE.isStop || taskBreak; return getState().isCancel || getState().isStop || taskBreak;
} }
/** /**
@ -230,10 +248,10 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
*/ */
protected boolean mergeFile() { protected boolean mergeFile() {
List<String> partPath = new ArrayList<>(); List<String> partPath = new ArrayList<>();
for (int i = 0, len = STATE.TASK_RECORD.threadNum; i < len; i++) { for (int i = 0, len = getState().TASK_RECORD.threadNum; i < len; i++) {
partPath.add(String.format(AbsFileer.SUB_PATH, STATE.TASK_RECORD.filePath, i)); partPath.add(String.format(AbsFileer.SUB_PATH, getState().TASK_RECORD.filePath, i));
} }
boolean isSuccess = FileUtil.mergeFile(STATE.TASK_RECORD.filePath, partPath); boolean isSuccess = FileUtil.mergeFile(getState().TASK_RECORD.filePath, partPath);
if (isSuccess) { if (isSuccess) {
for (String pp : partPath) { for (String pp : partPath) {
File f = new File(pp); File f = new File(pp);
@ -241,10 +259,10 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
f.delete(); f.delete();
} }
} }
File targetFile = new File(STATE.TASK_RECORD.filePath); File targetFile = new File(getState().TASK_RECORD.filePath);
if (targetFile.exists() && targetFile.length() > mEntity.getFileSize()) { if (targetFile.exists() && targetFile.length() > getEntity().getFileSize()) {
ALog.e(TAG, String.format("任务【%s】分块文件合并失败,下载长度超出文件真实长度,downloadLen: %s,fileSize: %s", ALog.e(TAG, String.format("任务【%s】分块文件合并失败,下载长度超出文件真实长度,downloadLen: %s,fileSize: %s",
mConfig.TEMP_FILE.getName(), targetFile.length(), mEntity.getFileSize())); getConfig().TEMP_FILE.getName(), targetFile.length(), getEntity().getFileSize()));
return false; return false;
} }
return true; return true;
@ -282,30 +300,31 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
*/ */
public void stop() { public void stop() {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
if (mConfig.SUPPORT_BP) { if (getConfig().SUPPORT_BP) {
final long stopLocation; final long stopLocation;
if (getTaskRecord().isBlock) { if (getTaskRecord().isBlock) {
File blockFile = getBockFile(); File blockFile = getBockFile();
ThreadRecord tr = getThreadRecord(); ThreadRecord tr = getThreadRecord();
long block = mEntity.getFileSize() / getTaskRecord().threadRecords.size(); long block = getEntity().getFileSize() / getTaskRecord().threadRecords.size();
stopLocation = stopLocation =
blockFile.exists() ? (tr.threadId * block + blockFile.length()) : tr.threadId * block; blockFile.exists() ? (tr.threadId * block + blockFile.length()) : tr.threadId * block;
} else { } else {
stopLocation = mChildCurrentLocation; stopLocation = mChildCurrentLocation;
} }
STATE.STOP_NUM++; getState().STOP_NUM++;
ALog.d(TAG, String.format("任务【%s】thread__%s__停止【当前线程停止位置:%s】", mConfig.TEMP_FILE.getName(), ALog.d(TAG,
mConfig.THREAD_ID, stopLocation)); String.format("任务【%s】thread__%s__停止【当前线程停止位置:%s】", getConfig().TEMP_FILE.getName(),
getConfig().THREAD_ID, stopLocation));
writeConfig(false, stopLocation); writeConfig(false, stopLocation);
if (STATE.isStop()) { if (getState().isStop()) {
ALog.i(TAG, String.format("任务【%s】已停止", mConfig.TEMP_FILE.getName())); ALog.i(TAG, String.format("任务【%s】已停止", getConfig().TEMP_FILE.getName()));
STATE.isRunning = false; getState().isRunning = false;
mListener.onStop(STATE.CURRENT_LOCATION); mListener.onStop(getState().CURRENT_LOCATION);
} }
} else { } else {
ALog.i(TAG, String.format("任务【%s】已停止", mConfig.TEMP_FILE.getName())); ALog.i(TAG, String.format("任务【%s】已停止", getConfig().TEMP_FILE.getName()));
STATE.isRunning = false; getState().isRunning = false;
mListener.onStop(STATE.CURRENT_LOCATION); mListener.onStop(getState().CURRENT_LOCATION);
} }
} }
} }
@ -315,19 +334,20 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
*/ */
protected void progress(long len) { protected void progress(long len) {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
if (STATE.CURRENT_LOCATION > mEntity.getFileSize() && !mTaskWrapper.asHttp().isChunked()) { if (getState().CURRENT_LOCATION > getEntity().getFileSize() && !getTaskWrapper().asHttp()
.isChunked()) {
String errorMsg = String errorMsg =
String.format("下载失败,下载长度超出文件真实长度;currentLocation=%s, fileSize=%s", String.format("下载失败,下载长度超出文件真实长度;currentLocation=%s, fileSize=%s",
STATE.CURRENT_LOCATION, getState().CURRENT_LOCATION,
mEntity.getFileSize()); getEntity().getFileSize());
taskBreak = true; taskBreak = true;
fail(mChildCurrentLocation, new FileException(TAG, errorMsg), false); fail(mChildCurrentLocation, new FileException(TAG, errorMsg), false);
return; return;
} }
mChildCurrentLocation += len; mChildCurrentLocation += len;
STATE.CURRENT_LOCATION += len; getState().CURRENT_LOCATION += len;
if (System.currentTimeMillis() - mLastSaveTime > 5000 if (System.currentTimeMillis() - mLastSaveTime > 5000
&& mChildCurrentLocation < mConfig.END_LOCATION) { && mChildCurrentLocation < getConfig().END_LOCATION) {
mLastSaveTime = System.currentTimeMillis(); mLastSaveTime = System.currentTimeMillis();
if (!mConfigThreadPool.isShutdown()) { if (!mConfigThreadPool.isShutdown()) {
mConfigThreadPool.execute(mConfigThread); mConfigThreadPool.execute(mConfigThread);
@ -341,21 +361,22 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
*/ */
public void cancel() { public void cancel() {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
if (mConfig.SUPPORT_BP) { if (getConfig().SUPPORT_BP) {
STATE.CANCEL_NUM++; getState().CANCEL_NUM++;
ALog.d(TAG, ALog.d(TAG,
String.format("任务【%s】thread__%s__取消", mConfig.TEMP_FILE.getName(), mConfig.THREAD_ID)); String.format("任务【%s】thread__%s__取消", getConfig().TEMP_FILE.getName(),
if (STATE.isCancel()) { getConfig().THREAD_ID));
if (mConfig.TEMP_FILE.exists() && !(mEntity instanceof UploadEntity)) { if (getState().isCancel()) {
mConfig.TEMP_FILE.delete(); if (getConfig().TEMP_FILE.exists() && !(getEntity() instanceof UploadEntity)) {
getConfig().TEMP_FILE.delete();
} }
ALog.d(TAG, String.format("任务【%s】已取消", mConfig.TEMP_FILE.getName())); ALog.d(TAG, String.format("任务【%s】已取消", getConfig().TEMP_FILE.getName()));
STATE.isRunning = false; getState().isRunning = false;
mListener.onCancel(); mListener.onCancel();
} }
} else { } else {
ALog.d(TAG, String.format("任务【%s】已取消", mConfig.TEMP_FILE.getName())); ALog.d(TAG, String.format("任务【%s】已取消", getConfig().TEMP_FILE.getName()));
STATE.isRunning = false; getState().isRunning = false;
mListener.onCancel(); mListener.onCancel();
} }
} }
@ -377,18 +398,16 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
* @param subCurrentLocation 当前子线程进度 * @param subCurrentLocation 当前子线程进度
*/ */
protected void fail(final long subCurrentLocation, BaseException ex, boolean needRetry) { protected void fail(final long subCurrentLocation, BaseException ex, boolean needRetry) {
synchronized (AriaManager.LOCK) { if (ex != null) {
if (ex != null) { ALog.e(TAG, ALog.getExceptionString(ex));
ALog.e(TAG, ALog.getExceptionString(ex)); }
} if (getConfig().SUPPORT_BP) {
if (mConfig.SUPPORT_BP) { writeConfig(false, subCurrentLocation);
writeConfig(false, subCurrentLocation); retryThis(needRetry && getState().START_THREAD_NUM != 1);
retryThis(needRetry && STATE.START_THREAD_NUM != 1); } else {
} else { ALog.e(TAG, String.format("任务【%s】执行失败", getConfig().TEMP_FILE.getName()));
ALog.e(TAG, String.format("任务【%s】执行失败", mConfig.TEMP_FILE.getName())); ErrorHelp.saveError(TAG, "", ALog.getExceptionString(ex));
ErrorHelp.saveError(TAG, "", ALog.getExceptionString(ex)); handleFailState(!isBreak());
handleFailState(!isBreak());
}
} }
} }
@ -398,22 +417,20 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
* @param needRetry 是否可以重试 * @param needRetry 是否可以重试
*/ */
private void retryThis(boolean needRetry) { private void retryThis(boolean needRetry) {
synchronized (AriaManager.LOCK) { if (!NetUtils.isConnected(AriaManager.APP) && !isNotNetRetry) {
if (!NetUtils.isConnected(AriaManager.APP) && !isNotNetRetry) { ALog.w(TAG, String.format("任务【%s】thread__%s__重试失败,网络未连接", getConfig().TEMP_FILE.getName(),
ALog.w(TAG, String.format("任务【%s】thread__%s__重试失败,网络未连接", mConfig.TEMP_FILE.getName(), getConfig().THREAD_ID));
mConfig.THREAD_ID)); }
} if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(AriaManager.APP)
if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(AriaManager.APP) || isNotNetRetry) && !isBreak()) {
|| isNotNetRetry) && !isBreak()) { ALog.w(TAG,
ALog.w(TAG, String.format("任务【%s】thread__%s__正在重试", getConfig().TEMP_FILE.getName(),
String.format("任务【%s】thread__%s__正在重试", mConfig.TEMP_FILE.getName(), getConfig().THREAD_ID));
mConfig.THREAD_ID)); mFailTimes++;
mFailTimes++; handleRetryRecord();
handleRetryRecord(); ThreadTaskManager.getInstance().retryThread(AbsThreadTask.this);
ThreadTaskManager.getInstance().retryThread(AbsThreadTask.this); } else {
} else { handleFailState(!isBreak());
handleFailState(!isBreak());
}
} }
} }
@ -423,7 +440,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
private void handleRetryRecord() { private void handleRetryRecord() {
if (getTaskRecord().isBlock) { if (getTaskRecord().isBlock) {
ThreadRecord tr = getThreadRecord(); ThreadRecord tr = getThreadRecord();
long block = mEntity.getFileSize() / getTaskRecord().threadRecords.size(); long block = getEntity().getFileSize() / getTaskRecord().threadRecords.size();
File blockFile = getBockFile(); File blockFile = getBockFile();
if (blockFile.length() > tr.blockLen) { if (blockFile.length() > tr.blockLen) {
@ -431,22 +448,22 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
blockFile.delete(); blockFile.delete();
tr.startLocation = block * tr.threadId; tr.startLocation = block * tr.threadId;
tr.isComplete = false; tr.isComplete = false;
mConfig.START_LOCATION = tr.startLocation; getConfig().START_LOCATION = tr.startLocation;
} else if (blockFile.length() < tr.blockLen) { } else if (blockFile.length() < tr.blockLen) {
tr.startLocation = block * tr.threadId + blockFile.length(); tr.startLocation = block * tr.threadId + blockFile.length();
tr.isComplete = false; tr.isComplete = false;
mConfig.START_LOCATION = tr.startLocation; getConfig().START_LOCATION = tr.startLocation;
STATE.CURRENT_LOCATION = getBlockRealTotalSize(); getState().CURRENT_LOCATION = getBlockRealTotalSize();
ALog.i(TAG, String.format("修正分块【%s】,开始位置:%s,当前进度:%s", blockFile.getPath(), tr.startLocation, ALog.i(TAG, String.format("修正分块【%s】,开始位置:%s,当前进度:%s", blockFile.getPath(), tr.startLocation,
STATE.CURRENT_LOCATION)); getState().CURRENT_LOCATION));
} else { } else {
STATE.COMPLETE_THREAD_NUM++; getState().COMPLETE_THREAD_NUM++;
tr.isComplete = true; tr.isComplete = true;
} }
tr.update(); tr.update();
} else { } else {
mConfig.START_LOCATION = mChildCurrentLocation == 0 ? mConfig.START_LOCATION getConfig().START_LOCATION = mChildCurrentLocation == 0 ? getConfig().START_LOCATION
: mConfig.THREAD_RECORD.startLocation; : getConfig().THREAD_RECORD.startLocation;
} }
} }
@ -456,7 +473,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
* @return 分块文件 * @return 分块文件
*/ */
private File getBockFile() { private File getBockFile() {
return new File(String.format(AbsFileer.SUB_PATH, STATE.TASK_RECORD.filePath, return new File(String.format(AbsFileer.SUB_PATH, getState().TASK_RECORD.filePath,
getThreadRecord().threadId)); getThreadRecord().threadId));
} }
@ -482,15 +499,13 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
* @param taskNeedReTry 任务是否需要重试{@code true} 需要 * @param taskNeedReTry 任务是否需要重试{@code true} 需要
*/ */
private void handleFailState(boolean taskNeedReTry) { private void handleFailState(boolean taskNeedReTry) {
synchronized (AriaManager.LOCK) { getState().FAIL_NUM++;
STATE.FAIL_NUM++; if (getState().isFail()) {
if (STATE.isFail()) { getState().isRunning = false;
STATE.isRunning = false; // 手动停止不进行fail回调
// 手动停止不进行fail回调 if (!getState().isStop) {
if (!STATE.isStop) { String errorMsg = String.format("任务【%s】执行失败", getConfig().TEMP_FILE.getName());
String errorMsg = String.format("任务【%s】执行失败", mConfig.TEMP_FILE.getName()); mListener.onFail(taskNeedReTry, new TaskException(TAG, errorMsg));
mListener.onFail(taskNeedReTry, new TaskException(TAG, errorMsg));
}
} }
} }
} }
@ -502,21 +517,19 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
* @param record 当前下载进度 * @param record 当前下载进度
*/ */
protected void writeConfig(boolean isComplete, final long record) { protected void writeConfig(boolean isComplete, final long record) {
synchronized (AriaManager.LOCK) { ThreadRecord tr = getThreadRecord();
ThreadRecord tr = getThreadRecord(); if (tr != null) {
if (tr != null) { tr.isComplete = isComplete;
tr.isComplete = isComplete; if (getTaskRecord().isBlock) {
if (getTaskRecord().isBlock) { tr.startLocation = record;
} else if (getTaskRecord().isOpenDynamicFile) {
tr.startLocation = getConfig().TEMP_FILE.length();
} else {
if (0 < record && record < getConfig().END_LOCATION) {
tr.startLocation = record; tr.startLocation = record;
} else if (getTaskRecord().isOpenDynamicFile) {
tr.startLocation = mConfig.TEMP_FILE.length();
} else {
if (0 < record && record < mConfig.END_LOCATION) {
tr.startLocation = record;
}
} }
tr.update();
} }
tr.update();
} }
} }

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.common; package com.arialyy.aria.core.common;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.BaseException;
public interface OnFileInfoCallback { public interface OnFileInfoCallback {
@ -30,5 +31,5 @@ public interface OnFileInfoCallback {
* *
* @param e 错误信息 * @param e 错误信息
*/ */
void onFail(String url, BaseException e, boolean needRetry); void onFail(AbsEntity entity, BaseException e, boolean needRetry);
} }

@ -374,7 +374,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_WRAPPER ex
private void failDownload(BaseException e, boolean needRetry) { private void failDownload(BaseException e, boolean needRetry) {
if (mCallback != null) { if (mCallback != null) {
mCallback.onFail(mEntity.getKey(), e, needRetry); mCallback.onFail(mEntity, e, needRetry);
} }
} }

@ -57,7 +57,7 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
*/ */
protected FTPClient createClient() { protected FTPClient createClient() {
FTPClient client = null; FTPClient client = null;
final FtpUrlEntity urlEntity = mTaskWrapper.asFtp().getUrlEntity(); final FtpUrlEntity urlEntity = getTaskWrapper().asFtp().getUrlEntity();
if (urlEntity.validAddr == null) { if (urlEntity.validAddr == null) {
try { try {
InetAddress[] ips = InetAddress.getAllByName(urlEntity.hostName); InetAddress[] ips = InetAddress.getAllByName(urlEntity.hostName);
@ -106,8 +106,8 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码 // 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
charSet = "UTF-8"; charSet = "UTF-8";
if (reply != FTPReply.COMMAND_IS_SUPERFLUOUS) { if (reply != FTPReply.COMMAND_IS_SUPERFLUOUS) {
if (!TextUtils.isEmpty(mTaskWrapper.asFtp().getCharSet())) { if (!TextUtils.isEmpty(getTaskWrapper().asFtp().getCharSet())) {
charSet = mTaskWrapper.asFtp().getCharSet(); charSet = getTaskWrapper().asFtp().getCharSet();
} }
} }
client.setControlEncoding(charSet); client.setControlEncoding(charSet);
@ -116,7 +116,7 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
client.enterLocalPassiveMode(); client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE); client.setFileType(FTP.BINARY_FILE_TYPE);
client.setControlKeepAliveTimeout(5000); client.setControlKeepAliveTimeout(5000);
if (mTaskWrapper.asFtp().getUrlEntity().isFtps) { if (getTaskWrapper().asFtp().getUrlEntity().isFtps) {
((FTPSClient) client).execPROT("P"); ((FTPSClient) client).execPROT("P");
} }
} catch (java.io.IOException e) { } catch (java.io.IOException e) {
@ -150,7 +150,7 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
private FTPClient connect(FTPClient client, InetAddress[] ips, int index, int port) { private FTPClient connect(FTPClient client, InetAddress[] ips, int index, int port) {
try { try {
client.connect(ips[index], port); client.connect(ips[index], port);
mTaskWrapper.asFtp().getUrlEntity().validAddr = ips[index]; getTaskWrapper().asFtp().getUrlEntity().validAddr = ips[index];
return client; return client;
} catch (java.io.IOException e) { } catch (java.io.IOException e) {
try { try {

@ -1,104 +1,103 @@
/* /*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.common.http; package com.arialyy.aria.core.common.http;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.download.DGTaskWrapper; import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadGroupTarget; import com.arialyy.aria.core.download.DownloadGroupTarget;
import com.arialyy.aria.core.inf.AbsTarget; import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.ITargetHandler; import com.arialyy.aria.core.inf.ITargetHandler;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* HTTP参数委托 * HTTP参数委托
* @param <TARGET> */
*/ class HttpDelegate<TARGET extends AbsTarget> implements ITargetHandler {
class HttpDelegate<TARGET extends AbsTarget> implements ITargetHandler { private static final String TAG = "PostDelegate";
private static final String TAG = "PostDelegate"; TARGET mTarget;
TARGET mTarget;
HttpDelegate(TARGET target) {
HttpDelegate(TARGET target) { mTarget = target;
mTarget = target; }
}
public TARGET setParams(Map<String, String> params) {
public TARGET setParams(Map<String, String> params) { mTarget.getTaskWrapper().asHttp().setParams(params);
mTarget.getTaskWrapper().asHttp().setParams(params); if (mTarget instanceof DownloadGroupTarget) {
if (mTarget instanceof DownloadGroupTarget) { for (DTaskWrapper subTask : ((DGTaskWrapper) mTarget.getTaskWrapper()).getSubTaskWrapper()) {
for (DTaskWrapper subTask : ((DGTaskWrapper) mTarget.getTaskWrapper()).getSubTaskWrapper()) { subTask.asHttp().setParams(params);
subTask.asHttp().setParams(params); }
} }
} return mTarget;
return mTarget; }
}
public TARGET setParam(String key, String value) {
public TARGET setParam(String key, String value) { if (TextUtils.isEmpty(key) || TextUtils.isEmpty(value)) {
if (TextUtils.isEmpty(key) || TextUtils.isEmpty(value)) { ALog.d(TAG, "key 或value 为空");
ALog.d(TAG, "key 或value 为空"); return mTarget;
return mTarget; }
} Map<String, String> params = mTarget.getTaskWrapper().asHttp().getParams();
Map<String, String> params = mTarget.getTaskWrapper().asHttp().getParams(); if (params == null) {
if (params == null) { params = new HashMap<>();
params = new HashMap<>(); mTarget.getTaskWrapper().asHttp().setParams(params);
mTarget.getTaskWrapper().asHttp().setParams(params); }
} params.put(key, value);
params.put(key, value); if (mTarget instanceof DownloadGroupTarget) {
if (mTarget instanceof DownloadGroupTarget) { for (DTaskWrapper subTask : ((DGTaskWrapper) mTarget.getTaskWrapper()).getSubTaskWrapper()) {
for (DTaskWrapper subTask : ((DGTaskWrapper) mTarget.getTaskWrapper()).getSubTaskWrapper()) { subTask.asHttp().setParams(params);
subTask.asHttp().setParams(params); }
} }
} return mTarget;
return mTarget; }
}
@Override public void add() {
@Override public void add() { mTarget.add();
mTarget.add(); }
}
@Override public void start() {
@Override public void start() { mTarget.start();
mTarget.start(); }
}
@Override public void stop() {
@Override public void stop() { mTarget.stop();
mTarget.stop(); }
}
@Override public void resume() {
@Override public void resume() { mTarget.resume();
mTarget.resume(); }
}
@Override public void cancel() {
@Override public void cancel() { mTarget.cancel();
mTarget.cancel(); }
}
@Override public void save() {
@Override public void save() { mTarget.save();
mTarget.save(); }
}
@Override public void cancel(boolean removeFile) {
@Override public void cancel(boolean removeFile) { mTarget.cancel(removeFile);
mTarget.cancel(removeFile); }
}
@Override public void reTry() {
@Override public void reTry() { mTarget.reTry();
mTarget.reTry(); }
}
@Override public void reStart() {
@Override public void reStart() { mTarget.reStart();
mTarget.reStart(); }
} }
}

@ -17,10 +17,20 @@ package com.arialyy.aria.core.common.http;
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.download.DGTaskWrapper;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.inf.AbsHttpFileLenAdapter;
import com.arialyy.aria.core.inf.AbsTarget; import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.AbsTaskWrapper; import com.arialyy.aria.core.inf.AbsTaskWrapper;
import com.arialyy.aria.core.inf.IHttpFileLenAdapter;
import com.arialyy.aria.core.inf.IHttpHeaderDelegate; import com.arialyy.aria.core.inf.IHttpHeaderDelegate;
import com.arialyy.aria.core.upload.UTaskWrapper;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.net.Proxy; import java.net.Proxy;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
@ -80,7 +90,31 @@ public class HttpHeaderDelegate<TARGET extends AbsTarget>
return mTarget; return mTarget;
} }
public void addHeader(AbsTaskWrapper taskWrapper, String key, String value) { public TARGET setFileLenAdapter(AbsHttpFileLenAdapter adapter) {
if (adapter == null) {
throw new IllegalArgumentException("adapter为空");
}
try {
adapter.clone();
mTarget.getTaskWrapper().asHttp().setFileLenAdapter((IHttpFileLenAdapter) adapter.clone());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
//// 以下代码有问题,匿名内部类不能序列化
//String objPath = String.format("%s/obj_temp/%s", AriaManager.APP.getFilesDir().getPath(),
// adapter.hashCode());
//CommonUtil.writeObjToFile(objPath, adapter);
//IHttpFileLenAdapter newAdapter = (IHttpFileLenAdapter) CommonUtil.readObjFromFile(objPath);
//File temp = new File(objPath);
//if (temp.exists()) {
// temp.delete();
//}
//mTarget.getTaskWrapper().asHttp().setFileLenAdapter(newAdapter);
return mTarget;
}
private void addHeader(AbsTaskWrapper taskWrapper, String key, String value) {
HttpTaskDelegate taskDelegate = taskWrapper.asHttp(); HttpTaskDelegate taskDelegate = taskWrapper.asHttp();
if (taskDelegate.getHeaders().get(key) == null) { if (taskDelegate.getHeaders().get(key) == null) {
taskDelegate.getHeaders().put(key, value); taskDelegate.getHeaders().put(key, value);
@ -89,7 +123,7 @@ public class HttpHeaderDelegate<TARGET extends AbsTarget>
} }
} }
public void addHeaders(AbsTaskWrapper taskWrapper, Map<String, String> headers) { private void addHeaders(AbsTaskWrapper taskWrapper, Map<String, String> headers) {
HttpTaskDelegate taskDelegate = taskWrapper.asHttp(); HttpTaskDelegate taskDelegate = taskWrapper.asHttp();
/* /*
两个map比较逻辑 两个map比较逻辑

@ -1,187 +1,198 @@
/* /*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.common.http; package com.arialyy.aria.core.common.http;
import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.inf.ITargetHeadDelegate; import com.arialyy.aria.core.inf.IHttpFileLenAdapter;
import java.net.CookieManager; import com.arialyy.aria.core.inf.ITargetHeadDelegate;
import java.net.Proxy; import java.net.CookieManager;
import java.util.HashMap; import java.net.Proxy;
import java.util.Map; import java.util.HashMap;
import java.util.Map;
/**
* Http任务设置的信息cookie请求参数 /**
*/ * Http任务设置的信息cookie请求参数
public class HttpTaskDelegate implements ITargetHeadDelegate { */
public class HttpTaskDelegate implements ITargetHeadDelegate {
private CookieManager cookieManager;
private CookieManager cookieManager;
/**
* 请求参数 /**
*/ * 请求参数
private Map<String, String> params; */
private Map<String, String> params;
/**
* http 请求头 /**
*/ * http 请求头
private Map<String, String> headers = new HashMap<>(); */
private Map<String, String> headers = new HashMap<>();
/**
* 字符编码默认为"utf-8" /**
*/ * 字符编码默认为"utf-8"
private String charSet = "utf-8"; */
private String charSet = "utf-8";
/**
* 网络请求类型 /**
*/ * 网络请求类型
private RequestEnum requestEnum = RequestEnum.GET; */
private RequestEnum requestEnum = RequestEnum.GET;
/**
* 是否使用服务器通过content-disposition传递的文件名内容格式{@code attachment; filename="filename.jpg"} {@code true} /**
* 使用 * 是否使用服务器通过content-disposition传递的文件名内容格式{@code attachment; filename="filename.jpg"} {@code true}
*/ * 使用
private boolean useServerFileName = false; */
private boolean useServerFileName = false;
/**
* 重定向链接 /**
*/ * 重定向链接
private String redirectUrl = ""; */
private String redirectUrl = "";
/**
* 是否是chunk模式 /**
*/ * 是否是chunk模式
private boolean isChunked = false; */
/** private boolean isChunked = false;
* 文件上传需要的key /**
*/ * 文件上传需要的key
private String attachment; */
/** private String attachment;
* 上传的文件类型 /**
*/ * 上传的文件类型
private String contentType = "multipart/form-data"; */
private String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)"; private String contentType = "multipart/form-data";
private String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)";
private Proxy proxy;
/** private Proxy proxy;
* 文件上传表单 /**
*/ * 文件上传表单
private Map<String, String> formFields = new HashMap<>(); */
private Map<String, String> formFields = new HashMap<>();
public Map<String, String> getFormFields() {
return formFields; private IHttpFileLenAdapter fileLenAdapter;
}
public IHttpFileLenAdapter getFileLenAdapter() {
public void setFormFields(Map<String, String> formFields) { return fileLenAdapter;
this.formFields = formFields; }
}
public void setFileLenAdapter(IHttpFileLenAdapter fileLenAdapter) {
public String getAttachment() { this.fileLenAdapter = fileLenAdapter;
return attachment; }
}
public Map<String, String> getFormFields() {
public void setAttachment(String attachment) { return formFields;
this.attachment = attachment; }
}
public void setFormFields(Map<String, String> formFields) {
public String getContentType() { this.formFields = formFields;
return contentType; }
}
public String getAttachment() {
public void setContentType(String contentType) { return attachment;
this.contentType = contentType; }
}
public void setAttachment(String attachment) {
public String getUserAgent() { this.attachment = attachment;
return userAgent; }
}
public String getContentType() {
public void setUserAgent(String userAgent) { return contentType;
this.userAgent = userAgent; }
}
public void setContentType(String contentType) {
public boolean isChunked() { this.contentType = contentType;
return isChunked; }
}
public String getUserAgent() {
public void setChunked(boolean chunked) { return userAgent;
isChunked = chunked; }
}
public void setUserAgent(String userAgent) {
public CookieManager getCookieManager() { this.userAgent = userAgent;
return cookieManager; }
}
public boolean isChunked() {
public void setCookieManager(CookieManager cookieManager) { return isChunked;
this.cookieManager = cookieManager; }
}
public void setChunked(boolean chunked) {
public Proxy getProxy() { isChunked = chunked;
return proxy; }
}
public CookieManager getCookieManager() {
public void setProxy(Proxy proxy) { return cookieManager;
this.proxy = proxy; }
}
public void setCookieManager(CookieManager cookieManager) {
public Map<String, String> getHeaders() { this.cookieManager = cookieManager;
return headers; }
}
public Proxy getProxy() {
public void setHeaders(Map<String, String> headers) { return proxy;
this.headers = headers; }
}
public void setProxy(Proxy proxy) {
public String getCharSet() { this.proxy = proxy;
return charSet; }
}
public Map<String, String> getHeaders() {
public void setCharSet(String charSet) { return headers;
this.charSet = charSet; }
}
public void setHeaders(Map<String, String> headers) {
public RequestEnum getRequestEnum() { this.headers = headers;
return requestEnum; }
}
public String getCharSet() {
public void setRequestEnum(RequestEnum requestEnum) { return charSet;
this.requestEnum = requestEnum; }
}
public void setCharSet(String charSet) {
public boolean isUseServerFileName() { this.charSet = charSet;
return useServerFileName; }
}
public RequestEnum getRequestEnum() {
public void setUseServerFileName(boolean useServerFileName) { return requestEnum;
this.useServerFileName = useServerFileName; }
}
public void setRequestEnum(RequestEnum requestEnum) {
public String getRedirectUrl() { this.requestEnum = requestEnum;
return redirectUrl; }
}
public boolean isUseServerFileName() {
public void setRedirectUrl(String redirectUrl) { return useServerFileName;
this.redirectUrl = redirectUrl; }
}
public void setUseServerFileName(boolean useServerFileName) {
public Map<String, String> getParams() { this.useServerFileName = useServerFileName;
return params; }
}
public String getRedirectUrl() {
public void setParams(Map<String, String> params) { return redirectUrl;
this.params = params; }
}
} public void setRedirectUrl(String redirectUrl) {
this.redirectUrl = redirectUrl;
}
public Map<String, String> getParams() {
return params;
}
public void setParams(Map<String, String> params) {
this.params = params;
}
}

@ -1,171 +1,68 @@
/* /*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.support.annotation.CheckResult; import android.support.annotation.CheckResult;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTarget; import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.AbsTaskWrapper; import com.arialyy.aria.core.inf.AbsTaskWrapper;
import com.arialyy.aria.core.manager.SubTaskManager; import com.arialyy.aria.core.manager.SubTaskManager;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue; import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
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 java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* Created by lyy on 2017/7/26. * Created by lyy on 2017/7/26.
*/ */
abstract class AbsDGTarget<TARGET extends AbsDGTarget> extends AbsTarget<TARGET> { abstract class AbsDGTarget<TARGET extends AbsDGTarget> extends AbsTarget<TARGET> {
///** private SubTaskManager mSubTaskManager;
// * 组任务名
// */ /**
//String mGroupHash; * 获取子任务管理器
///** *
// * 文件夹临时路径 * @return 子任务管理器
// */ */
//String mDirPathTemp; @CheckResult
///** public SubTaskManager getSubTaskManager() {
// * 是否需要修改路径 if (mSubTaskManager == null) {
// */ mSubTaskManager = new SubTaskManager(getTargetName(), getTaskWrapper());
//boolean needModifyPath = false; }
return mSubTaskManager;
private SubTaskManager mSubTaskManager; }
/** @Override public DownloadGroupEntity getEntity() {
* 获取子任务管理器 return (DownloadGroupEntity) super.getEntity();
* }
* @return 子任务管理器
*/ @Override public DGTaskWrapper getTaskWrapper() {
@CheckResult return (DGTaskWrapper) super.getTaskWrapper();
public SubTaskManager getSubTaskManager() { }
if (mSubTaskManager == null) {
mSubTaskManager = new SubTaskManager(getTargetName(), getTaskWrapper()); /**
} * 设置任务组别名
return mSubTaskManager; */
} @CheckResult
public TARGET setGroupAlias(String alias) {
@Override public DownloadGroupEntity getEntity() { if (TextUtils.isEmpty(alias)) return (TARGET) this;
return (DownloadGroupEntity) super.getEntity(); getEntity().setAlias(alias);
} return (TARGET) this;
}
@Override public DGTaskWrapper getTaskWrapper() { }
return (DGTaskWrapper) super.getTaskWrapper();
}
/**
* 设置任务组别名
*/
@CheckResult
public TARGET setGroupAlias(String alias) {
if (TextUtils.isEmpty(alias)) return (TARGET) this;
getEntity().setAlias(alias);
return (TARGET) this;
}
//@Override public boolean taskExists() {
// return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", mGroupHash);
//}
///**
// * 设置任务组的文件夹路径,在Aria中,任务组的所有子任务都会下载到以任务组组名的文件夹中。
// * 如:groupDirPath = "/mnt/sdcard/download/group_test"
// * <pre>
// * {@code
// * + mnt
// * + sdcard
// * + download
// * + group_test
// * - task1.apk
// * - task2.apk
// * - task3.apk
// * ....
// *
// * }
// * </pre>
// *
// * @param dirPath 任务组保存文件夹路径
// */
//@CheckResult
//public TARGET setDirPath(String dirPath) {
// mDirPathTemp = dirPath;
// return (TARGET) this;
//}
//@Override public boolean isRunning() {
// DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(getEntity().getKey());
// return task != null && task.isRunning();
//}
///**
// * 改变任务组文件夹路径,修改文件夹路径会将子任务所有路径更换
// *
// * @param newDirPath 新的文件夹路径
// */
//void reChangeDirPath(String newDirPath) {
// List<DTaskWrapper> subTasks = getTaskWrapper().getSubTaskWrapper();
// if (subTasks != null && !subTasks.isEmpty()) {
// List<DbEntity> des = new ArrayList<>();
// for (DTaskWrapper dte : subTasks) {
// DownloadEntity de = dte.getEntity();
// String oldPath = de.getDownloadPath();
// String newPath = newDirPath + "/" + de.getFileName();
// File file = new File(oldPath);
// if (file.exists()) {
// file.renameTo(new File(newPath));
// }
// de.setDownloadPath(newPath);
// des.add(de);
// }
// AbsEntity.saveAll(des);
// }
//}
///**
// * 检查并设置文件夹路径
// *
// * @return {@code true} 合法
// */
//boolean checkDirPath() {
// if (TextUtils.isEmpty(mDirPathTemp)) {
// ALog.e(TAG, "文件夹路径不能为null");
// return false;
// } else if (!mDirPathTemp.startsWith("/")) {
// ALog.e(TAG, "文件夹路径【" + mDirPathTemp + "】错误");
// return false;
// }
// File file = new File(mDirPathTemp);
// if (file.isFile()) {
// ALog.e(TAG, "路径【" + mDirPathTemp + "】是文件,请设置文件夹路径");
// return false;
// }
//
// if (TextUtils.isEmpty(getEntity().getDirPath()) || !getEntity().getDirPath()
// .equals(mDirPathTemp)) {
// if (!file.exists()) {
// file.mkdirs();
// }
// needModifyPath = true;
// getEntity().setDirPath(mDirPathTemp);
// ALog.i(TAG, String.format("文件夹路径改变,将更新文件夹路径为:%s", mDirPathTemp));
// }
//
// return true;
//}
}

@ -134,7 +134,7 @@ class DownloadGroupListener
mTaskWrapper.setState(state); mTaskWrapper.setState(state);
mEntity.setState(state); mEntity.setState(state);
if (state == IEntity.STATE_CANCEL) { if (state == IEntity.STATE_CANCEL) {
CommonUtil.delGroupTaskRecord(mTaskWrapper.isRemoveFile(), mEntity); CommonUtil.delGroupTaskRecord(mEntity, mTaskWrapper.isRemoveFile());
return; return;
} else if (state == IEntity.STATE_STOP) { } else if (state == IEntity.STATE_STOP) {
mEntity.setStopTime(System.currentTimeMillis()); mEntity.setStopTime(System.currentTimeMillis());

@ -19,6 +19,8 @@ import android.support.annotation.CheckResult;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.arialyy.aria.core.common.http.HttpHeaderDelegate; import com.arialyy.aria.core.common.http.HttpHeaderDelegate;
import com.arialyy.aria.core.common.http.PostDelegate; import com.arialyy.aria.core.common.http.PostDelegate;
import com.arialyy.aria.core.inf.AbsHttpFileLenAdapter;
import com.arialyy.aria.core.inf.IHttpFileLenAdapter;
import com.arialyy.aria.core.inf.IHttpHeaderDelegate; import com.arialyy.aria.core.inf.IHttpHeaderDelegate;
import com.arialyy.aria.core.manager.TaskWrapperManager; import com.arialyy.aria.core.manager.TaskWrapperManager;
import com.arialyy.aria.exception.ParamException; import com.arialyy.aria.exception.ParamException;
@ -157,6 +159,13 @@ public class DownloadGroupTarget extends AbsDGTarget<DownloadGroupTarget> implem
return mGroupDelegate.setSubFileName(subTaskFileName); return mGroupDelegate.setSubFileName(subTaskFileName);
} }
/**
* 如果你需要使用header中特定的key来设置文件长度或有定制文件长度的需要那么你可以通过该方法自行处理文件长度
*/
public DownloadGroupTarget setFileLenAdapter(AbsHttpFileLenAdapter adapter) {
return mHeaderDelegate.setFileLenAdapter(adapter);
}
@Override public int getTargetType() { @Override public int getTargetType() {
return GROUP_HTTP; return GROUP_HTTP;
} }
@ -175,17 +184,11 @@ public class DownloadGroupTarget extends AbsDGTarget<DownloadGroupTarget> implem
@CheckResult @CheckResult
@Override public DownloadGroupTarget addHeader(@NonNull String key, @NonNull String value) { @Override public DownloadGroupTarget addHeader(@NonNull String key, @NonNull String value) {
for (DTaskWrapper subTask : getTaskWrapper().getSubTaskWrapper()) {
mHeaderDelegate.addHeader(subTask, key, value);
}
return mHeaderDelegate.addHeader(key, value); return mHeaderDelegate.addHeader(key, value);
} }
@CheckResult @CheckResult
@Override public DownloadGroupTarget addHeaders(Map<String, String> headers) { @Override public DownloadGroupTarget addHeaders(Map<String, String> headers) {
for (DTaskWrapper subTask : getTaskWrapper().getSubTaskWrapper()) {
mHeaderDelegate.addHeaders(subTask, headers);
}
return mHeaderDelegate.addHeaders(headers); return mHeaderDelegate.addHeaders(headers);
} }

@ -1,147 +1,156 @@
/* /*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.support.annotation.CheckResult; import android.support.annotation.CheckResult;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.arialyy.aria.core.common.http.GetDelegate; import com.arialyy.aria.core.common.http.GetDelegate;
import com.arialyy.aria.core.common.http.HttpHeaderDelegate; import com.arialyy.aria.core.common.http.HttpHeaderDelegate;
import com.arialyy.aria.core.common.http.PostDelegate; import com.arialyy.aria.core.common.http.PostDelegate;
import com.arialyy.aria.core.inf.IHttpHeaderDelegate; import com.arialyy.aria.core.inf.IHttpFileLenAdapter;
import java.net.Proxy; import com.arialyy.aria.core.inf.IHttpHeaderDelegate;
import java.util.Map; import java.net.Proxy;
import java.util.Map;
/**
* Created by lyy on 2016/12/5. /**
* https://github.com/AriaLyy/Aria * Created by lyy on 2016/12/5.
*/ * https://github.com/AriaLyy/Aria
public class DownloadTarget extends AbsDTarget<DownloadTarget> */
implements IHttpHeaderDelegate<DownloadTarget> { public class DownloadTarget extends AbsDTarget<DownloadTarget>
private HttpHeaderDelegate<DownloadTarget> mHeaderDelegate; implements IHttpHeaderDelegate<DownloadTarget> {
private DNormalDelegate<DownloadTarget> mNormalDelegate; private HttpHeaderDelegate<DownloadTarget> mHeaderDelegate;
private DNormalDelegate<DownloadTarget> mNormalDelegate;
DownloadTarget(DownloadEntity entity, String targetName) {
this(entity.getUrl(), targetName); DownloadTarget(DownloadEntity entity, String targetName) {
} this(entity.getUrl(), targetName);
}
DownloadTarget(String url, String targetName) {
mNormalDelegate = new DNormalDelegate<>(this, url, targetName); DownloadTarget(String url, String targetName) {
mHeaderDelegate = new HttpHeaderDelegate<>(this); mNormalDelegate = new DNormalDelegate<>(this, url, targetName);
} mHeaderDelegate = new HttpHeaderDelegate<>(this);
}
/**
* Post处理 /**
*/ * Post处理
@CheckResult */
public PostDelegate asPost() { @CheckResult
return new PostDelegate<>(this); public PostDelegate asPost() {
} return new PostDelegate<>(this);
}
/**
* get参数传递 /**
*/ * get参数传递
@CheckResult */
public GetDelegate asGet() { @CheckResult
return new GetDelegate<>(this); public GetDelegate asGet() {
} return new GetDelegate<>(this);
}
/**
* 是否使用服务器通过content-disposition传递的文件名内容格式{@code attachment;filename=***} /**
* 如果获取不到服务器文件名则使用用户设置的文件名 * 是否使用服务器通过content-disposition传递的文件名内容格式{@code attachment;filename=***}
* * 如果获取不到服务器文件名则使用用户设置的文件名
* @param use {@code true} 使用 *
*/ * @param use {@code true} 使用
@CheckResult */
public DownloadTarget useServerFileName(boolean use) { @CheckResult
getTaskWrapper().asHttp().setUseServerFileName(use); public DownloadTarget useServerFileName(boolean use) {
return this; getTaskWrapper().asHttp().setUseServerFileName(use);
} return this;
}
/**
* 设置文件存储路径如果需要修改新的文件名修改路径便可 /**
* 原文件路径 /mnt/sdcard/test.zip * 设置文件存储路径如果需要修改新的文件名修改路径便可
* 如果需要将test.zip改为game.zip只需要重新设置文件路径为/mnt/sdcard/game.zip * 原文件路径 /mnt/sdcard/test.zip
* * 如果需要将test.zip改为game.zip只需要重新设置文件路径为/mnt/sdcard/game.zip
* @param filePath 路径必须为文件路径不能为文件夹路径 *
*/ * @param filePath 路径必须为文件路径不能为文件夹路径
@CheckResult */
public DownloadTarget setFilePath(@NonNull String filePath) { @CheckResult
mNormalDelegate.setTempFilePath(filePath); public DownloadTarget setFilePath(@NonNull String filePath) {
return this; mNormalDelegate.setTempFilePath(filePath);
} return this;
}
/**
* 设置文件存储路径如果需要修改新的文件名修改路径便可 /**
* 原文件路径 /mnt/sdcard/test.zip * 设置文件存储路径如果需要修改新的文件名修改路径便可
* 如果需要将test.zip改为game.zip只需要重新设置文件路径为/mnt/sdcard/game.zip * 原文件路径 /mnt/sdcard/test.zip
* * 如果需要将test.zip改为game.zip只需要重新设置文件路径为/mnt/sdcard/game.zip
* @param filePath 路径必须为文件路径不能为文件夹路径 *
* @param forceDownload {@code true}强制下载不考虑文件路径是否被占用 * @param filePath 路径必须为文件路径不能为文件夹路径
*/ * @param forceDownload {@code true}强制下载不考虑文件路径是否被占用
@CheckResult */
public DownloadTarget setFilePath(@NonNull String filePath, boolean forceDownload) { @CheckResult
mNormalDelegate.setTempFilePath(filePath); public DownloadTarget setFilePath(@NonNull String filePath, boolean forceDownload) {
mNormalDelegate.setForceDownload(forceDownload); mNormalDelegate.setTempFilePath(filePath);
return this; mNormalDelegate.setForceDownload(forceDownload);
} return this;
}
/**
* 从header中获取文件描述信息 /**
*/ * 如果你需要使用header中特定的key来设置文件长度或有定制文件长度的需要那么你可以通过该方法自行处理文件长度
public String getContentDisposition() { */
return getEntity().getDisposition(); public DownloadTarget setFileLenAdapter(IHttpFileLenAdapter adapter) {
} //return mHeaderDelegate.setFileLenAdapter(adapter);
return this;
@Override public DownloadTarget updateUrl(String newUrl) { }
return mNormalDelegate.updateUrl(newUrl);
} /**
* 从header中获取文件描述信息
@Override public int getTargetType() { */
return HTTP; public String getContentDisposition() {
} return getEntity().getDisposition();
}
/**
* 设置URL的代理 @Override public DownloadTarget updateUrl(String newUrl) {
* return mNormalDelegate.updateUrl(newUrl);
* @param proxy {@link Proxy} }
*/
@CheckResult @Override public int getTargetType() {
@Override public DownloadTarget setUrlProxy(Proxy proxy) { return HTTP;
return mHeaderDelegate.setUrlProxy(proxy); }
}
/**
@CheckResult * 设置URL的代理
@Override public DownloadTarget addHeader(@NonNull String key, @NonNull String value) { *
return mHeaderDelegate.addHeader(key, value); * @param proxy {@link Proxy}
} */
@CheckResult
@CheckResult @Override public DownloadTarget setUrlProxy(Proxy proxy) {
@Override public DownloadTarget addHeaders(Map<String, String> headers) { return mHeaderDelegate.setUrlProxy(proxy);
return mHeaderDelegate.addHeaders(headers); }
}
@CheckResult
@Override protected boolean checkEntity() { @Override public DownloadTarget addHeader(@NonNull String key, @NonNull String value) {
return mNormalDelegate.checkEntity(); return mHeaderDelegate.addHeader(key, value);
} }
@Override public boolean isRunning() { @CheckResult
return mNormalDelegate.isRunning(); @Override public DownloadTarget addHeaders(Map<String, String> headers) {
} return mHeaderDelegate.addHeaders(headers);
}
@Override public boolean taskExists() {
return mNormalDelegate.taskExists(); @Override protected boolean checkEntity() {
} return mNormalDelegate.checkEntity();
} }
@Override public boolean isRunning() {
return mNormalDelegate.isRunning();
}
@Override public boolean taskExists() {
return mNormalDelegate.taskExists();
}
}

@ -38,8 +38,7 @@ class FtpFileInfoThread extends AbsFtpInfoThread<DownloadEntity, DTaskWrapper> {
@Override protected void handleFile(String remotePath, FTPFile ftpFile) { @Override protected void handleFile(String remotePath, FTPFile ftpFile) {
super.handleFile(remotePath, ftpFile); super.handleFile(remotePath, ftpFile);
if (!CommonUtil.checkSDMemorySpace(mEntity.getDownloadPath(), ftpFile.getSize())) { if (!CommonUtil.checkSDMemorySpace(mEntity.getDownloadPath(), ftpFile.getSize())) {
mCallback.onFail(mEntity.getUrl(), mCallback.onFail(mEntity, new AriaIOException(TAG,
new AriaIOException(TAG,
String.format("获取ftp文件信息失败,内存空间不足, filePath: %s", mEntity.getDownloadPath())), String.format("获取ftp文件信息失败,内存空间不足, filePath: %s", mEntity.getDownloadPath())),
false); false);
} }

@ -48,31 +48,31 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
FtpThreadTask(StateConstance constance, IDownloadListener listener, FtpThreadTask(StateConstance constance, IDownloadListener listener,
SubThreadConfig<DTaskWrapper> downloadInfo) { SubThreadConfig<DTaskWrapper> downloadInfo) {
super(constance, listener, downloadInfo); super(constance, listener, downloadInfo);
isOpenDynamicFile = STATE.TASK_RECORD.isOpenDynamicFile; isOpenDynamicFile = getState().TASK_RECORD.isOpenDynamicFile;
isBlock = STATE.TASK_RECORD.isBlock; isBlock = getState().TASK_RECORD.isBlock;
} }
@Override public FtpThreadTask call() throws Exception { @Override public FtpThreadTask call() throws Exception {
super.call(); super.call();
if (mConfig.THREAD_RECORD.isComplete) { if (getConfig().THREAD_RECORD.isComplete) {
handleComplete(); handleComplete();
return this; return this;
} }
mChildCurrentLocation = mConfig.START_LOCATION; mChildCurrentLocation = getConfig().START_LOCATION;
FTPClient client = null; FTPClient client = null;
InputStream is = null; InputStream is = null;
try { try {
ALog.d(TAG, ALog.d(TAG,
String.format("任务【%s】线程__%s__开始下载【开始位置 : %s,结束位置:%s】", mConfig.TEMP_FILE.getName(), String.format("任务【%s】线程__%s__开始下载【开始位置 : %s,结束位置:%s】", getConfig().TEMP_FILE.getName(),
mConfig.THREAD_ID, mConfig.START_LOCATION, mConfig.END_LOCATION)); getConfig().THREAD_ID, getConfig().START_LOCATION, getConfig().END_LOCATION));
client = createClient(); client = createClient();
if (client == null) { if (client == null) {
fail(mChildCurrentLocation, new TaskException(TAG, "ftp client 创建失败")); fail(mChildCurrentLocation, new TaskException(TAG, "ftp client 创建失败"));
return this; return this;
} }
if (mConfig.START_LOCATION > 0) { if (getConfig().START_LOCATION > 0) {
client.setRestartOffset(mConfig.START_LOCATION); client.setRestartOffset(getConfig().START_LOCATION);
} }
//发送第二次指令时,还需要再做一次判断 //发送第二次指令时,还需要再做一次判断
int reply = client.getReplyCode(); int reply = client.getReplyCode();
@ -84,7 +84,7 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
return this; return this;
} }
String remotePath = String remotePath =
new String(mTaskWrapper.asFtp().getUrlEntity().remotePath.getBytes(charSet), new String(getTaskWrapper().asFtp().getUrlEntity().remotePath.getBytes(charSet),
SERVER_CHARSET); SERVER_CHARSET);
ALog.i(TAG, String.format("remotePath【%s】", remotePath)); ALog.i(TAG, String.format("remotePath【%s】", remotePath));
is = client.retrieveFileStream(remotePath); is = client.retrieveFileStream(remotePath);
@ -105,10 +105,10 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
} }
} catch (IOException e) { } catch (IOException e) {
fail(mChildCurrentLocation, fail(mChildCurrentLocation,
new AriaIOException(TAG, String.format("下载失败【%s】", mConfig.URL), e)); new AriaIOException(TAG, String.format("下载失败【%s】", getConfig().URL), e));
} catch (Exception e) { } catch (Exception e) {
fail(mChildCurrentLocation, fail(mChildCurrentLocation,
new AriaIOException(TAG, String.format("下载失败【%s】", mConfig.URL), e)); new AriaIOException(TAG, String.format("下载失败【%s】", getConfig().URL), e));
} finally { } finally {
try { try {
if (is != null) { if (is != null) {
@ -135,28 +135,28 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
return; return;
} }
ALog.i(TAG, ALog.i(TAG,
String.format("任务【%s】线程__%s__下载完毕", mConfig.TEMP_FILE.getName(), mConfig.THREAD_ID)); String.format("任务【%s】线程__%s__下载完毕", getConfig().TEMP_FILE.getName(), getConfig().THREAD_ID));
writeConfig(true, mConfig.END_LOCATION); writeConfig(true, getConfig().END_LOCATION);
STATE.COMPLETE_THREAD_NUM++; getState().COMPLETE_THREAD_NUM++;
if (STATE.isComplete()) { if (getState().isComplete()) {
if (isBlock) { if (isBlock) {
boolean success = mergeFile(); boolean success = mergeFile();
if (!success) { if (!success) {
//ALog.e(TAG, String.format("任务【%s】分块文件合并失败", mConfig.TEMP_FILE.getName())); //ALog.e(TAG, String.format("任务【%s】分块文件合并失败", getConfig().TEMP_FILE.getName()));
STATE.isRunning = false; getState().isRunning = false;
mListener.onFail(false, mListener.onFail(false,
new TaskException(TAG, String.format("任务【%s】分块文件合并失败", mConfig.TEMP_FILE.getName()))); new TaskException(TAG, String.format("任务【%s】分块文件合并失败", getConfig().TEMP_FILE.getName())));
return; return;
} }
} }
STATE.TASK_RECORD.deleteData(); getState().TASK_RECORD.deleteData();
STATE.isRunning = false; getState().isRunning = false;
mListener.onComplete(); mListener.onComplete();
} }
if (STATE.isFail()) { if (getState().isFail()) {
STATE.isRunning = false; getState().isRunning = false;
mListener.onFail(false, mListener.onFail(false,
new TaskException(TAG, String.format("任务【%s】下载失败", mConfig.TEMP_FILE.getName()))); new TaskException(TAG, String.format("任务【%s】下载失败", getConfig().TEMP_FILE.getName())));
} }
} }
@ -169,7 +169,7 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
ReadableByteChannel fic = null; ReadableByteChannel fic = null;
try { try {
int len; int len;
fos = new FileOutputStream(mConfig.TEMP_FILE, true); fos = new FileOutputStream(getConfig().TEMP_FILE, true);
foc = fos.getChannel(); foc = fos.getChannel();
fic = Channels.newChannel(is); fic = Channels.newChannel(is);
ByteBuffer bf = ByteBuffer.allocate(getTaskConfig().getBuffSize()); ByteBuffer bf = ByteBuffer.allocate(getTaskConfig().getBuffSize());
@ -180,8 +180,8 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
if (mSpeedBandUtil != null) { if (mSpeedBandUtil != null) {
mSpeedBandUtil.limitNextBytes(len); mSpeedBandUtil.limitNextBytes(len);
} }
if (mChildCurrentLocation + len >= mConfig.END_LOCATION) { if (mChildCurrentLocation + len >= getConfig().END_LOCATION) {
len = (int) (mConfig.END_LOCATION - mChildCurrentLocation); len = (int) (getConfig().END_LOCATION - mChildCurrentLocation);
bf.flip(); bf.flip();
fos.write(bf.array(), 0, len); fos.write(bf.array(), 0, len);
bf.compact(); bf.compact();
@ -197,7 +197,7 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
handleComplete(); handleComplete();
} catch (IOException e) { } catch (IOException e) {
fail(mChildCurrentLocation, fail(mChildCurrentLocation,
new AriaIOException(TAG, String.format("下载失败【%s】", mConfig.URL), e)); new AriaIOException(TAG, String.format("下载失败【%s】", getConfig().URL), e));
} finally { } finally {
try { try {
if (fos != null) { if (fos != null) {
@ -221,8 +221,8 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
private void readNormal(InputStream is) { private void readNormal(InputStream is) {
BufferedRandomAccessFile file = null; BufferedRandomAccessFile file = null;
try { try {
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", getTaskConfig().getBuffSize()); file = new BufferedRandomAccessFile(getConfig().TEMP_FILE, "rwd", getTaskConfig().getBuffSize());
file.seek(mConfig.START_LOCATION); file.seek(getConfig().START_LOCATION);
byte[] buffer = new byte[getTaskConfig().getBuffSize()]; byte[] buffer = new byte[getTaskConfig().getBuffSize()];
int len; int len;
while (isLive() && (len = is.read(buffer)) != -1) { while (isLive() && (len = is.read(buffer)) != -1) {
@ -232,8 +232,8 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
if (mSpeedBandUtil != null) { if (mSpeedBandUtil != null) {
mSpeedBandUtil.limitNextBytes(len); mSpeedBandUtil.limitNextBytes(len);
} }
if (mChildCurrentLocation + len >= mConfig.END_LOCATION) { if (mChildCurrentLocation + len >= getConfig().END_LOCATION) {
len = (int) (mConfig.END_LOCATION - mChildCurrentLocation); len = (int) (getConfig().END_LOCATION - mChildCurrentLocation);
file.write(buffer, 0, len); file.write(buffer, 0, len);
progress(len); progress(len);
break; break;
@ -244,7 +244,7 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
} }
} catch (IOException e) { } catch (IOException e) {
fail(mChildCurrentLocation, fail(mChildCurrentLocation,
new AriaIOException(TAG, String.format("下载失败【%s】", mConfig.URL), e)); new AriaIOException(TAG, String.format("下载失败【%s】", getConfig().URL), e));
} finally { } finally {
try { try {
if (file != null) { if (file != null) {
@ -261,6 +261,6 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DTaskWrapper> {
} }
@Override protected DownloadConfig getTaskConfig() { @Override protected DownloadConfig getTaskConfig() {
return mTaskWrapper.getConfig(); return getTaskWrapper().getConfig();
} }
} }

@ -25,6 +25,7 @@ import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.common.http.HttpTaskDelegate; import com.arialyy.aria.core.common.http.HttpTaskDelegate;
import com.arialyy.aria.core.inf.IHttpFileLenAdapter;
import com.arialyy.aria.exception.AriaIOException; import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.TaskException; import com.arialyy.aria.exception.TaskException;
@ -109,22 +110,11 @@ public class HttpFileInfoThread implements Runnable {
} }
} }
long len = conn.getContentLength(); IHttpFileLenAdapter lenAdapter = mTaskWrapper.asHttp().getFileLenAdapter();
if (len < 0) { if (lenAdapter == null) {
String temp = conn.getHeaderField("Content-Length"); lenAdapter = new FileLenAdapter();
len = TextUtils.isEmpty(temp) ? -1 : Long.parseLong(temp);
// 某些服务,如果设置了conn.setRequestProperty("Range", "bytes=" + 0 + "-");
// 会返回 Content-Range: bytes 0-225427911/225427913
if (len < 0) {
temp = conn.getHeaderField("Content-Range");
if (TextUtils.isEmpty(temp)) {
len = -1;
} else {
int start = temp.indexOf("/");
len = Long.parseLong(temp.substring(start + 1));
}
}
} }
long len = lenAdapter.handleFileLen(conn.getHeaderFields());
if (!CommonUtil.checkSDMemorySpace(mEntity.getDownloadPath(), len)) { if (!CommonUtil.checkSDMemorySpace(mEntity.getDownloadPath(), len)) {
failDownload(new TaskException(TAG, failDownload(new TaskException(TAG,
@ -288,7 +278,7 @@ public class HttpFileInfoThread implements Runnable {
if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null") || !newUrl.startsWith( if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null") || !newUrl.startsWith(
"http")) { "http")) {
if (onFileInfoCallback != null) { if (onFileInfoCallback != null) {
onFileInfoCallback.onFail(mEntity.getUrl(), new TaskException(TAG, "获取重定向链接失败"), false); onFileInfoCallback.onFail(mEntity, new TaskException(TAG, "获取重定向链接失败"), false);
} }
return; return;
} }
@ -327,7 +317,32 @@ public class HttpFileInfoThread implements Runnable {
private void failDownload(BaseException e, boolean needRetry) { private void failDownload(BaseException e, boolean needRetry) {
if (onFileInfoCallback != null) { if (onFileInfoCallback != null) {
onFileInfoCallback.onFail(mEntity.getUrl(), e, needRetry); onFileInfoCallback.onFail(mEntity, e, needRetry);
}
}
private static class FileLenAdapter implements IHttpFileLenAdapter {
@Override public long handleFileLen(Map<String, List<String>> headers) {
List<String> sLength = headers.get("Content-Length");
if (sLength == null || sLength.isEmpty()) {
return -1;
}
String temp = sLength.get(0);
long len = TextUtils.isEmpty(temp) ? -1 : Long.parseLong(temp);
// 某些服务,如果设置了conn.setRequestProperty("Range", "bytes=" + 0 + "-");
// 会返回 Content-Range: bytes 0-225427911/225427913
if (len < 0) {
List<String> sRange = headers.get("Content-Range");
if (sRange == null || sRange.isEmpty()) {
len = -1;
} else {
int start = temp.indexOf("/");
len = Long.parseLong(temp.substring(start + 1));
}
}
return len;
} }
} }
} }

@ -55,8 +55,8 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
HttpThreadTask(StateConstance constance, IDownloadListener listener, HttpThreadTask(StateConstance constance, IDownloadListener listener,
SubThreadConfig<DTaskWrapper> downloadInfo) { SubThreadConfig<DTaskWrapper> downloadInfo) {
super(constance, listener, downloadInfo); super(constance, listener, downloadInfo);
isOpenDynamicFile = STATE.TASK_RECORD.isOpenDynamicFile; isOpenDynamicFile = getState().TASK_RECORD.isOpenDynamicFile;
isBlock = STATE.TASK_RECORD.isBlock; isBlock = getState().TASK_RECORD.isBlock;
} }
@Override public HttpThreadTask call() throws Exception { @Override public HttpThreadTask call() throws Exception {
@ -69,17 +69,17 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
BufferedInputStream is = null; BufferedInputStream is = null;
BufferedRandomAccessFile file = null; BufferedRandomAccessFile file = null;
//当前子线程的下载位置 //当前子线程的下载位置
mChildCurrentLocation = mConfig.START_LOCATION; mChildCurrentLocation = getConfig().START_LOCATION;
try { try {
HttpTaskDelegate taskDelegate = mTaskWrapper.asHttp(); HttpTaskDelegate taskDelegate = getTaskWrapper().asHttp();
URL url = ConnectionHelp.handleUrl(mConfig.URL, taskDelegate); URL url = ConnectionHelp.handleUrl(getConfig().URL, taskDelegate);
conn = ConnectionHelp.handleConnection(url, taskDelegate); conn = ConnectionHelp.handleConnection(url, taskDelegate);
if (mConfig.SUPPORT_BP) { if (getConfig().SUPPORT_BP) {
ALog.d(TAG, ALog.d(TAG,
String.format("任务【%s】线程__%s__开始下载【开始位置 : %s,结束位置:%s】", mConfig.TEMP_FILE.getName(), String.format("任务【%s】线程__%s__开始下载【开始位置 : %s,结束位置:%s】", getConfig().TEMP_FILE.getName(),
mConfig.THREAD_ID, mConfig.START_LOCATION, mConfig.END_LOCATION)); getConfig().THREAD_ID, getConfig().START_LOCATION, getConfig().END_LOCATION));
conn.setRequestProperty("Range", conn.setRequestProperty("Range", String.format("bytes=%s-%s", getConfig().START_LOCATION,
String.format("bytes=%s-%s", mConfig.START_LOCATION, (mConfig.END_LOCATION - 1))); (getConfig().END_LOCATION - 1)));
} else { } else {
ALog.w(TAG, "该下载不支持断点"); ALog.w(TAG, "该下载不支持断点");
} }
@ -117,24 +117,25 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
} else { } else {
//创建可设置位置的文件 //创建可设置位置的文件
file = file =
new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", getTaskConfig().getBuffSize()); new BufferedRandomAccessFile(getConfig().TEMP_FILE, "rwd",
getTaskConfig().getBuffSize());
//设置每条线程写入文件的位置 //设置每条线程写入文件的位置
file.seek(mConfig.START_LOCATION); file.seek(getConfig().START_LOCATION);
readNormal(is, file); readNormal(is, file);
handleComplete(); handleComplete();
} }
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
fail(mChildCurrentLocation, new TaskException(TAG, fail(mChildCurrentLocation, new TaskException(TAG,
String.format("任务【%s】下载失败,filePath: %s, url: %s", mConfig.TEMP_FILE.getName(), String.format("任务【%s】下载失败,filePath: %s, url: %s", getConfig().TEMP_FILE.getName(),
mEntity.getDownloadPath(), mEntity.getUrl()), e)); getEntity().getDownloadPath(), getEntity().getUrl()), e));
} catch (IOException e) { } catch (IOException e) {
fail(mChildCurrentLocation, new TaskException(TAG, fail(mChildCurrentLocation, new TaskException(TAG,
String.format("任务【%s】下载失败,filePath: %s, url: %s", mConfig.TEMP_FILE.getName(), String.format("任务【%s】下载失败,filePath: %s, url: %s", getConfig().TEMP_FILE.getName(),
mEntity.getDownloadPath(), mEntity.getUrl()), e)); getEntity().getDownloadPath(), getEntity().getUrl()), e));
} catch (Exception e) { } catch (Exception e) {
fail(mChildCurrentLocation, new TaskException(TAG, fail(mChildCurrentLocation, new TaskException(TAG,
String.format("任务【%s】下载失败,filePath: %s, url: %s", mConfig.TEMP_FILE.getName(), String.format("任务【%s】下载失败,filePath: %s, url: %s", getConfig().TEMP_FILE.getName(),
mEntity.getDownloadPath(), mEntity.getUrl()), e)); getEntity().getDownloadPath(), getEntity().getUrl()), e));
} finally { } finally {
try { try {
if (file != null) { if (file != null) {
@ -159,7 +160,7 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
private void readChunked(InputStream is) { private void readChunked(InputStream is) {
FileOutputStream fos = null; FileOutputStream fos = null;
try { try {
fos = new FileOutputStream(mConfig.TEMP_FILE, true); fos = new FileOutputStream(getConfig().TEMP_FILE, true);
byte[] buffer = new byte[getTaskConfig().getBuffSize()]; byte[] buffer = new byte[getTaskConfig().getBuffSize()];
int len; int len;
while (isLive() && (len = is.read(buffer)) != -1) { while (isLive() && (len = is.read(buffer)) != -1) {
@ -175,7 +176,7 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
handleComplete(); handleComplete();
} catch (IOException e) { } catch (IOException e) {
fail(mChildCurrentLocation, new AriaIOException(TAG, fail(mChildCurrentLocation, new AriaIOException(TAG,
String.format("文件下载失败,savePath: %s, url: %s", mEntity.getDownloadPath(), mConfig.URL), String.format("文件下载失败,savePath: %s, url: %s", getEntity().getDownloadPath(), getConfig().URL),
e)); e));
} finally { } finally {
if (fos != null) { if (fos != null) {
@ -197,7 +198,7 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
ReadableByteChannel fic = null; ReadableByteChannel fic = null;
try { try {
int len; int len;
fos = new FileOutputStream(mConfig.TEMP_FILE, true); fos = new FileOutputStream(getConfig().TEMP_FILE, true);
foc = fos.getChannel(); foc = fos.getChannel();
fic = Channels.newChannel(is); fic = Channels.newChannel(is);
ByteBuffer bf = ByteBuffer.allocate(getTaskConfig().getBuffSize()); ByteBuffer bf = ByteBuffer.allocate(getTaskConfig().getBuffSize());
@ -210,8 +211,8 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
if (mSpeedBandUtil != null) { if (mSpeedBandUtil != null) {
mSpeedBandUtil.limitNextBytes(len); mSpeedBandUtil.limitNextBytes(len);
} }
if (mChildCurrentLocation + len >= mConfig.END_LOCATION) { if (mChildCurrentLocation + len >= getConfig().END_LOCATION) {
len = (int) (mConfig.END_LOCATION - mChildCurrentLocation); len = (int) (getConfig().END_LOCATION - mChildCurrentLocation);
bf.flip(); bf.flip();
fos.write(bf.array(), 0, len); fos.write(bf.array(), 0, len);
bf.compact(); bf.compact();
@ -227,7 +228,7 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
handleComplete(); handleComplete();
} catch (IOException e) { } catch (IOException e) {
fail(mChildCurrentLocation, new AriaIOException(TAG, fail(mChildCurrentLocation, new AriaIOException(TAG,
String.format("文件下载失败,savePath: %s, url: %s", mEntity.getDownloadPath(), mConfig.URL), String.format("文件下载失败,savePath: %s, url: %s", getEntity().getDownloadPath(), getConfig().URL),
e)); e));
} finally { } finally {
try { try {
@ -276,48 +277,49 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
if (!checkBlock()) { if (!checkBlock()) {
return; return;
} }
if (mTaskWrapper.asHttp().isChunked()) { if (getTaskWrapper().asHttp().isChunked()) {
ALog.i(TAG, "任务下载完成"); ALog.i(TAG, "任务下载完成");
STATE.isRunning = false; getState().isRunning = false;
mListener.onComplete(); mListener.onComplete();
return; return;
} }
if (mChildCurrentLocation == mConfig.END_LOCATION) { if (mChildCurrentLocation == getConfig().END_LOCATION) {
//支持断点的处理 //支持断点的处理
if (mConfig.SUPPORT_BP) { if (getConfig().SUPPORT_BP) {
ALog.i(TAG, ALog.i(TAG,
String.format("任务【%s】线程__%s__下载完毕", mConfig.TEMP_FILE.getName(), mConfig.THREAD_ID)); String.format("任务【%s】线程__%s__下载完毕", getConfig().TEMP_FILE.getName(),
writeConfig(true, mConfig.END_LOCATION); getConfig().THREAD_ID));
STATE.COMPLETE_THREAD_NUM++; writeConfig(true, getConfig().END_LOCATION);
if (STATE.isComplete()) { getState().COMPLETE_THREAD_NUM++;
if (getState().isComplete()) {
if (isBlock) { if (isBlock) {
boolean success = mergeFile(); boolean success = mergeFile();
if (!success) { if (!success) {
STATE.isRunning = false; getState().isRunning = false;
mListener.onFail(false, new TaskException(TAG, mListener.onFail(false, new TaskException(TAG,
String.format("任务【%s】分块文件合并失败", mConfig.TEMP_FILE.getName()))); String.format("任务【%s】分块文件合并失败", getConfig().TEMP_FILE.getName())));
return; return;
} }
} }
STATE.TASK_RECORD.deleteData(); getState().TASK_RECORD.deleteData();
STATE.isRunning = false; getState().isRunning = false;
mListener.onComplete(); mListener.onComplete();
} }
if (STATE.isFail()) { if (getState().isFail()) {
STATE.isRunning = false; getState().isRunning = false;
mListener.onFail(false, mListener.onFail(false,
new TaskException(TAG, new TaskException(TAG,
String.format("任务【%s】下载失败,filePath: %s, url: %s", mConfig.TEMP_FILE.getName(), String.format("任务【%s】下载失败,filePath: %s, url: %s", getConfig().TEMP_FILE.getName(),
mEntity.getDownloadPath(), mEntity.getUrl()))); getEntity().getDownloadPath(), getEntity().getUrl())));
} }
} else { } else {
ALog.i(TAG, "任务下载完成"); ALog.i(TAG, "任务下载完成");
STATE.isRunning = false; getState().isRunning = false;
mListener.onComplete(); mListener.onComplete();
} }
} else { } else {
STATE.FAIL_NUM++; getState().FAIL_NUM++;
} }
} }
@ -326,6 +328,6 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
} }
@Override protected DownloadConfig getTaskConfig() { @Override protected DownloadConfig getTaskConfig() {
return mTaskWrapper.getConfig(); return getTaskWrapper().getConfig();
} }
} }

@ -20,6 +20,7 @@ import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback; import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskWrapper; import com.arialyy.aria.core.inf.AbsTaskWrapper;
import com.arialyy.aria.core.inf.IDownloadListener; import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
@ -131,7 +132,7 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
mDownloader.start(); mDownloader.start();
} }
@Override public void onFail(String url, BaseException e, boolean needRetry) { @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
failDownload(e, needRetry); failDownload(e, needRetry);
mDownloader.closeTimer(); mDownloader.closeTimer();
} }
@ -143,7 +144,7 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
mDownloader.start(); mDownloader.start();
} }
@Override public void onFail(String url, BaseException e, boolean needRetry) { @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
failDownload(e, needRetry); failDownload(e, needRetry);
mDownloader.closeTimer(); mDownloader.closeTimer();
} }

@ -18,6 +18,7 @@ package com.arialyy.aria.core.download.group;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.http.HttpTaskDelegate;
import com.arialyy.aria.core.config.Configuration; import com.arialyy.aria.core.config.Configuration;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DGTaskWrapper; import com.arialyy.aria.core.download.DGTaskWrapper;
@ -293,12 +294,31 @@ public abstract class AbsGroupUtil implements IUtil, Runnable {
/** /**
* 创建并启动子任务下载器 * 创建并启动子任务下载器
*
* @param needGetFileInfo {@code true} 需要获取文件信息{@code false} 不需要获取文件信息 * @param needGetFileInfo {@code true} 需要获取文件信息{@code false} 不需要获取文件信息
*/ */
SubDownloadLoader createSubLoader(DTaskWrapper taskWrapper, boolean needGetFileInfo) { SubDownloadLoader createSubLoader(DTaskWrapper taskWrapper, boolean needGetFileInfo) {
if (getTaskType() == HTTP_GROUP) {
cloneHeader(taskWrapper);
}
SubDownloadLoader loader = new SubDownloadLoader(mScheduler, taskWrapper, needGetFileInfo); SubDownloadLoader loader = new SubDownloadLoader(mScheduler, taskWrapper, needGetFileInfo);
mExeLoader.put(loader.getKey(), loader); mExeLoader.put(loader.getKey(), loader);
mSubQueue.startTask(loader); mSubQueue.startTask(loader);
return loader; return loader;
} }
/**
* 子任务使用父包裹器的属性
*/
private void cloneHeader(DTaskWrapper taskWrapper) {
HttpTaskDelegate groupDelegate = mGTWrapper.asHttp();
HttpTaskDelegate subDelegate = taskWrapper.asHttp();
// 设置属性
subDelegate.setFileLenAdapter(groupDelegate.getFileLenAdapter());
subDelegate.setRequestEnum(groupDelegate.getRequestEnum());
subDelegate.setHeaders(groupDelegate.getHeaders());
subDelegate.setProxy(groupDelegate.getProxy());
subDelegate.setParams(groupDelegate.getParams());
}
} }

@ -20,8 +20,11 @@ import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback; import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DGTaskWrapper; import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.downloader.HttpFileInfoThread; import com.arialyy.aria.core.download.downloader.HttpFileInfoThread;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -84,6 +87,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
private void getGroupSize() { private void getGroupSize() {
new Thread(new Runnable() { new Thread(new Runnable() {
int count; int count;
int failCount;
@Override public void run() { @Override public void run() {
for (DTaskWrapper dTaskWrapper : mGTWrapper.getSubTaskWrapper()) { for (DTaskWrapper dTaskWrapper : mGTWrapper.getSubTaskWrapper()) {
@ -91,13 +95,16 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
@Override public void onComplete(String url, CompleteInfo info) { @Override public void onComplete(String url, CompleteInfo info) {
createSubLoader((DTaskWrapper) info.wrapper, false); createSubLoader((DTaskWrapper) info.wrapper, false);
count++; count++;
checkGetSizeComplete(count); checkGetSizeComplete(count, failCount);
} }
@Override public void onFail(String url, BaseException e, boolean needRetry) { @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
ALog.e(TAG, String.format("获取文件信息失败,url:%s", url)); ALog.e(TAG, String.format("获取文件信息失败,url:%s", ((DownloadEntity) entity).getUrl()));
count++; count++;
checkGetSizeComplete(count); failCount++;
mListener.onSubFail((DownloadEntity) entity, new AriaIOException(TAG,
String.format("子任务获取文件长度失败,url:%s", ((DownloadEntity) entity).getUrl())));
checkGetSizeComplete(count, failCount);
} }
})); }));
} }
@ -108,17 +115,20 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
/** /**
* 检查组合任务大小是否获取完成获取完成后取消阻塞并设置组合任务大小 * 检查组合任务大小是否获取完成获取完成后取消阻塞并设置组合任务大小
*/ */
private void checkGetSizeComplete(int count) { private void checkGetSizeComplete(int count, int failCount) {
if (count == mGTWrapper.getSubTaskWrapper().size()) { if (count == mGTWrapper.getSubTaskWrapper().size()) {
long size = 0; long size = 0;
for (DTaskWrapper wrapper : mGTWrapper.getSubTaskWrapper()) { for (DTaskWrapper wrapper : mGTWrapper.getSubTaskWrapper()) {
size += wrapper.getEntity().getFileSize(); size += wrapper.getEntity().getFileSize();
} }
mGTWrapper.getEntity().setFileSize(size); mGTWrapper.getEntity().setFileSize(size);
mGTWrapper.getEntity().update();
} else if (failCount == mGTWrapper.getSubTaskWrapper().size()) {
mListener.onFail(true, new AriaIOException(TAG, "获取子任务长度失败"));
}
synchronized (LOCK) { synchronized (LOCK) {
LOCK.notify(); LOCK.notify();
}
} }
} }
} }

@ -19,6 +19,7 @@ import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.OnFileInfoCallback; import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DGTaskWrapper; import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.BaseException;
@ -49,7 +50,7 @@ public class FtpDirDownloadUtil extends AbsGroupUtil {
} }
} }
@Override public void onFail(String url, BaseException e, boolean needRetry) { @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
mListener.onFail(needRetry, e); mListener.onFail(needRetry, e);
} }
}).start(); }).start();

@ -24,6 +24,7 @@ import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.downloader.Downloader; import com.arialyy.aria.core.download.downloader.Downloader;
import com.arialyy.aria.core.download.downloader.HttpFileInfoThread; import com.arialyy.aria.core.download.downloader.HttpFileInfoThread;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskWrapper; import com.arialyy.aria.core.inf.AbsTaskWrapper;
import com.arialyy.aria.core.scheduler.ISchedulers; import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.BaseException;
@ -104,7 +105,7 @@ class SubDownloadLoader implements IUtil {
mDownloader.start(); mDownloader.start();
} }
@Override public void onFail(String url, BaseException e, boolean needRetry) { @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
mSchedulers.obtainMessage(ISchedulers.FAIL, SubDownloadLoader.this); mSchedulers.obtainMessage(ISchedulers.FAIL, SubDownloadLoader.this);
} }
})).start(); })).start();

@ -0,0 +1,10 @@
package com.arialyy.aria.core.inf;
public abstract class AbsHttpFileLenAdapter implements IHttpFileLenAdapter {
@Override public Object clone() throws CloneNotSupportedException {
//AbsHttpFileLenAdapter newAdapter = super.clone();
return super.clone();
}
}

@ -1,348 +1,340 @@
/* /*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.inf;
import android.support.annotation.CheckResult; 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;
import com.arialyy.aria.core.command.normal.CancelCmd; import com.arialyy.aria.core.command.normal.CancelCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory; import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.TaskRecord; import com.arialyy.aria.core.download.DGTaskWrapper;
import com.arialyy.aria.core.download.DGTaskWrapper; import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.manager.TaskWrapperManager;
import com.arialyy.aria.core.manager.TaskWrapperManager; import com.arialyy.aria.core.upload.UTaskWrapper;
import com.arialyy.aria.core.upload.UTaskWrapper; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.ALog; import java.util.ArrayList;
import com.arialyy.aria.util.CommonUtil; import java.util.List;
import java.util.ArrayList;
import java.util.List; /**
* Created by AriaL on 2017/7/3.
/** */
* Created by AriaL on 2017/7/3. public abstract class AbsTarget<TARGET extends AbsTarget> implements ITargetHandler {
*/
public abstract class AbsTarget<TARGET extends AbsTarget> implements ITargetHandler { protected String TAG;
private AbsEntity mEntity;
protected String TAG; private AbsTaskWrapper mTaskWrapper;
private AbsEntity mEntity; private String mTargetName;
private AbsTaskWrapper mTaskWrapper;
private String mTargetName; protected AbsTarget() {
TAG = CommonUtil.getClassName(this);
protected AbsTarget() { }
TAG = CommonUtil.getClassName(this);
} public void setTaskWrapper(AbsTaskWrapper wrapper) {
mTaskWrapper = wrapper;
public void setTaskWrapper(AbsTaskWrapper wrapper) { mEntity = wrapper.getEntity();
mTaskWrapper = wrapper; }
mEntity = wrapper.getEntity();
} /**
* 重置状态将任务状态设置为未开始状态
/** * 注意如果在后续方法调用链中没有调用 {@link #start()}{@link #stop()}{@link #cancel()}{@link #resume()}
* 重置状态将任务状态设置为未开始状态 * 等操作任务的方法那么你需要调用{@link #save()}才能将修改保存到数据库
* 注意如果在后续方法调用链中没有调用 {@link #start()}{@link #stop()}{@link #cancel()}{@link #resume()} */
* 等操作任务的方法那么你需要调用{@link #save()}才能将修改保存到数据库 @CheckResult(suggest = "after use #start()、#stop()、#cancel()、#resume()、#save()?")
*/ public TARGET resetState() {
@CheckResult(suggest = "after use #start()、#stop()、#cancel()、#resume()、#save()?") mTaskWrapper.getEntity().setState(IEntity.STATE_WAIT);
public TARGET resetState() { mTaskWrapper.setRefreshInfo(true);
mTaskWrapper.getEntity().setState(IEntity.STATE_WAIT); return (TARGET) this;
mTaskWrapper.setRefreshInfo(true); }
return (TARGET) this;
} /**
* 删除记录如果任务正在执行则会删除正在下载的任务
/** */
* 删除记录如果任务正在执行则会删除正在下载的任务 public void removeRecord() {
*/ if (isRunning()) {
public void removeRecord() { ALog.d("AbsTarget", "任务正在下载,即将删除任务");
if (isRunning()) { cancel();
ALog.d("AbsTarget", "任务正在下载,即将删除任务"); } else {
cancel(); if (mEntity instanceof AbsNormalEntity) {
} else { CommonUtil.delTaskRecord((AbsNormalEntity) mEntity, mTaskWrapper.isRemoveFile());
if (mEntity instanceof AbsNormalEntity) { } else if (mEntity instanceof DownloadGroupEntity) {
TaskRecord record = CommonUtil.delGroupTaskRecord(((DownloadGroupEntity) mEntity), mTaskWrapper.isRemoveFile());
DbEntity.findFirst(TaskRecord.class, "TaskRecord.filePath=?", mTaskWrapper.getKey()); }
if (record != null) { TaskWrapperManager.getInstance().removeTaskWrapper(mEntity.getKey());
CommonUtil.delTaskRecord(record, mTaskWrapper.isRemoveFile(), (AbsNormalEntity) mEntity); }
} else { }
mEntity.deleteData();
} public AbsEntity getEntity() {
} else if (mEntity instanceof DownloadGroupEntity) { return mEntity;
CommonUtil.delGroupTaskRecord(mTaskWrapper.isRemoveFile(), ((DownloadGroupEntity) mEntity)); }
}
TaskWrapperManager.getInstance().removeTaskWrapper(mEntity.getKey()); public String getTargetName() {
} return mTargetName;
} }
public AbsEntity getEntity() { public void setTargetName(String mTargetName) {
return mEntity; this.mTargetName = mTargetName;
} }
public String getTargetName() { /**
return mTargetName; * 获取任务实体
} */
public AbsTaskWrapper getTaskWrapper() {
public void setTargetName(String mTargetName) { return mTaskWrapper;
this.mTargetName = mTargetName; }
}
/**
/** * 获取任务进度如果任务存在则返回当前进度
* 获取任务实体 *
*/ * @return 该任务进度
public AbsTaskWrapper getTaskWrapper() { */
return mTaskWrapper; public long getCurrentProgress() {
} return mEntity == null ? -1 : mEntity.getCurrentProgress();
}
/**
* 获取任务进度如果任务存在则返回当前进度 /**
* * 获取任务文件大小
* @return 该任务进度 *
*/ * @return 文件大小
public long getCurrentProgress() { */
return mEntity == null ? -1 : mEntity.getCurrentProgress(); public long getFileSize() {
} return mEntity == null ? 0 : mEntity.getFileSize();
}
/**
* 获取任务文件大小 /**
* * 获取单位转换后的文件大小
* @return 文件大小 *
*/ * @return 文件大小{@code xxx mb}
public long getFileSize() { */
return mEntity == null ? 0 : mEntity.getFileSize(); public String getConvertFileSize() {
} return mEntity == null ? "0b" : CommonUtil.formatFileSize(mEntity.getFileSize());
}
/**
* 获取单位转换后的文件大小 /**
* * 设置扩展字段用来保存你的其它数据如果你的数据比较多你可以把你的数据转换为JSON字符串然后再存到Aria中
* @return 文件大小{@code xxx mb} * 注意如果在后续方法调用链中没有调用 {@link #start()}{@link #stop()}{@link #cancel()}{@link #resume()}
*/ * 等操作任务的方法那么你需要调用{@link #save()}才能将修改保存到数据库
public String getConvertFileSize() { *
return mEntity == null ? "0b" : CommonUtil.formatFileSize(mEntity.getFileSize()); * @param str 扩展数据
} */
@CheckResult(suggest = "after use #start()、#stop()、#cancel()、#resume()、#save()?")
/** public TARGET setExtendField(String str) {
* 设置扩展字段用来保存你的其它数据如果你的数据比较多你可以把你的数据转换为JSON字符串然后再存到Aria中 if (TextUtils.isEmpty(str)) return (TARGET) this;
* 注意如果在后续方法调用链中没有调用 {@link #start()}{@link #stop()}{@link #cancel()}{@link #resume()} if (TextUtils.isEmpty(mEntity.getStr()) || !mEntity.getStr().equals(str)) {
* 等操作任务的方法那么你需要调用{@link #save()}才能将修改保存到数据库 mEntity.setStr(str);
* } else {
* @param str 扩展数据 ALog.e(TAG, "设置扩展字段失败,扩展字段为一致");
*/ }
@CheckResult(suggest = "after use #start()、#stop()、#cancel()、#resume()、#save()?")
public TARGET setExtendField(String str) { return (TARGET) this;
if (TextUtils.isEmpty(str)) return (TARGET) this; }
if (TextUtils.isEmpty(mEntity.getStr()) || !mEntity.getStr().equals(str)) {
mEntity.setStr(str); /**
} else { * 获取存放的扩展字段
ALog.e(TAG, "设置扩展字段失败,扩展字段为一致"); * 设置扩展字段{@link #setExtendField(String)}
} */
public String getExtendField() {
return (TARGET) this; return mEntity.getStr();
} }
/** /**
* 获取存放的扩展字段 * 获取任务状态
* 设置扩展字段{@link #setExtendField(String)} *
*/ * @return {@link IEntity}
public String getExtendField() { */
return mEntity.getStr(); public int getTaskState() {
} return mEntity.getState();
}
/**
* 获取任务状态 /**
* * 获取任务进度百分比
* @return {@link IEntity} *
*/ * @return 返回任务进度
public int getTaskState() { */
return mEntity.getState(); public int getPercent() {
} if (mEntity == null) {
ALog.e("AbsTarget", "下载管理器中没有该任务");
/** return 0;
* 获取任务进度百分比 }
* if (mEntity.getFileSize() != 0) {
* @return 返回任务进度 return (int) (mEntity.getCurrentProgress() * 100 / mEntity.getFileSize());
*/ }
public int getPercent() { return 0;
if (mEntity == null) { }
ALog.e("AbsTarget", "下载管理器中没有该任务");
return 0; /**
} * 检查实体是否合法如果实体合法将保存实体到数据库或更新数据库中的实体对象
if (mEntity.getFileSize() != 0) { *
return (int) (mEntity.getCurrentProgress() * 100 / mEntity.getFileSize()); * @return {@code true} 合法
} */
return 0; protected abstract boolean checkEntity();
}
protected int checkTaskType() {
/** int taskType = 0;
* 检查实体是否合法如果实体合法将保存实体到数据库或更新数据库中的实体对象 if (mTaskWrapper instanceof DTaskWrapper) {
* taskType = ICmd.TASK_TYPE_DOWNLOAD;
* @return {@code true} 合法 } else if (mTaskWrapper instanceof DGTaskWrapper) {
*/ taskType = ICmd.TASK_TYPE_DOWNLOAD_GROUP;
protected abstract boolean checkEntity(); } else if (mTaskWrapper instanceof UTaskWrapper) {
taskType = ICmd.TASK_TYPE_UPLOAD;
protected int checkTaskType() { }
int taskType = 0; return taskType;
if (mTaskWrapper instanceof DTaskWrapper) { }
taskType = ICmd.TASK_TYPE_DOWNLOAD;
} else if (mTaskWrapper instanceof DGTaskWrapper) { /**
taskType = ICmd.TASK_TYPE_DOWNLOAD_GROUP; * 保存修改
} else if (mTaskWrapper instanceof UTaskWrapper) { */
taskType = ICmd.TASK_TYPE_UPLOAD; @Override public void save() {
} if (!checkEntity()) {
return taskType; ALog.e(TAG, "保存修改失败");
} } else {
ALog.i(TAG, "保存成功");
/** }
* 保存修改 }
*/
@Override public void save() { /**
if (!checkEntity()) { * 任务是否在执行
ALog.e(TAG, "保存修改失败"); *
} else { * @return {@code true} 任务正在执行
ALog.i(TAG, "保存成功"); */
} public abstract boolean isRunning();
}
/**
/** * 任务是否存在
* 任务是否在执行 *
* * @return {@code true} 任务存在
* @return {@code true} 任务正在执行 */
*/ public abstract boolean taskExists();
public abstract boolean isRunning();
/**
/** * 设置target类型
* 任务是否存在 *
* * @return {@link #HTTP}{@link #FTP}{@link #GROUP_HTTP}{@link #GROUP_FTP_DIR}
* @return {@code true} 任务存在 */
*/ public abstract int getTargetType();
public abstract boolean taskExists();
/**
/** * 添加任务
* 设置target类型 */
* @Override public void add() {
* @return {@link #HTTP}{@link #FTP}{@link #GROUP_HTTP}{@link #GROUP_FTP_DIR} if (checkEntity()) {
*/ AriaManager.getInstance(AriaManager.APP)
public abstract int getTargetType(); .setCmd(CommonUtil.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_CREATE,
checkTaskType()))
/** .exe();
* 添加任务 }
*/ }
@Override public void add() {
if (checkEntity()) { /**
AriaManager.getInstance(AriaManager.APP) * 开始任务
.setCmd(CommonUtil.createNormalCmd(getTaskWrapper(), NormalCmdFactory.TASK_CREATE, */
checkTaskType())) @Override public void start() {
.exe(); if (checkEntity()) {
} AriaManager.getInstance(AriaManager.APP)
} .setCmd(
CommonUtil.createNormalCmd(mTaskWrapper, NormalCmdFactory.TASK_START,
/** checkTaskType()))
* 开始任务 .exe();
*/ }
@Override public void start() { }
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP) /**
.setCmd( * 停止任务
CommonUtil.createNormalCmd(mTaskWrapper, NormalCmdFactory.TASK_START, *
checkTaskType())) * @see #stop()
.exe(); */
} @Deprecated public void pause() {
} if (checkEntity()) {
stop();
/** }
* 停止任务 }
*
* @see #stop() @Override public void stop() {
*/ if (checkEntity()) {
@Deprecated public void pause() { AriaManager.getInstance(AriaManager.APP)
if (checkEntity()) { .setCmd(
stop(); CommonUtil.createNormalCmd(mTaskWrapper, NormalCmdFactory.TASK_STOP, checkTaskType()))
} .exe();
} }
}
@Override public void stop() {
if (checkEntity()) { /**
AriaManager.getInstance(AriaManager.APP) * 恢复任务
.setCmd( */
CommonUtil.createNormalCmd(mTaskWrapper, NormalCmdFactory.TASK_STOP, checkTaskType())) @Override public void resume() {
.exe(); if (checkEntity()) {
} AriaManager.getInstance(AriaManager.APP)
} .setCmd(
CommonUtil.createNormalCmd(mTaskWrapper, NormalCmdFactory.TASK_START,
/** checkTaskType()))
* 恢复任务 .exe();
*/ }
@Override public void resume() { }
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP) /**
.setCmd( * 删除任务
CommonUtil.createNormalCmd(mTaskWrapper, NormalCmdFactory.TASK_START, */
checkTaskType())) @Override public void cancel() {
.exe(); if (checkEntity()) {
} AriaManager.getInstance(AriaManager.APP)
} .setCmd(CommonUtil.createNormalCmd(mTaskWrapper, NormalCmdFactory.TASK_CANCEL,
checkTaskType()))
/** .exe();
* 删除任务 }
*/ }
@Override public void cancel() {
if (checkEntity()) { /**
AriaManager.getInstance(AriaManager.APP) * 任务重试
.setCmd(CommonUtil.createNormalCmd(mTaskWrapper, NormalCmdFactory.TASK_CANCEL, */
checkTaskType())) @Override public void reTry() {
.exe(); if (checkEntity()) {
} List<ICmd> cmds = new ArrayList<>();
} int taskType = checkTaskType();
cmds.add(
/** CommonUtil.createNormalCmd(mTaskWrapper, NormalCmdFactory.TASK_STOP, taskType));
* 任务重试 cmds.add(CommonUtil.createNormalCmd(mTaskWrapper, NormalCmdFactory.TASK_START, taskType));
*/ AriaManager.getInstance(AriaManager.APP).setCmds(cmds).exe();
@Override public void reTry() { }
if (checkEntity()) { }
List<ICmd> cmds = new ArrayList<>();
int taskType = checkTaskType(); /**
cmds.add( * 删除任务
CommonUtil.createNormalCmd(mTaskWrapper, NormalCmdFactory.TASK_STOP, taskType)); *
cmds.add(CommonUtil.createNormalCmd(mTaskWrapper, NormalCmdFactory.TASK_START, taskType)); * @param removeFile {@code true} 不仅删除任务数据库记录还会删除已经删除完成的文件
AriaManager.getInstance(AriaManager.APP).setCmds(cmds).exe(); * {@code false}如果任务已经完成只删除任务数据库记录
} */
} @Override public void cancel(boolean removeFile) {
if (checkEntity()) {
/** CancelCmd cancelCmd =
* 删除任务 (CancelCmd) CommonUtil.createNormalCmd(mTaskWrapper, NormalCmdFactory.TASK_CANCEL,
* checkTaskType());
* @param removeFile {@code true} 不仅删除任务数据库记录还会删除已经删除完成的文件 cancelCmd.removeFile = removeFile;
* {@code false}如果任务已经完成只删除任务数据库记录 AriaManager.getInstance(AriaManager.APP).setCmd(cancelCmd).exe();
*/ }
@Override public void cancel(boolean removeFile) { }
if (checkEntity()) {
CancelCmd cancelCmd = /**
(CancelCmd) CommonUtil.createNormalCmd(mTaskWrapper, NormalCmdFactory.TASK_CANCEL, * 重新下载
checkTaskType()); */
cancelCmd.removeFile = removeFile; @Override public void reStart() {
AriaManager.getInstance(AriaManager.APP).setCmd(cancelCmd).exe(); if (checkEntity()) {
} cancel();
} start();
}
/** }
* 重新下载 }
*/
@Override public void reStart() {
if (checkEntity()) {
cancel();
start();
}
}
}

@ -0,0 +1,36 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.core.inf;
import java.io.Serializable;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
/**
* Http文件长度适配器
*/
public interface IHttpFileLenAdapter extends Serializable {
long serialVersionUID = 1L;
/**
* 同伙header中的数据获取文件长度
*
* @param headers header参数{@link URLConnection#getHeaderFields()}
* @return 文件长度
*/
long handleFileLen(Map<String, List<String>> headers);
}

@ -1,194 +1,194 @@
/* /*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.upload.uploader; package com.arialyy.aria.core.upload.uploader;
import aria.apache.commons.net.ftp.FTPClient; import aria.apache.commons.net.ftp.FTPClient;
import aria.apache.commons.net.ftp.FTPReply; import aria.apache.commons.net.ftp.FTPReply;
import aria.apache.commons.net.ftp.OnFtpInputStreamListener; import aria.apache.commons.net.ftp.OnFtpInputStreamListener;
import com.arialyy.aria.core.common.StateConstance; import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.common.ftp.AbsFtpThreadTask; import com.arialyy.aria.core.common.ftp.AbsFtpThreadTask;
import com.arialyy.aria.core.config.BaseTaskConfig; import com.arialyy.aria.core.config.BaseTaskConfig;
import com.arialyy.aria.core.config.DownloadConfig; import com.arialyy.aria.core.config.DownloadConfig;
import com.arialyy.aria.core.config.UploadConfig; import com.arialyy.aria.core.config.UploadConfig;
import com.arialyy.aria.core.inf.IEventListener; import com.arialyy.aria.core.inf.IEventListener;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UTaskWrapper; import com.arialyy.aria.core.upload.UTaskWrapper;
import com.arialyy.aria.exception.AriaIOException; import com.arialyy.aria.exception.AriaIOException;
import com.arialyy.aria.exception.TaskException; import com.arialyy.aria.exception.TaskException;
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.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
/** /**
* Created by Aria.Lao on 2017/7/28. FTP 单线程上传任务需要FTP 服务器给用户打开append和write的权限 * Created by Aria.Lao on 2017/7/28. FTP 单线程上传任务需要FTP 服务器给用户打开append和write的权限
*/ */
class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UTaskWrapper> { class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UTaskWrapper> {
private final String TAG = "FtpThreadTask"; private final String TAG = "FtpThreadTask";
private String dir, remotePath; private String dir, remotePath;
FtpThreadTask(StateConstance constance, IEventListener listener, FtpThreadTask(StateConstance constance, IEventListener listener,
SubThreadConfig<UTaskWrapper> info) { SubThreadConfig<UTaskWrapper> info) {
super(constance, listener, info); super(constance, listener, info);
} }
@Override public int getMaxSpeed() { @Override public int getMaxSpeed() {
return getTaskConfig().getMaxSpeed(); return getTaskConfig().getMaxSpeed();
} }
@Override protected UploadConfig getTaskConfig() { @Override protected UploadConfig getTaskConfig() {
return mTaskWrapper.getConfig(); return getTaskWrapper().getConfig();
} }
@Override public FtpThreadTask call() throws Exception { @Override public FtpThreadTask call() throws Exception {
super.call(); super.call();
//当前子线程的下载位置 //当前子线程的下载位置
mChildCurrentLocation = mConfig.START_LOCATION; mChildCurrentLocation = getConfig().START_LOCATION;
FTPClient client = null; FTPClient client = null;
BufferedRandomAccessFile file = null; BufferedRandomAccessFile file = null;
try { try {
ALog.d(TAG, ALog.d(TAG,
String.format("任务【%s】线程__%s__开始上传【开始位置 : %s,结束位置:%s】", mConfig.TEMP_FILE.getName(), String.format("任务【%s】线程__%s__开始上传【开始位置 : %s,结束位置:%s】", getConfig().TEMP_FILE.getName(),
mConfig.THREAD_ID, mConfig.START_LOCATION, mConfig.END_LOCATION)); getConfig().THREAD_ID, getConfig().START_LOCATION, getConfig().END_LOCATION));
client = createClient(); client = createClient();
if (client == null) { if (client == null) {
return this; return this;
} }
initPath(); initPath();
client.makeDirectory(dir); client.makeDirectory(dir);
client.changeWorkingDirectory(dir); client.changeWorkingDirectory(dir);
client.setRestartOffset(mConfig.START_LOCATION); client.setRestartOffset(getConfig().START_LOCATION);
int reply = client.getReplyCode(); int reply = client.getReplyCode();
if (!FTPReply.isPositivePreliminary(reply) && reply != FTPReply.FILE_ACTION_OK) { if (!FTPReply.isPositivePreliminary(reply) && reply != FTPReply.FILE_ACTION_OK) {
fail(mChildCurrentLocation, fail(mChildCurrentLocation,
new AriaIOException(TAG, new AriaIOException(TAG,
String.format("文件上传错误,错误码为:%s, msg:%s, filePath: %s", reply, String.format("文件上传错误,错误码为:%s, msg:%s, filePath: %s", reply,
client.getReplyString(), mEntity.getFilePath()))); client.getReplyString(), getEntity().getFilePath())));
client.disconnect(); client.disconnect();
return this; return this;
} }
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", getTaskConfig().getBuffSize()); file = new BufferedRandomAccessFile(getConfig().TEMP_FILE, "rwd", getTaskConfig().getBuffSize());
if (mConfig.START_LOCATION != 0) { if (getConfig().START_LOCATION != 0) {
//file.skipBytes((int) mConfig.START_LOCATION); //file.skipBytes((int) getConfig().START_LOCATION);
file.seek(mConfig.START_LOCATION); file.seek(getConfig().START_LOCATION);
} }
boolean complete = upload(client, file); boolean complete = upload(client, file);
if (!complete || isBreak()) { if (!complete || isBreak()) {
return this; return this;
} }
ALog.i(TAG, ALog.i(TAG,
String.format("任务【%s】线程__%s__上传完毕", mConfig.TEMP_FILE.getName(), mConfig.THREAD_ID)); String.format("任务【%s】线程__%s__上传完毕", getConfig().TEMP_FILE.getName(), getConfig().THREAD_ID));
writeConfig(true, mConfig.END_LOCATION); writeConfig(true, getConfig().END_LOCATION);
STATE.COMPLETE_THREAD_NUM++; getState().COMPLETE_THREAD_NUM++;
if (STATE.isComplete()) { if (getState().isComplete()) {
STATE.TASK_RECORD.deleteData(); getState().TASK_RECORD.deleteData();
STATE.isRunning = false; getState().isRunning = false;
mListener.onComplete(); mListener.onComplete();
} }
if (STATE.isFail()) { if (getState().isFail()) {
STATE.isRunning = false; getState().isRunning = false;
mListener.onFail(false, new TaskException(TAG, mListener.onFail(false, new TaskException(TAG,
String.format("上传失败,filePath: %s, uploadUrl: %s", mEntity.getFilePath(), mConfig.URL))); String.format("上传失败,filePath: %s, uploadUrl: %s", getEntity().getFilePath(), getConfig().URL)));
} }
} catch (IOException e) { } catch (IOException e) {
fail(mChildCurrentLocation, new AriaIOException(TAG, fail(mChildCurrentLocation, new AriaIOException(TAG,
String.format("上传失败,filePath: %s, uploadUrl: %s", mEntity.getFilePath(), mConfig.URL))); String.format("上传失败,filePath: %s, uploadUrl: %s", getEntity().getFilePath(), getConfig().URL)));
} catch (Exception e) { } catch (Exception e) {
fail(mChildCurrentLocation, new AriaIOException(TAG, null, e)); fail(mChildCurrentLocation, new AriaIOException(TAG, null, e));
} finally { } finally {
try { try {
if (file != null) { if (file != null) {
file.close(); file.close();
} }
if (client != null && client.isConnected()) { if (client != null && client.isConnected()) {
client.disconnect(); client.disconnect();
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
return this; return this;
} }
private void initPath() throws UnsupportedEncodingException { private void initPath() throws UnsupportedEncodingException {
dir = new String(mTaskWrapper.asFtp().getUrlEntity().remotePath.getBytes(charSet), dir = new String(getTaskWrapper().asFtp().getUrlEntity().remotePath.getBytes(charSet),
SERVER_CHARSET); SERVER_CHARSET);
remotePath = new String(String.format("%s/%s", mTaskWrapper.asFtp().getUrlEntity().remotePath, remotePath = new String(String.format("%s/%s", getTaskWrapper().asFtp().getUrlEntity().remotePath,
mEntity.getFileName()).getBytes(charSet), SERVER_CHARSET); getEntity().getFileName()).getBytes(charSet), SERVER_CHARSET);
} }
/** /**
* 上传 * 上传
* *
* @return {@code true}上传成功{@code false} 上传失败 * @return {@code true}上传成功{@code false} 上传失败
*/ */
private boolean upload(final FTPClient client, final BufferedRandomAccessFile bis) private boolean upload(final FTPClient client, final BufferedRandomAccessFile bis)
throws IOException { throws IOException {
try { try {
ALog.d(TAG, String.format("remotePath: %s", 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) {
try { try {
if (isBreak() && !isStoped) { if (isBreak() && !isStoped) {
isStoped = true; isStoped = true;
client.abor(); client.abor();
} }
if (mSpeedBandUtil != null) { if (mSpeedBandUtil != null) {
mSpeedBandUtil.limitNextBytes(bytesTransferred); mSpeedBandUtil.limitNextBytes(bytesTransferred);
} }
progress(bytesTransferred); progress(bytesTransferred);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
}); });
} catch (IOException e) { } catch (IOException e) {
String msg = String.format("文件上传错误,错误码为:%s, msg:%s, filePath: %s", client.getReplyCode(), String msg = String.format("文件上传错误,错误码为:%s, msg:%s, filePath: %s", client.getReplyCode(),
client.getReplyString(), mEntity.getFilePath()); client.getReplyString(), getEntity().getFilePath());
if (client.isConnected()) { if (client.isConnected()) {
client.disconnect(); client.disconnect();
} }
if (e.getMessage().contains("AriaIOException caught while copying")) { if (e.getMessage().contains("AriaIOException caught while copying")) {
e.printStackTrace(); e.printStackTrace();
} else { } else {
fail(mChildCurrentLocation, fail(mChildCurrentLocation,
new AriaIOException(TAG, msg, e)); new AriaIOException(TAG, msg, e));
} }
return false; return false;
} }
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, fail(mChildCurrentLocation,
new AriaIOException(TAG, new AriaIOException(TAG,
String.format("文件上传错误,错误码为:%s, msg:%s, filePath: %s", reply, String.format("文件上传错误,错误码为:%s, msg:%s, filePath: %s", reply,
client.getReplyString(), mEntity.getFilePath()))); client.getReplyString(), getEntity().getFilePath())));
} }
if (client.isConnected()) { if (client.isConnected()) {
client.disconnect(); client.disconnect();
} }
return false; return false;
} }
return true; return true;
} }
} }

@ -59,18 +59,18 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UTaskWrapper> {
@Override public HttpThreadTask call() throws Exception { @Override public HttpThreadTask call() throws Exception {
super.call(); super.call();
File uploadFile = new File(mEntity.getFilePath()); File uploadFile = new File(getEntity().getFilePath());
if (!uploadFile.exists()) { if (!uploadFile.exists()) {
fail(new TaskException(TAG, fail(new TaskException(TAG,
String.format("上传失败,文件不存在;filePath: %s, url: %s", mEntity.getFilePath(), String.format("上传失败,文件不存在;filePath: %s, url: %s", getEntity().getFilePath(),
mEntity.getUrl()))); getEntity().getUrl())));
return this; return this;
} }
mListener.onPre(); mListener.onPre();
URL url; URL url;
try { try {
url = new URL(mEntity.getUrl()); url = new URL(getEntity().getUrl());
HttpTaskDelegate taskDelegate = mTaskWrapper.asHttp(); HttpTaskDelegate taskDelegate = getTaskWrapper().asHttp();
mHttpConn = (HttpURLConnection) url.openConnection(); mHttpConn = (HttpURLConnection) url.openConnection();
mHttpConn.setRequestMethod(taskDelegate.getRequestEnum().name); mHttpConn.setRequestMethod(taskDelegate.getRequestEnum().name);
mHttpConn.setUseCaches(false); mHttpConn.setUseCaches(false);
@ -100,12 +100,13 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UTaskWrapper> {
addFormField(writer, key, taskDelegate.getFormFields().get(key)); addFormField(writer, key, taskDelegate.getFormFields().get(key));
} }
uploadFile(writer, taskDelegate.getAttachment(), uploadFile); uploadFile(writer, taskDelegate.getAttachment(), uploadFile);
mTaskWrapper.getEntity().setResponseStr(finish(writer)); getEntity().setResponseStr(finish(writer));
mListener.onComplete(); mListener.onComplete();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
fail(new TaskException(TAG, fail(new TaskException(TAG,
String.format("上传失败,filePath: %s, url: %s", mEntity.getFilePath(), mEntity.getUrl()), e)); String.format("上传失败,filePath: %s, url: %s", getEntity().getFilePath(),
getEntity().getUrl()), e));
} }
return this; return this;
} }
@ -113,7 +114,7 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UTaskWrapper> {
private void fail(BaseException e1) { private void fail(BaseException e1) {
try { try {
mListener.onFail(true, e1); mListener.onFail(true, e1);
STATE.isRunning = false; getState().isRunning = false;
if (mOutputStream != null) { if (mOutputStream != null) {
mOutputStream.close(); mOutputStream.close();
} }
@ -132,7 +133,7 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UTaskWrapper> {
.append("\"") .append("\"")
.append(LINE_END); .append(LINE_END);
writer.append("Content-Type: text/plain; charset=") writer.append("Content-Type: text/plain; charset=")
.append(mTaskWrapper.asHttp().getCharSet()) .append(getTaskWrapper().asHttp().getCharSet())
.append(LINE_END); .append(LINE_END);
writer.append(LINE_END); writer.append(LINE_END);
writer.append(value).append(LINE_END); writer.append(value).append(LINE_END);
@ -151,11 +152,11 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UTaskWrapper> {
writer.append("Content-Disposition: form-data; name=\"") writer.append("Content-Disposition: form-data; name=\"")
.append(attachment) .append(attachment)
.append("\"; filename=\"") .append("\"; filename=\"")
.append(mTaskWrapper.getEntity().getFileName()) .append(getEntity().getFileName())
.append("\"") .append("\"")
.append(LINE_END); .append(LINE_END);
writer.append("Content-Type: ") writer.append("Content-Type: ")
.append(URLConnection.guessContentTypeFromName(mTaskWrapper.getEntity().getFileName())) .append(URLConnection.guessContentTypeFromName(getEntity().getFileName()))
.append(LINE_END); .append(LINE_END);
writer.append("Content-Transfer-Encoding: binary").append(LINE_END); writer.append("Content-Transfer-Encoding: binary").append(LINE_END);
writer.append(LINE_END); writer.append(LINE_END);
@ -165,9 +166,9 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UTaskWrapper> {
byte[] buffer = new byte[4096]; byte[] buffer = new byte[4096];
int bytesRead; int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) { while ((bytesRead = inputStream.read(buffer)) != -1) {
STATE.CURRENT_LOCATION += bytesRead; getState().CURRENT_LOCATION += bytesRead;
mOutputStream.write(buffer, 0, bytesRead); mOutputStream.write(buffer, 0, bytesRead);
if (STATE.isCancel) { if (getState().isCancel) {
break; break;
} }
if (mSpeedBandUtil != null) { if (mSpeedBandUtil != null) {
@ -180,11 +181,11 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UTaskWrapper> {
inputStream.close(); inputStream.close();
writer.append(LINE_END); writer.append(LINE_END);
writer.flush(); writer.flush();
if (STATE.isCancel) { if (getState().isCancel) {
STATE.isRunning = false; getState().isRunning = false;
return; return;
} }
STATE.isRunning = false; getState().isRunning = false;
} }
/** /**
@ -224,6 +225,6 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UTaskWrapper> {
} }
@Override protected UploadConfig getTaskConfig() { @Override protected UploadConfig getTaskConfig() {
return mTaskWrapper.getConfig(); return getTaskWrapper().getConfig();
} }
} }

@ -18,6 +18,7 @@ package com.arialyy.aria.core.upload.uploader;
import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback; import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskWrapper; import com.arialyy.aria.core.inf.AbsTaskWrapper;
import com.arialyy.aria.core.inf.IUploadListener; import com.arialyy.aria.core.inf.IUploadListener;
import com.arialyy.aria.core.upload.UTaskWrapper; import com.arialyy.aria.core.upload.UTaskWrapper;
@ -61,7 +62,7 @@ public class SimpleUploadUtil implements IUtil, Runnable {
} }
} }
@Override public void onFail(String url, BaseException e, boolean needRetry) { @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
mListener.onFail(needRetry, e); mListener.onFail(needRetry, e);
} }
}).start(); }).start();

File diff suppressed because it is too large Load Diff

@ -11,6 +11,8 @@
- 修复使用`Content-Disposition`的文件名时,第一次下载无法重命名文件的问题 - 修复使用`Content-Disposition`的文件名时,第一次下载无法重命名文件的问题
- 修复使用`Content-Disposition`的文件名时,多次重命名文件的问题 - 修复使用`Content-Disposition`的文件名时,多次重命名文件的问题
- 组合任务新增`unknownSize()`,用于处理组合任务大小未知的情况,https://github.com/AriaLyy/Aria/issues/380 - 组合任务新增`unknownSize()`,用于处理组合任务大小未知的情况,https://github.com/AriaLyy/Aria/issues/380
- 优化`AbsThreadTask`代码
- 新增文件长度处理功能 https://github.com/AriaLyy/Aria/issues/393
+ v_3.6.3 (2019/4/2) + v_3.6.3 (2019/4/2)
- fix bug https://github.com/AriaLyy/Aria/issues/377 - fix bug https://github.com/AriaLyy/Aria/issues/377
+ v_3.6.2 (2019/4/1) + v_3.6.2 (2019/4/1)

@ -55,6 +55,9 @@ dependencies {
// annotationProcessor 'com.arialyy.aria:aria-compiler:3.3.14' // annotationProcessor 'com.arialyy.aria:aria-compiler:3.3.14'
api 'com.github.PhilJay:MPAndroidChart:v3.0.3' api 'com.github.PhilJay:MPAndroidChart:v3.0.3'
implementation project(':AppFrame') implementation project(':AppFrame')
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
implementation 'com.github.bumptech.glide:glide:3.7.0'
} }
repositories { repositories {
mavenCentral() mavenCentral()

@ -24,6 +24,7 @@ import com.arialyy.aria.core.Aria;
import com.arialyy.frame.core.AbsFrame; import com.arialyy.frame.core.AbsFrame;
import com.arialyy.simple.BuildConfig; import com.arialyy.simple.BuildConfig;
import com.arialyy.simple.common.ConnectionChangeReceiver; import com.arialyy.simple.common.ConnectionChangeReceiver;
import com.squareup.leakcanary.LeakCanary;
/** /**
* Created by Lyy on 2016/9/27. * Created by Lyy on 2016/9/27.
@ -44,12 +45,20 @@ public class BaseApplication extends Application {
.build()); .build());
StrictMode.setThreadPolicy( StrictMode.setThreadPolicy(
new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
} if (LeakCanary.isInAnalyzerProcess(this)) {//1
// This process is dedicated to LeakCanary for heap analysis.
registerReceiver(new ConnectionChangeReceiver(), // You should not init your app in this process.
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); return;
}
LeakCanary.install(this);
} }
registerReceiver(new ConnectionChangeReceiver(),
new
IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
public static BaseApplication getApp() { public static BaseApplication getApp() {
return INSTANCE; return INSTANCE;
} }

@ -21,6 +21,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
@ -36,6 +37,7 @@ import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTarget; import com.arialyy.aria.core.download.DownloadTarget;
import com.arialyy.aria.core.download.DownloadTask; import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.IHttpFileLenAdapter;
import com.arialyy.aria.core.scheduler.ISchedulers; import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
@ -58,8 +60,8 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
//"http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apks"; //"http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apks";
//"http://120.55.95.61:8811/ghcg/zg/武义总规纲要成果.zip"; //"http://120.55.95.61:8811/ghcg/zg/武义总规纲要成果.zip";
//"https://yizi-kejian.oss-cn-beijing.aliyuncs.com/qimeng/package1/qmtable11.zip"; //"https://yizi-kejian.oss-cn-beijing.aliyuncs.com/qimeng/package1/qmtable11.zip";
//"http://rs.0.gaoshouyou.com/d/04/1e/400423a7551e1f3f0eb1812afa1f9b44.apk"; "http://rs.0.gaoshouyou.com/d/04/1e/400423a7551e1f3f0eb1812afa1f9b44.apk";
"http://chargepile2.techsum.net/car-manage/file/download?path=2019-04-26/c0242efd18be4ecbb23911b1c509dcad--掌通各系统汇总.xls"; // 无长度的chunked //"http://chargepile2.techsum.net/car-manage/file/download?path=2019-04-26/c0242efd18be4ecbb23911b1c509dcad--掌通各系统汇总.xls"; // 无长度的chunked
//"http://58.210.9.131/tpk/sipgt//TDLYZTGH.tpk"; //chunked 下载 //"http://58.210.9.131/tpk/sipgt//TDLYZTGH.tpk"; //chunked 下载
//"http://apk500.bce.baidu-mgame.com/game/67000/67734/20170622040827_oem_5502845.apk?r=1"; //"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"; //"https://dl.genymotion.com/releases/genymotion-2.12.1/genymotion-2.12.1-vbox.exe";
@ -262,8 +264,8 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
L.d(TAG, "path = " + task.getDownloadEntity().getDownloadPath()); L.d(TAG, "path = " + task.getDownloadEntity().getDownloadPath());
L.d(TAG, "md5Code = " + CommonUtil.getFileMD5(new File(task.getDownloadPath()))); L.d(TAG, "md5Code = " + CommonUtil.getFileMD5(new File(task.getDownloadPath())));
L.d(TAG, "data = " + Aria.download(this).getDownloadEntity(DOWNLOAD_URL)); L.d(TAG, "data = " + Aria.download(this).getDownloadEntity(DOWNLOAD_URL));
DownloadEntity temp = Aria.download(this).getDownloadEntity(DOWNLOAD_URL); //DownloadEntity temp = Aria.download(this).getDownloadEntity(DOWNLOAD_URL);
L.d(TAG, "status = " + temp.getState() + ", isComplete = " + temp.isComplete()); //L.d(TAG, "status = " + temp.getState() + ", isComplete = " + temp.isComplete());
//Intent install = new Intent(Intent.ACTION_VIEW); //Intent install = new Intent(Intent.ACTION_VIEW);
//install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//File apkFile = new File(task.getDownloadPath()); //File apkFile = new File(task.getDownloadPath());
@ -289,15 +291,9 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
switch (view.getId()) { switch (view.getId()) {
case R.id.start: case R.id.start:
startD(); startD();
//List<DownloadEntity> list = Aria.download(this).getAllNotCompleteTask(5, 2);
//ALog.d("Tag", list.size() + "");
break; break;
case R.id.stop: case R.id.stop:
Aria.download(this).load(DOWNLOAD_URL).stop(); Aria.download(this).load(DOWNLOAD_URL).stop();
//startActivity(new Intent(this, SingleTaskActivity.class));
//Aria.download(this).unRegister();
//Aria.download(this).load(DOWNLOAD_URL).removeRecord();
//Log.d(TAG, Aria.download(this).taskExists(DOWNLOAD_URL) + "");
break; break;
case R.id.cancel: case R.id.cancel:
Aria.download(this).load(DOWNLOAD_URL).cancel(true); Aria.download(this).load(DOWNLOAD_URL).cancel(true);
@ -310,9 +306,6 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
private void startD() { private void startD() {
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/ggsg14.apk"; String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/ggsg14.apk";
//Map<String, String> params = new HashMap<>();
//params.put("key", "value");
//params.put("filename", "CentOS-7-x86_64-Minimal-1804.iso");
Aria.download(SingleTaskActivity.this) Aria.download(SingleTaskActivity.this)
.load(DOWNLOAD_URL) .load(DOWNLOAD_URL)
//.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3") //.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3")
@ -321,6 +314,18 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
//.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)
.setFilePath(path, true) .setFilePath(path, true)
.setFileLenAdapter(new IHttpFileLenAdapter() {
@Override public long handleFileLen(Map<String, List<String>> headers) {
List<String> sLength = headers.get("Content-Length");
if (sLength == null || sLength.isEmpty()) {
return -1;
}
String temp = sLength.get(0);
return Long.parseLong(temp);
}
})
//.asGet() //.asGet()
//.asPost() //.asPost()
//.setParams(params) //.setParams(params)

@ -24,6 +24,8 @@ import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity; import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTask; import com.arialyy.aria.core.download.DownloadGroupTask;
import com.arialyy.aria.core.inf.AbsHttpFileLenAdapter;
import com.arialyy.aria.core.inf.IHttpFileLenAdapter;
import com.arialyy.frame.util.show.L; import com.arialyy.frame.util.show.L;
import com.arialyy.frame.util.show.T; import com.arialyy.frame.util.show.T;
import com.arialyy.simple.R; import com.arialyy.simple.R;
@ -31,6 +33,7 @@ import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.databinding.ActivityDownloadGroupBinding; import com.arialyy.simple.databinding.ActivityDownloadGroupBinding;
import com.arialyy.simple.widget.SubStateLinearLayout; import com.arialyy.simple.widget.SubStateLinearLayout;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Created by lyy on 2017/7/6. * Created by lyy on 2017/7/6.
@ -87,6 +90,18 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
//.setSubFileName(getModule(GroupModule.class).getSubName2()) //.setSubFileName(getModule(GroupModule.class).getSubName2())
.setSubFileName(getModule(GroupModule.class).getSubName()) .setSubFileName(getModule(GroupModule.class).getSubName())
.unknownSize() .unknownSize()
.setFileLenAdapter(new AbsHttpFileLenAdapter() {
@Override public long handleFileLen(Map<String, List<String>> headers) {
List<String> sLength = headers.get("Content-Length");
if (sLength == null || sLength.isEmpty()) {
return -1;
}
String temp = sLength.get(0);
return Long.parseLong(temp);
}
})
//.setFileSize(114981416) //.setFileSize(114981416)
//.updateUrls(temp) //.updateUrls(temp)
.start(); .start();

Loading…
Cancel
Save