优化组合任务target

v3.6.6
laoyuyu 6 years ago
parent b3501dc3c3
commit 4b8eeca164
  1. 194
      Aria/src/main/java/com/arialyy/aria/core/download/AbsDGTarget.java
  2. 2
      Aria/src/main/java/com/arialyy/aria/core/download/AbsDTarget.java
  3. 159
      Aria/src/main/java/com/arialyy/aria/core/download/AbsGroupDelegate.java
  4. 8
      Aria/src/main/java/com/arialyy/aria/core/download/DNormalDelegate.java
  5. 247
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
  6. 948
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
  7. 2
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java
  8. 91
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDelegate.java
  9. 104
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
  10. 2
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
  11. 238
      Aria/src/main/java/com/arialyy/aria/core/download/HttpGroupDelegate.java
  12. 58
      Aria/src/main/java/com/arialyy/aria/core/inf/IGroupTarget.java
  13. 17
      Aria/src/main/java/com/arialyy/aria/core/inf/INormalTarget.java
  14. 8
      Aria/src/main/java/com/arialyy/aria/core/upload/UNormalDelegate.java
  15. 518
      Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
  16. 14
      README.md
  17. BIN
      img/group_task.gif

@ -33,18 +33,18 @@ import java.util.List;
*/ */
abstract class AbsDGTarget<TARGET extends AbsDGTarget> extends AbsTarget<TARGET> { abstract class AbsDGTarget<TARGET extends AbsDGTarget> extends AbsTarget<TARGET> {
/** ///**
* 组任务名 // * 组任务名
*/ // */
String mGroupHash; //String mGroupHash;
/** ///**
* 文件夹临时路径 // * 文件夹临时路径
*/ // */
String mDirPathTemp; //String mDirPathTemp;
/** ///**
* 是否需要修改路径 // * 是否需要修改路径
*/ // */
boolean needModifyPath = false; //boolean needModifyPath = false;
private SubTaskManager mSubTaskManager; private SubTaskManager mSubTaskManager;
@ -79,93 +79,93 @@ abstract class AbsDGTarget<TARGET extends AbsDGTarget> extends AbsTarget<TARGET>
return (TARGET) this; return (TARGET) this;
} }
@Override public boolean taskExists() { //@Override public boolean taskExists() {
return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", mGroupHash); // return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", mGroupHash);
} //}
/** ///**
* 设置任务组的文件夹路径在Aria中任务组的所有子任务都会下载到以任务组组名的文件夹中 // * 设置任务组的文件夹路径,在Aria中,任务组的所有子任务都会下载到以任务组组名的文件夹中。
* groupDirPath = "/mnt/sdcard/download/group_test" // * 如:groupDirPath = "/mnt/sdcard/download/group_test"
* <pre> // * <pre>
* {@code // * {@code
* + mnt // * + mnt
* + sdcard // * + sdcard
* + download // * + download
* + group_test // * + group_test
* - task1.apk // * - task1.apk
* - task2.apk // * - task2.apk
* - task3.apk // * - task3.apk
* .... // * ....
* // *
* } // * }
* </pre> // * </pre>
* // *
* @param dirPath 任务组保存文件夹路径 // * @param dirPath 任务组保存文件夹路径
*/ // */
@CheckResult //@CheckResult
public TARGET setDirPath(String dirPath) { //public TARGET setDirPath(String dirPath) {
mDirPathTemp = dirPath; // mDirPathTemp = dirPath;
return (TARGET) this; // return (TARGET) this;
} //}
@Override public boolean isRunning() { //@Override public boolean isRunning() {
DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(getEntity().getKey()); // DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(getEntity().getKey());
return task != null && task.isRunning(); // return task != null && task.isRunning();
} //}
/** ///**
* 改变任务组文件夹路径修改文件夹路径会将子任务所有路径更换 // * 改变任务组文件夹路径,修改文件夹路径会将子任务所有路径更换
* // *
* @param newDirPath 新的文件夹路径 // * @param newDirPath 新的文件夹路径
*/ // */
void reChangeDirPath(String newDirPath) { //void reChangeDirPath(String newDirPath) {
List<DTaskWrapper> subTasks = getTaskWrapper().getSubTaskWrapper(); // List<DTaskWrapper> subTasks = getTaskWrapper().getSubTaskWrapper();
if (subTasks != null && !subTasks.isEmpty()) { // if (subTasks != null && !subTasks.isEmpty()) {
List<DbEntity> des = new ArrayList<>(); // List<DbEntity> des = new ArrayList<>();
for (DTaskWrapper dte : subTasks) { // for (DTaskWrapper dte : subTasks) {
DownloadEntity de = dte.getEntity(); // DownloadEntity de = dte.getEntity();
String oldPath = de.getDownloadPath(); // String oldPath = de.getDownloadPath();
String newPath = newDirPath + "/" + de.getFileName(); // String newPath = newDirPath + "/" + de.getFileName();
File file = new File(oldPath); // File file = new File(oldPath);
if (file.exists()) { // if (file.exists()) {
file.renameTo(new File(newPath)); // file.renameTo(new File(newPath));
} // }
de.setDownloadPath(newPath); // de.setDownloadPath(newPath);
des.add(de); // des.add(de);
} // }
AbsEntity.saveAll(des); // 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(); // * @return {@code true} 合法
} // */
needModifyPath = true; //boolean checkDirPath() {
getEntity().setDirPath(mDirPathTemp); // if (TextUtils.isEmpty(mDirPathTemp)) {
ALog.i(TAG, String.format("文件夹路径改变,将更新文件夹路径为:%s", mDirPathTemp)); // ALog.e(TAG, "文件夹路径不能为null");
} // return false;
// } else if (!mDirPathTemp.startsWith("/")) {
return true; // 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;
//}
} }

@ -23,7 +23,7 @@ import com.arialyy.aria.util.CommonUtil;
/** /**
* Created by lyy on 2017/2/28. * Created by lyy on 2017/2/28.
*/ */
abstract class AbsDownloadTarget<TARGET extends AbsDownloadTarget> extends AbsTarget<TARGET> { abstract class AbsDTarget<TARGET extends AbsDTarget> extends AbsTarget<TARGET> {
/** /**
* 更新下载url * 更新下载url

@ -0,0 +1,159 @@
/*
* 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.download;
import android.support.annotation.CheckResult;
import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.IGroupTarget;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* Created by lyy on 2019/4/9.
* 下载组合任务功能
*/
abstract class AbsGroupDelegate<TARGET extends AbsDGTarget> implements IGroupTarget {
protected String TAG;
private TARGET mTarget;
private DGTaskWrapper mWrapper;
/**
* 组任务名
*/
private String mGroupHash;
/**
* 文件夹临时路径
*/
private String mDirPathTemp;
/**
* 是否需要修改路径
*/
private boolean needModifyPath = false;
AbsGroupDelegate(TARGET target, DGTaskWrapper wrapper) {
TAG = CommonUtil.getClassName(getClass());
mTarget = target;
mWrapper = wrapper;
setGroupHash(wrapper.getKey());
mTarget.setTaskWrapper(wrapper);
if (getEntity() != null) {
mDirPathTemp = getEntity().getDirPath();
}
}
@Override public boolean isRunning() {
DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(getEntity().getKey());
return task != null && task.isRunning();
}
@CheckResult
TARGET setDirPath(String dirPath) {
mDirPathTemp = dirPath;
return mTarget;
}
/**
* 改变任务组文件夹路径修改文件夹路径会将子任务所有路径更换
*
* @param newDirPath 新的文件夹路径
*/
void reChangeDirPath(String newDirPath) {
List<DTaskWrapper> subTasks = mWrapper.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} 合法
*/
@Override public 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;
}
@Override public DownloadGroupEntity getEntity() {
return mWrapper.getEntity();
}
@Override public boolean taskExists() {
return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", mWrapper.getKey());
}
DGTaskWrapper getTaskWrapper() {
return mWrapper;
}
boolean isNeedModifyPath() {
return needModifyPath;
}
String getDirPathTemp() {
return mDirPathTemp;
}
TARGET getTarget() {
return mTarget;
}
public String getGroupHash() {
return mGroupHash;
}
public void setGroupHash(String groupHash) {
this.mGroupHash = groupHash;
}
}

@ -17,7 +17,7 @@ package com.arialyy.aria.core.download;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.inf.ITargetHandler; import com.arialyy.aria.core.inf.ITargetHandler;
import com.arialyy.aria.core.inf.ITargetNormal; import com.arialyy.aria.core.inf.INormalTarget;
import com.arialyy.aria.core.manager.TaskWrapperManager; import com.arialyy.aria.core.manager.TaskWrapperManager;
import com.arialyy.aria.core.queue.DownloadTaskQueue; import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
@ -29,7 +29,7 @@ import java.io.File;
* Created by AriaL on 2019/4/5. * Created by AriaL on 2019/4/5.
* 普通下载任务通用功能处理 * 普通下载任务通用功能处理
*/ */
class DNormalDelegate<TARGET extends AbsDownloadTarget> implements ITargetNormal<TARGET> { class DNormalDelegate<TARGET extends AbsDTarget> implements INormalTarget {
private final String TAG = "DNormalDelegate"; private final String TAG = "DNormalDelegate";
private DownloadEntity mEntity; private DownloadEntity mEntity;
@ -54,7 +54,7 @@ class DNormalDelegate<TARGET extends AbsDownloadTarget> implements ITargetNormal
initTarget(url, targetName); initTarget(url, targetName);
} }
@Override public void initTarget(String url, String targetName) { private void initTarget(String url, String targetName) {
DTaskWrapper taskWrapper = DTaskWrapper taskWrapper =
TaskWrapperManager.getInstance().getHttpTaskWrapper(DTaskWrapper.class, url); TaskWrapperManager.getInstance().getHttpTaskWrapper(DTaskWrapper.class, url);
mEntity = taskWrapper.getEntity(); mEntity = taskWrapper.getEntity();
@ -67,7 +67,7 @@ class DNormalDelegate<TARGET extends AbsDownloadTarget> implements ITargetNormal
} }
} }
@Override public TARGET updateUrl(String newUrl) { TARGET updateUrl(String newUrl) {
if (TextUtils.isEmpty(newUrl)) { if (TextUtils.isEmpty(newUrl)) {
ALog.e(TAG, "url更新失败,newUrl为null"); ALog.e(TAG, "url更新失败,newUrl为null");
return mTarget; return mTarget;

@ -17,21 +17,15 @@ 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 android.text.TextUtils;
import com.arialyy.aria.core.common.RequestEnum;
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.IHttpHeaderDelegate;
import com.arialyy.aria.core.manager.TaskWrapperManager; import com.arialyy.aria.core.manager.TaskWrapperManager;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.exception.ParamException;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.net.Proxy; import java.net.Proxy;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* Created by AriaL on 2017/6/29. * Created by AriaL on 2017/6/29.
@ -39,43 +33,33 @@ import java.util.Set;
*/ */
public class DownloadGroupTarget extends AbsDGTarget<DownloadGroupTarget> implements public class DownloadGroupTarget extends AbsDGTarget<DownloadGroupTarget> implements
IHttpHeaderDelegate<DownloadGroupTarget> { IHttpHeaderDelegate<DownloadGroupTarget> {
private HttpHeaderDelegate<DownloadGroupTarget> mDelegate; private HttpHeaderDelegate<DownloadGroupTarget> mHeaderDelegate;
/** private HttpGroupDelegate mGroupDelegate;
* 子任务下载地址
*/
private List<String> mUrls = new ArrayList<>();
/**
* 子任务文件名
*/
private List<String> mSubNameTemp = new ArrayList<>();
public DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) { DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) {
setTargetName(targetName); setTargetName(targetName);
if (groupEntity.getUrls() != null && !groupEntity.getUrls().isEmpty()) { if (groupEntity.getUrls() != null && !groupEntity.getUrls().isEmpty()) {
this.mUrls.addAll(groupEntity.getUrls()); init(groupEntity.getUrls());
} else {
throw new ParamException("组合任务只任务下载地址为空");
} }
init();
} }
DownloadGroupTarget(List<String> urls, String targetName) { DownloadGroupTarget(List<String> urls, String targetName) {
setTargetName(targetName); setTargetName(targetName);
this.mUrls = urls; init(urls);
init();
} }
private void init() { private void init(List<String> urls) {
mGroupHash = CommonUtil.getMd5Code(mUrls); mGroupDelegate = new HttpGroupDelegate(this,
setTaskWrapper(TaskWrapperManager.getInstance().getDGTaskWrapper(DGTaskWrapper.class, mUrls)); TaskWrapperManager.getInstance().getDGTaskWrapper(DGTaskWrapper.class, urls));
if (getEntity() != null) { mHeaderDelegate = new HttpHeaderDelegate<>(this);
mDirPathTemp = getEntity().getDirPath();
}
mDelegate = new HttpHeaderDelegate<>(this);
} }
/** /**
* Post处理 * Post处理
*/ */
@CheckResult
public PostDelegate asPost() { public PostDelegate asPost() {
return new PostDelegate<>(this); return new PostDelegate<>(this);
} }
@ -87,24 +71,7 @@ public class DownloadGroupTarget extends AbsDGTarget<DownloadGroupTarget> implem
*/ */
@CheckResult @CheckResult
public DownloadGroupTarget updateUrls(List<String> urls) { public DownloadGroupTarget updateUrls(List<String> urls) {
if (urls == null || urls.isEmpty()) { return mGroupDelegate.updateUrls(urls);
throw new NullPointerException("下载地址列表为空");
}
if (urls.size() != mUrls.size()) {
throw new IllegalArgumentException("新下载地址数量和旧下载地址数量不一致");
}
mUrls.clear();
mUrls.addAll(urls);
mGroupHash = CommonUtil.getMd5Code(urls);
getEntity().setGroupHash(mGroupHash);
getEntity().update();
if (getEntity().getSubEntities() != null && !getEntity().getSubEntities().isEmpty()) {
for (DownloadEntity de : getEntity().getSubEntities()) {
de.setGroupHash(mGroupHash);
de.update();
}
}
return this;
} }
/** /**
@ -132,9 +99,7 @@ public class DownloadGroupTarget extends AbsDGTarget<DownloadGroupTarget> implem
*/ */
@CheckResult @CheckResult
public DownloadGroupTarget setGroupUrl(List<String> urls) { public DownloadGroupTarget setGroupUrl(List<String> urls) {
mUrls.clear(); return mGroupDelegate.setGroupUrl(urls);
mUrls.addAll(urls);
return this;
} }
/** /**
@ -147,22 +112,36 @@ public class DownloadGroupTarget extends AbsDGTarget<DownloadGroupTarget> implem
return setSubFileName(subTaskFileName); return setSubFileName(subTaskFileName);
} }
/**
* 设置任务组的文件夹路径在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 DownloadGroupTarget setDirPath(String dirPath) {
return mGroupDelegate.setDirPath(dirPath);
}
/** /**
* 设置子任务文件名该方法必须在{@link #setDirPath(String)}之后调用否则不生效 * 设置子任务文件名该方法必须在{@link #setDirPath(String)}之后调用否则不生效
*/ */
@CheckResult @CheckResult
public DownloadGroupTarget setSubFileName(List<String> subTaskFileName) { public DownloadGroupTarget setSubFileName(List<String> subTaskFileName) {
if (subTaskFileName == null || subTaskFileName.isEmpty()) { return mGroupDelegate.setSubFileName(subTaskFileName);
ALog.e(TAG, "修改子任务的文件名失败:列表为null");
return this;
}
if (subTaskFileName.size() != getTaskWrapper().getSubTaskWrapper().size()) {
ALog.e(TAG, "修改子任务的文件名失败:子任务文件名列表数量和子任务的数量不匹配");
return this;
}
mSubNameTemp.clear();
mSubNameTemp.addAll(subTaskFileName);
return this;
} }
@Override public int getTargetType() { @Override public int getTargetType() {
@ -170,161 +149,35 @@ public class DownloadGroupTarget extends AbsDGTarget<DownloadGroupTarget> implem
} }
@Override protected boolean checkEntity() { @Override protected boolean checkEntity() {
if (getTargetType() == GROUP_HTTP) { return mGroupDelegate.checkEntity();
if (!checkDirPath()) {
return false;
}
if (!checkSubName()) {
return false;
}
if (!checkUrls()) {
return false;
}
if (getTaskWrapper().getEntity().getFileSize() == 0) {
ALog.e(TAG, "组合任务必须设置文件文件大小");
return false;
}
if (getTaskWrapper().asHttp().getRequestEnum() == RequestEnum.POST) {
for (DTaskWrapper subTask : getTaskWrapper().getSubTaskWrapper()) {
subTask.asHttp().setRequestEnum(RequestEnum.POST);
}
}
getEntity().save();
if (needModifyPath) {
reChangeDirPath(mDirPathTemp);
}
if (!mSubNameTemp.isEmpty()) {
updateSingleSubFileName();
}
return true;
}
return false;
}
/**
* 更新所有改动的子任务文件名
*/
private void updateSingleSubFileName() {
List<DTaskWrapper> entities = getTaskWrapper().getSubTaskWrapper();
int i = 0;
for (DTaskWrapper entity : entities) {
if (i < mSubNameTemp.size()) {
String newName = mSubNameTemp.get(i);
updateSingleSubFileName(entity, newName);
}
i++;
}
}
/**
* 检查urls是否合法并删除不合法的子任务
*
* @return {@code true} 合法
*/
private boolean checkUrls() {
if (mUrls.isEmpty()) {
ALog.e(TAG, "下载失败,子任务下载列表为null");
return false;
}
Set<Integer> delItem = new HashSet<>();
int i = 0;
for (String url : mUrls) {
if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "子任务url为null,即将删除该子任务。");
delItem.add(i);
continue;
} else if (!url.startsWith("http")) {
//} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
ALog.e(TAG, "子任务url【" + url + "】错误,即将删除该子任务。");
delItem.add(i);
continue;
}
int index = url.indexOf("://");
if (index == -1) {
ALog.e(TAG, "子任务url【" + url + "】不合法,即将删除该子任务。");
delItem.add(i);
continue;
}
i++;
}
for (int index : delItem) {
mUrls.remove(index);
if (mSubNameTemp != null && !mSubNameTemp.isEmpty()) {
mSubNameTemp.remove(index);
}
}
getEntity().setGroupHash(CommonUtil.getMd5Code(mUrls));
return true;
} }
/** @Override public boolean isRunning() {
* 更新单个子任务文件名 return mGroupDelegate.isRunning();
*/
private void updateSingleSubFileName(DTaskWrapper taskEntity, String newName) {
DownloadEntity entity = taskEntity.getEntity();
if (!newName.equals(entity.getFileName())) {
String oldPath = getEntity().getDirPath() + "/" + entity.getFileName();
String newPath = getEntity().getDirPath() + "/" + newName;
if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=? or isComplete='true'",
newPath)) {
ALog.w(TAG, String.format("更新文件名失败,路径【%s】已存在或文件已下载", newPath));
return;
}
CommonUtil.modifyTaskRecord(oldPath, newPath);
entity.setDownloadPath(newPath);
entity.setFileName(newName);
entity.update();
}
} }
/** @Override public boolean taskExists() {
* 如果用户设置了子任务文件名检查子任务文件名 return mGroupDelegate.taskExists();
*
* @return {@code true} 合法
*/
private boolean checkSubName() {
if (mSubNameTemp == null || mSubNameTemp.isEmpty()) {
return true;
}
if (mUrls.size() != mSubNameTemp.size()) {
ALog.e(TAG, "子任务文件名必须和子任务数量一致");
return false;
}
return true;
} }
@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()) { for (DTaskWrapper subTask : getTaskWrapper().getSubTaskWrapper()) {
mDelegate.addHeader(subTask, key, value); mHeaderDelegate.addHeader(subTask, key, value);
} }
return mDelegate.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()) { for (DTaskWrapper subTask : getTaskWrapper().getSubTaskWrapper()) {
mDelegate.addHeaders(subTask, headers); mHeaderDelegate.addHeaders(subTask, headers);
} }
return mDelegate.addHeaders(headers); return mHeaderDelegate.addHeaders(headers);
} }
@CheckResult @CheckResult
@Override public DownloadGroupTarget setUrlProxy(Proxy proxy) { @Override public DownloadGroupTarget setUrlProxy(Proxy proxy) {
return mDelegate.setUrlProxy(proxy); return mHeaderDelegate.setUrlProxy(proxy);
} }
} }

@ -1,475 +1,475 @@
/* /*
* 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 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.CancelAllCmd; import com.arialyy.aria.core.command.normal.CancelAllCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory; import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.ProxyHelper; import com.arialyy.aria.core.common.ProxyHelper;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsReceiver; import com.arialyy.aria.core.inf.AbsReceiver;
import com.arialyy.aria.core.inf.ReceiverType; import com.arialyy.aria.core.inf.ReceiverType;
import com.arialyy.aria.core.manager.TaskWrapperManager; import com.arialyy.aria.core.manager.TaskWrapperManager;
import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers; import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers;
import com.arialyy.aria.core.scheduler.DownloadSchedulers; import com.arialyy.aria.core.scheduler.DownloadSchedulers;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
/** /**
* Created by lyy on 2016/12/5. * Created by lyy on 2016/12/5.
* 下载功能接收器 * 下载功能接收器
*/ */
public class DownloadReceiver extends AbsReceiver { public class DownloadReceiver extends AbsReceiver {
private final String TAG = "DownloadReceiver"; private final String TAG = "DownloadReceiver";
/** /**
* 设置最大下载速度单位kb * 设置最大下载速度单位kb
* *
* @param maxSpeed 为0表示不限速 * @param maxSpeed 为0表示不限速
* @deprecated {@code Aria.get(Context).getDownloadConfig().setMaxSpeed(int)} * @deprecated {@code Aria.get(Context).getDownloadConfig().setMaxSpeed(int)}
*/ */
@Deprecated @Deprecated
public DownloadReceiver setMaxSpeed(int maxSpeed) { public DownloadReceiver setMaxSpeed(int maxSpeed) {
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().setMaxSpeed(maxSpeed); AriaManager.getInstance(AriaManager.APP).getDownloadConfig().setMaxSpeed(maxSpeed);
return this; return this;
} }
/** /**
* 使用下载实体执行下载操作 * 使用下载实体执行下载操作
* *
* @param entity 下载实体 * @param entity 下载实体
*/ */
@CheckResult @CheckResult
public DownloadTarget load(DownloadEntity entity) { public DownloadTarget load(DownloadEntity entity) {
CheckUtil.checkUrlInvalidThrow(entity.getUrl()); CheckUtil.checkUrlInvalidThrow(entity.getUrl());
return new DownloadTarget(entity, targetName); return new DownloadTarget(entity, targetName);
} }
/** /**
* 加载Httphttps单任务下载地址 * 加载Httphttps单任务下载地址
* *
* @param url 下载地址 * @param url 下载地址
*/ */
@CheckResult @CheckResult
public DownloadTarget load(@NonNull String url) { public DownloadTarget load(@NonNull String url) {
CheckUtil.checkUrlInvalidThrow(url); CheckUtil.checkUrlInvalidThrow(url);
return new DownloadTarget(url, targetName); return new DownloadTarget(url, targetName);
} }
/** /**
* 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组 * 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组
* *
* @param urls 任务组子任务下载地址列表 * @param urls 任务组子任务下载地址列表
* @deprecated {@link #loadGroup(DownloadGroupEntity)} * @deprecated {@link #loadGroup(DownloadGroupEntity)}
*/ */
@Deprecated @Deprecated
@CheckResult @CheckResult
public DownloadGroupTarget load(List<String> urls) { public DownloadGroupTarget load(List<String> urls) {
return loadGroup(urls); return loadGroup(urls);
} }
/** /**
* 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组 * 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组
*/ */
@CheckResult @CheckResult
public DownloadGroupTarget loadGroup(List<String> urls) { public DownloadGroupTarget loadGroup(List<String> urls) {
CheckUtil.checkDownloadUrls(urls); CheckUtil.checkDownloadUrls(urls);
return new DownloadGroupTarget(urls, targetName); return new DownloadGroupTarget(urls, targetName);
} }
/** /**
* 使用下载实体执行FTP下载操作 * 使用下载实体执行FTP下载操作
* *
* @param entity 下载实体 * @param entity 下载实体
*/ */
@CheckResult @CheckResult
public FtpDownloadTarget loadFtp(DownloadEntity entity) { public FtpDownloadTarget loadFtp(DownloadEntity entity) {
CheckUtil.checkUrlInvalidThrow(entity.getUrl()); CheckUtil.checkUrlInvalidThrow(entity.getUrl());
return new FtpDownloadTarget(entity, targetName); return new FtpDownloadTarget(entity, targetName);
} }
/** /**
* 加载ftp单任务下载地址 * 加载ftp单任务下载地址
*/ */
@CheckResult @CheckResult
public FtpDownloadTarget loadFtp(@NonNull String url) { public FtpDownloadTarget loadFtp(@NonNull String url) {
CheckUtil.checkUrlInvalidThrow(url); CheckUtil.checkUrlInvalidThrow(url);
return new FtpDownloadTarget(url, targetName); return new FtpDownloadTarget(url, targetName);
} }
/** /**
* 使用任务组实体执行任务组的实体执行任务组的下载操作后续版本会删除该api * 使用任务组实体执行任务组的实体执行任务组的下载操作后续版本会删除该api
* *
* @param groupEntity 如果加载的任务实体没有子项的下载地址 * @param groupEntity 如果加载的任务实体没有子项的下载地址
* 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址 * 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址
* @deprecated 请使用 {@link #loadGroup(DownloadGroupEntity)} * @deprecated 请使用 {@link #loadGroup(DownloadGroupEntity)}
*/ */
@Deprecated @Deprecated
@CheckResult @CheckResult
public DownloadGroupTarget load(DownloadGroupEntity groupEntity) { public DownloadGroupTarget load(DownloadGroupEntity groupEntity) {
CheckUtil.checkDownloadUrls(groupEntity.getUrls()); CheckUtil.checkDownloadUrls(groupEntity.getUrls());
return loadGroup(groupEntity); return loadGroup(groupEntity);
} }
/** /**
* 使用任务组实体执行任务组的实体执行任务组的下载操作 * 使用任务组实体执行任务组的实体执行任务组的下载操作
* *
* @param groupEntity 如果加载的任务实体没有子项的下载地址 * @param groupEntity 如果加载的任务实体没有子项的下载地址
* 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址 * 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址
*/ */
@CheckResult @CheckResult
public DownloadGroupTarget loadGroup(DownloadGroupEntity groupEntity) { public DownloadGroupTarget loadGroup(DownloadGroupEntity groupEntity) {
CheckUtil.checkDownloadUrls(groupEntity.getUrls()); CheckUtil.checkDownloadUrls(groupEntity.getUrls());
return new DownloadGroupTarget(groupEntity, targetName); return new DownloadGroupTarget(groupEntity, targetName);
} }
/** /**
* 加载ftp文件夹下载地址 * 加载ftp文件夹下载地址
*/ */
@CheckResult @CheckResult
public FtpDirDownloadTarget loadFtpDir(@NonNull String dirUrl) { public FtpDirDownloadTarget loadFtpDir(@NonNull String dirUrl) {
CheckUtil.checkUrlInvalidThrow(dirUrl); CheckUtil.checkUrlInvalidThrow(dirUrl);
return new FtpDirDownloadTarget(dirUrl, targetName); return new FtpDirDownloadTarget(dirUrl, targetName);
} }
/** /**
* 将当前类注册到Aria * 将当前类注册到Aria
*/ */
public void register() { public void register() {
if (TextUtils.isEmpty(targetName)) { if (TextUtils.isEmpty(targetName)) {
ALog.e(TAG, "download register target null"); ALog.e(TAG, "download register target null");
return; return;
} }
Object obj = OBJ_MAP.get(getKey()); Object obj = OBJ_MAP.get(getKey());
if (obj == null) { if (obj == null) {
ALog.e(TAG, String.format("【%s】观察者为空", targetName)); ALog.e(TAG, String.format("【%s】观察者为空", targetName));
return; return;
} }
Set<Integer> set = ProxyHelper.getInstance().checkProxyType(obj.getClass()); Set<Integer> set = ProxyHelper.getInstance().checkProxyType(obj.getClass());
if (set != null && !set.isEmpty()) { if (set != null && !set.isEmpty()) {
for (Integer type : set) { for (Integer type : set) {
if (type == ProxyHelper.PROXY_TYPE_DOWNLOAD) { if (type == ProxyHelper.PROXY_TYPE_DOWNLOAD) {
DownloadSchedulers.getInstance().register(obj); DownloadSchedulers.getInstance().register(obj);
} else if (type == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) { } else if (type == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) {
DownloadGroupSchedulers.getInstance().register(obj); DownloadGroupSchedulers.getInstance().register(obj);
} }
} }
} else { } else {
ALog.w(TAG, "没有Aria的注解方法"); ALog.w(TAG, "没有Aria的注解方法");
} }
} }
/** /**
* 取消注册如果是Activity或fragmentAria会界面销毁时自动调用该方法不需要你手动调用 * 取消注册如果是Activity或fragmentAria会界面销毁时自动调用该方法不需要你手动调用
* 注意事项 * 注意事项
* 1如果在activity中一定要调用该方法那么请在{@code onDestroy()}中调用 * 1如果在activity中一定要调用该方法那么请在{@code onDestroy()}中调用
* 2不要在activity的{@code onStop()}中调用改方法 * 2不要在activity的{@code onStop()}中调用改方法
* 3如果是Dialog或popupwindow需要你在撤销界面时调用该方法 * 3如果是Dialog或popupwindow需要你在撤销界面时调用该方法
* 4如果你是在Module非android组件类中注册了Aria那么你也需要在Module类中调用该方法而不是在组件类中 * 4如果你是在Module非android组件类中注册了Aria那么你也需要在Module类中调用该方法而不是在组件类中
* 调用销毁详情见 * 调用销毁详情见
* *
* @see <a href="https://aria.laoyuyu.me/aria_doc/start/any_java.html#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9">module类中销毁</a> * @see <a href="https://aria.laoyuyu.me/aria_doc/start/any_java.html#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9">module类中销毁</a>
*/ */
@Override public void unRegister() { @Override public void unRegister() {
if (needRmListener) { if (needRmListener) {
unRegisterListener(); unRegisterListener();
} }
AriaManager.getInstance(AriaManager.APP).removeReceiver(OBJ_MAP.get(getKey())); AriaManager.getInstance(AriaManager.APP).removeReceiver(OBJ_MAP.get(getKey()));
} }
@Override public String getType() { @Override public String getType() {
return ReceiverType.DOWNLOAD; return ReceiverType.DOWNLOAD;
} }
@Override protected void unRegisterListener() { @Override protected void unRegisterListener() {
if (TextUtils.isEmpty(targetName)) { if (TextUtils.isEmpty(targetName)) {
ALog.e(TAG, "download unRegisterListener target null"); ALog.e(TAG, "download unRegisterListener target null");
return; return;
} }
Object obj = OBJ_MAP.get(getKey()); Object obj = OBJ_MAP.get(getKey());
if (obj == null) { if (obj == null) {
ALog.e(TAG, String.format("【%s】观察者为空", targetName)); ALog.e(TAG, String.format("【%s】观察者为空", targetName));
return; return;
} }
Set<Integer> set = ProxyHelper.getInstance().mProxyCache.get(obj.getClass().getName()); Set<Integer> set = ProxyHelper.getInstance().mProxyCache.get(obj.getClass().getName());
if (set != null) { if (set != null) {
for (Integer integer : set) { for (Integer integer : set) {
if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD) { if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD) {
DownloadSchedulers.getInstance().unRegister(obj); DownloadSchedulers.getInstance().unRegister(obj);
} else if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) { } else if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) {
DownloadGroupSchedulers.getInstance().unRegister(obj); DownloadGroupSchedulers.getInstance().unRegister(obj);
} }
} }
} }
} }
/** /**
* 通过下载链接获取下载实体 * 通过下载链接获取下载实体
* *
* @return 如果url错误或查找不到数据则返回null * @return 如果url错误或查找不到数据则返回null
*/ */
public DownloadEntity getDownloadEntity(String downloadUrl) { public DownloadEntity getDownloadEntity(String downloadUrl) {
if (!CheckUtil.checkUrl(downloadUrl)) { if (!CheckUtil.checkUrl(downloadUrl)) {
return null; return null;
} }
return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl); return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl);
} }
/** /**
* 通过下载地址和文件保存路径获取下载任务实体 * 通过下载地址和文件保存路径获取下载任务实体
* *
* @param downloadUrl 下载地址 * @param downloadUrl 下载地址
* @return 如果url错误或查找不到数据则返回null * @return 如果url错误或查找不到数据则返回null
*/ */
public DTaskWrapper getDownloadTask(String downloadUrl) { public DTaskWrapper getDownloadTask(String downloadUrl) {
if (!CheckUtil.checkUrl(downloadUrl)) { if (!CheckUtil.checkUrl(downloadUrl)) {
return null; return null;
} }
if (!taskExists(downloadUrl)) { if (!taskExists(downloadUrl)) {
return null; return null;
} }
return TaskWrapperManager.getInstance().getHttpTaskWrapper(DTaskWrapper.class, downloadUrl); return TaskWrapperManager.getInstance().getHttpTaskWrapper(DTaskWrapper.class, downloadUrl);
} }
/** /**
* 通过下载链接获取保存在数据库的下载任务组实体 * 通过下载链接获取保存在数据库的下载任务组实体
* *
* @param urls 任务组子任务下载地址列表 * @param urls 任务组子任务下载地址列表
* @return 返回对应的任务组实体如果查找不到对应的数据或子任务列表为null返回null * @return 返回对应的任务组实体如果查找不到对应的数据或子任务列表为null返回null
*/ */
public DGTaskWrapper getGroupTask(List<String> urls) { public DGTaskWrapper getGroupTask(List<String> urls) {
if (urls == null || urls.isEmpty()) { if (urls == null || urls.isEmpty()) {
ALog.e(TAG, "获取任务组实体失败:任务组子任务下载地址列表为null"); ALog.e(TAG, "获取任务组实体失败:任务组子任务下载地址列表为null");
return null; return null;
} }
if (!taskExists(urls)) { if (!taskExists(urls)) {
return null; return null;
} }
return TaskWrapperManager.getInstance().getDGTaskWrapper(DGTaskWrapper.class, urls); return TaskWrapperManager.getInstance().getDGTaskWrapper(DGTaskWrapper.class, urls);
} }
/** /**
* 获取FTP文件夹下载任务实体 * 获取FTP文件夹下载任务实体
* *
* @param dirUrl FTP文件夹本地下载路径 * @param dirUrl FTP文件夹本地下载路径
* @return 返回对应的任务组实体如果查找不到对应的数据或路径为null返回null * @return 返回对应的任务组实体如果查找不到对应的数据或路径为null返回null
*/ */
public DGTaskWrapper getFtpDirTask(String dirUrl) { public DGTaskWrapper getFtpDirTask(String dirUrl) {
if (TextUtils.isEmpty(dirUrl)) { if (TextUtils.isEmpty(dirUrl)) {
ALog.e(TAG, "获取FTP文件夹实体失败:下载路径为null"); ALog.e(TAG, "获取FTP文件夹实体失败:下载路径为null");
return null; return null;
} }
boolean b = boolean b =
DownloadGroupEntity.findFirst(DownloadGroupEntity.class, "groupHash=?", dirUrl) != null; DownloadGroupEntity.findFirst(DownloadGroupEntity.class, "groupHash=?", dirUrl) != null;
if (!b) { if (!b) {
return null; return null;
} }
return TaskWrapperManager.getInstance().getFtpTaskWrapper(DGTaskWrapper.class, dirUrl); return TaskWrapperManager.getInstance().getFtpTaskWrapper(DGTaskWrapper.class, dirUrl);
} }
/** /**
* 下载任务是否存在 * 下载任务是否存在
* *
* @return {@code true}存在{@code false} 不存在 * @return {@code true}存在{@code false} 不存在
*/ */
public boolean taskExists(String downloadUrl) { public boolean taskExists(String downloadUrl) {
return DbEntity.checkDataExist(DownloadEntity.class, "url=?", downloadUrl); return DbEntity.checkDataExist(DownloadEntity.class, "url=?", downloadUrl);
} }
/** /**
* 判断任务组是否存在 * 判断任务组是否存在
* *
* @return {@code true} 存在{@code false} 不存在 * @return {@code true} 存在{@code false} 不存在
*/ */
public boolean taskExists(List<String> urls) { public boolean taskExists(List<String> urls) {
if (urls == null || urls.isEmpty()) { if (urls == null || urls.isEmpty()) {
return false; return false;
} }
String groupHash = CommonUtil.getMd5Code(urls); String groupHash = CommonUtil.getMd5Code(urls);
return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", groupHash); return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", groupHash);
} }
/** /**
* 获取所有普通下载任务 * 获取所有普通下载任务
* 获取未完成的普通任务列表{@link #getAllNotCompleteTask()} * 获取未完成的普通任务列表{@link #getAllNotCompleteTask()}
* 获取已经完成的普通任务列表{@link #getAllCompleteTask()} * 获取已经完成的普通任务列表{@link #getAllCompleteTask()}
*/ */
public List<DownloadEntity> getTaskList() { public List<DownloadEntity> getTaskList() {
return DbEntity.findDatas(DownloadEntity.class, "isGroupChild=? and downloadPath!=''", return DbEntity.findDatas(DownloadEntity.class, "isGroupChild=? and downloadPath!=''",
"false"); "false");
} }
/** /**
* 分页获取所有普通下载任务 * 分页获取所有普通下载任务
* 获取未完成的普通任务列表{@link #getAllNotCompleteTask()} * 获取未完成的普通任务列表{@link #getAllNotCompleteTask()}
* 获取已经完成的普通任务列表{@link #getAllCompleteTask()} * 获取已经完成的普通任务列表{@link #getAllCompleteTask()}
* *
* @param page 当前页不能小于1 * @param page 当前页不能小于1
* @param num 每页数量不能小于1 * @param num 每页数量不能小于1
* @return 如果页数大于总页数返回null * @return 如果页数大于总页数返回null
*/ */
public List<DownloadEntity> getTaskList(int page, int num) { public List<DownloadEntity> getTaskList(int page, int num) {
CheckUtil.checkPageParams(page, num); CheckUtil.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class, page, num, return DbEntity.findDatas(DownloadEntity.class, page, num,
"isGroupChild=? and downloadPath!=''", "false"); "isGroupChild=? and downloadPath!=''", "false");
} }
/** /**
* 获取所有未完成的普通下载任务 * 获取所有未完成的普通下载任务
*/ */
public List<DownloadEntity> getAllNotCompleteTask() { public List<DownloadEntity> getAllNotCompleteTask() {
return DbEntity.findDatas(DownloadEntity.class, return DbEntity.findDatas(DownloadEntity.class,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false"); "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false");
} }
/** /**
* 分页获取所有未完成的普通下载任务 * 分页获取所有未完成的普通下载任务
* *
* @param page 当前页不能小于1 * @param page 当前页不能小于1
* @param num 每页数量不能小于1 * @param num 每页数量不能小于1
* @return 如果页数大于总页数返回null * @return 如果页数大于总页数返回null
*/ */
public List<DownloadEntity> getAllNotCompleteTask(int page, int num) { public List<DownloadEntity> getAllNotCompleteTask(int page, int num) {
CheckUtil.checkPageParams(page, num); CheckUtil.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class, page, num, return DbEntity.findDatas(DownloadEntity.class, page, num,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false"); "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false");
} }
/** /**
* 获取所有已经完成的普通任务 * 获取所有已经完成的普通任务
*/ */
public List<DownloadEntity> getAllCompleteTask() { public List<DownloadEntity> getAllCompleteTask() {
return DbEntity.findDatas(DownloadEntity.class, return DbEntity.findDatas(DownloadEntity.class,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true"); "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true");
} }
/** /**
* 分页获取所有已经完成的普通任务 * 分页获取所有已经完成的普通任务
* *
* @param page 当前页不能小于1 * @param page 当前页不能小于1
* @param num 每页数量不能小于1 * @param num 每页数量不能小于1
* @return 如果页数大于总页数返回null * @return 如果页数大于总页数返回null
*/ */
public List<DownloadEntity> getAllCompleteTask(int page, int num) { public List<DownloadEntity> getAllCompleteTask(int page, int num) {
CheckUtil.checkPageParams(page, num); CheckUtil.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class, return DbEntity.findDatas(DownloadEntity.class,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true"); "isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true");
} }
/** /**
* 获取任务组列表 * 获取任务组列表
* *
* @return 如果没有任务组列表则返回null * @return 如果没有任务组列表则返回null
*/ */
public List<DownloadGroupEntity> getGroupTaskList() { public List<DownloadGroupEntity> getGroupTaskList() {
List<DGEntityWrapper> wrappers = DbEntity.findRelationData(DGEntityWrapper.class); List<DGEntityWrapper> wrappers = DbEntity.findRelationData(DGEntityWrapper.class);
if (wrappers == null || wrappers.isEmpty()) { if (wrappers == null || wrappers.isEmpty()) {
return null; return null;
} }
List<DownloadGroupEntity> entities = new ArrayList<>(); List<DownloadGroupEntity> entities = new ArrayList<>();
for (DGEntityWrapper wrapper : wrappers) { for (DGEntityWrapper wrapper : wrappers) {
entities.add(wrapper.groupEntity); entities.add(wrapper.groupEntity);
} }
return entities; return entities;
} }
/** /**
* 分页获取祝贺任务列表 * 分页获取祝贺任务列表
* *
* @param page 当前页不能小于1 * @param page 当前页不能小于1
* @param num 每页数量不能小于1 * @param num 每页数量不能小于1
* @return 如果没有任务组列表则返回null * @return 如果没有任务组列表则返回null
*/ */
public List<DownloadGroupEntity> getGroupTaskList(int page, int num) { public List<DownloadGroupEntity> getGroupTaskList(int page, int num) {
List<DGEntityWrapper> wrappers = DbEntity.findRelationData(DGEntityWrapper.class, page, num); List<DGEntityWrapper> wrappers = DbEntity.findRelationData(DGEntityWrapper.class, page, num);
if (wrappers == null || wrappers.isEmpty()) { if (wrappers == null || wrappers.isEmpty()) {
return null; return null;
} }
List<DownloadGroupEntity> entities = new ArrayList<>(); List<DownloadGroupEntity> entities = new ArrayList<>();
for (DGEntityWrapper wrapper : wrappers) { for (DGEntityWrapper wrapper : wrappers) {
entities.add(wrapper.groupEntity); entities.add(wrapper.groupEntity);
} }
return entities; return entities;
} }
/** /**
* 获取普通任务和任务组的任务列表 * 获取普通任务和任务组的任务列表
*/ */
public List<AbsEntity> getTotalTaskList() { public List<AbsEntity> getTotalTaskList() {
List<AbsEntity> list = new ArrayList<>(); List<AbsEntity> list = new ArrayList<>();
List<DownloadEntity> simpleTask = getTaskList(); List<DownloadEntity> simpleTask = getTaskList();
List<DownloadGroupEntity> groupTask = getGroupTaskList(); List<DownloadGroupEntity> groupTask = getGroupTaskList();
if (simpleTask != null && !simpleTask.isEmpty()) { if (simpleTask != null && !simpleTask.isEmpty()) {
list.addAll(simpleTask); list.addAll(simpleTask);
} }
if (groupTask != null && !groupTask.isEmpty()) { if (groupTask != null && !groupTask.isEmpty()) {
list.addAll(groupTask); list.addAll(groupTask);
} }
return list; return list;
} }
/** /**
* 停止所有正在下载的任务并清空等待队列 * 停止所有正在下载的任务并清空等待队列
*/ */
public void stopAllTask() { public void stopAllTask() {
AriaManager.getInstance(AriaManager.APP) AriaManager.getInstance(AriaManager.APP)
.setCmd(NormalCmdFactory.getInstance() .setCmd(NormalCmdFactory.getInstance()
.createCmd(new DTaskWrapper(null), NormalCmdFactory.TASK_STOP_ALL, .createCmd(new DTaskWrapper(null), NormalCmdFactory.TASK_STOP_ALL,
ICmd.TASK_TYPE_DOWNLOAD)) ICmd.TASK_TYPE_DOWNLOAD))
.exe(); .exe();
} }
/** /**
* 恢复所有正在下载的任务 * 恢复所有正在下载的任务
* 1.如果执行队列没有满则开始下载任务直到执行队列满 * 1.如果执行队列没有满则开始下载任务直到执行队列满
* 2.如果队列执行队列已经满了则将所有任务添加到等待队列中 * 2.如果队列执行队列已经满了则将所有任务添加到等待队列中
*/ */
public void resumeAllTask() { public void resumeAllTask() {
AriaManager.getInstance(AriaManager.APP) AriaManager.getInstance(AriaManager.APP)
.setCmd(NormalCmdFactory.getInstance() .setCmd(NormalCmdFactory.getInstance()
.createCmd(new DTaskWrapper(null), NormalCmdFactory.TASK_RESUME_ALL, .createCmd(new DTaskWrapper(null), NormalCmdFactory.TASK_RESUME_ALL,
ICmd.TASK_TYPE_DOWNLOAD)) ICmd.TASK_TYPE_DOWNLOAD))
.exe(); .exe();
} }
/** /**
* 删除所有任务 * 删除所有任务
* *
* @param removeFile {@code true} 删除已经下载完成的任务不仅删除下载记录还会删除已经下载完成的文件{@code false} * @param removeFile {@code true} 删除已经下载完成的任务不仅删除下载记录还会删除已经下载完成的文件{@code false}
* 如果文件已经下载完成只删除下载记录 * 如果文件已经下载完成只删除下载记录
*/ */
public void removeAllTask(boolean removeFile) { public void removeAllTask(boolean removeFile) {
final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP); final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
CancelAllCmd cancelCmd = CancelAllCmd cancelCmd =
(CancelAllCmd) CommonUtil.createNormalCmd(new DTaskWrapper(null), (CancelAllCmd) CommonUtil.createNormalCmd(new DTaskWrapper(null),
NormalCmdFactory.TASK_CANCEL_ALL, ICmd.TASK_TYPE_DOWNLOAD); NormalCmdFactory.TASK_CANCEL_ALL, ICmd.TASK_TYPE_DOWNLOAD);
cancelCmd.removeFile = removeFile; cancelCmd.removeFile = removeFile;
ariaManager.setCmd(cancelCmd).exe(); ariaManager.setCmd(cancelCmd).exe();
Set<String> keys = ariaManager.getReceiver().keySet(); Set<String> keys = ariaManager.getReceiver().keySet();
for (String key : keys) { for (String key : keys) {
ariaManager.getReceiver().remove(key); ariaManager.getReceiver().remove(key);
} }
} }
} }

@ -28,7 +28,7 @@ import java.util.Map;
* Created by lyy on 2016/12/5. * Created by lyy on 2016/12/5.
* https://github.com/AriaLyy/Aria * https://github.com/AriaLyy/Aria
*/ */
public class DownloadTarget extends AbsDownloadTarget<DownloadTarget> public class DownloadTarget extends AbsDTarget<DownloadTarget>
implements IHttpHeaderDelegate<DownloadTarget> { implements IHttpHeaderDelegate<DownloadTarget> {
private HttpHeaderDelegate<DownloadTarget> mHeaderDelegate; private HttpHeaderDelegate<DownloadTarget> mHeaderDelegate;
private DNormalDelegate<DownloadTarget> mNormalDelegate; private DNormalDelegate<DownloadTarget> mNormalDelegate;

@ -0,0 +1,91 @@
/*
* 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.download;
import android.text.TextUtils;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.inf.AbsTaskWrapper;
import com.arialyy.aria.util.ALog;
/**
* Created by lyy on 2017/4/9.
* ftp文件夹下载功能代理
*/
class FtpDirDelegate extends AbsGroupDelegate<FtpDirDownloadTarget> {
FtpDirDelegate(FtpDirDownloadTarget target, DGTaskWrapper wrapper) {
super(target, wrapper);
wrapper.setRequestType(AbsTaskWrapper.D_FTP_DIR);
}
@Override public boolean checkEntity() {
boolean b = checkDirPath() && checkUrl();
if (b) {
getEntity().save();
if (getTaskWrapper().getSubTaskWrapper() != null) {
//初始化子项的登录信息
FtpUrlEntity tUrlEntity = getTaskWrapper().asFtp().getUrlEntity();
for (DTaskWrapper wrapper : getTaskWrapper().getSubTaskWrapper()) {
FtpUrlEntity urlEntity = wrapper.asFtp().getUrlEntity();
urlEntity.needLogin = tUrlEntity.needLogin;
urlEntity.account = tUrlEntity.account;
urlEntity.user = tUrlEntity.user;
urlEntity.password = tUrlEntity.password;
// 处理ftps详细
if (tUrlEntity.isFtps) {
urlEntity.isFtps = true;
urlEntity.protocol = tUrlEntity.protocol;
urlEntity.storePath = tUrlEntity.storePath;
urlEntity.storePass = tUrlEntity.storePass;
urlEntity.keyAlias = tUrlEntity.keyAlias;
}
}
}
}
if (getTaskWrapper().asFtp().getUrlEntity().isFtps) {
if (TextUtils.isEmpty(getTaskWrapper().asFtp().getUrlEntity().storePath)) {
ALog.e(TAG, "证书路径为空");
return false;
}
if (TextUtils.isEmpty(getTaskWrapper().asFtp().getUrlEntity().keyAlias)) {
ALog.e(TAG, "证书别名为空");
return false;
}
}
return b;
}
/**
* 检查普通任务的下载地址
*
* @return {@code true}地址合法
*/
private boolean checkUrl() {
final String url = getGroupHash();
if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "下载失败,url为null");
return false;
} else if (!url.startsWith("ftp")) {
ALog.e(TAG, "下载失败,url【" + url + "】错误");
return false;
}
int index = url.indexOf("://");
if (index == -1) {
ALog.e(TAG, "下载失败,url【" + url + "】不合法");
return false;
}
return true;
}
}

@ -16,14 +16,10 @@
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 com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.ftp.FTPSDelegate; import com.arialyy.aria.core.common.ftp.FTPSDelegate;
import com.arialyy.aria.core.common.ftp.FtpDelegate; import com.arialyy.aria.core.common.ftp.FtpDelegate;
import com.arialyy.aria.core.inf.AbsTaskWrapper;
import com.arialyy.aria.core.inf.IFtpTarget; import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.core.manager.TaskWrapperManager; import com.arialyy.aria.core.manager.TaskWrapperManager;
import com.arialyy.aria.util.ALog;
import java.net.Proxy; import java.net.Proxy;
/** /**
@ -32,7 +28,8 @@ import java.net.Proxy;
*/ */
public class FtpDirDownloadTarget extends AbsDGTarget<FtpDirDownloadTarget> public class FtpDirDownloadTarget extends AbsDGTarget<FtpDirDownloadTarget>
implements IFtpTarget<FtpDirDownloadTarget> { implements IFtpTarget<FtpDirDownloadTarget> {
private FtpDelegate<FtpDirDownloadTarget> mDelegate; private FtpDelegate<FtpDirDownloadTarget> mFtpDelegate;
private FtpDirDelegate mDirDelegate;
FtpDirDownloadTarget(String url, String targetName) { FtpDirDownloadTarget(String url, String targetName) {
setTargetName(targetName); setTargetName(targetName);
@ -40,13 +37,9 @@ public class FtpDirDownloadTarget extends AbsDGTarget<FtpDirDownloadTarget>
} }
private void init(String key) { private void init(String key) {
mGroupHash = key; mDirDelegate = new FtpDirDelegate(this,
setTaskWrapper(TaskWrapperManager.getInstance().getFtpTaskWrapper(DGTaskWrapper.class, key)); TaskWrapperManager.getInstance().getFtpTaskWrapper(DGTaskWrapper.class, key));
getTaskWrapper().setRequestType(AbsTaskWrapper.D_FTP_DIR); mFtpDelegate = new FtpDelegate<>(this);
if (getEntity() != null) {
mDirPathTemp = getEntity().getDirPath();
}
mDelegate = new FtpDelegate<>(this);
} }
@Override public int getTargetType() { @Override public int getTargetType() {
@ -54,62 +47,39 @@ public class FtpDirDownloadTarget extends AbsDGTarget<FtpDirDownloadTarget>
} }
@Override protected boolean checkEntity() { @Override protected boolean checkEntity() {
boolean b = getTargetType() == GROUP_FTP_DIR && checkDirPath() && checkUrl(); return mDirDelegate.checkEntity();
if (b) { }
getEntity().save();
if (getTaskWrapper().getSubTaskWrapper() != null) { @Override public boolean isRunning() {
//初始化子项的登录信息 return mDirDelegate.isRunning();
FtpUrlEntity tUrlEntity = getTaskWrapper().asFtp().getUrlEntity(); }
for (DTaskWrapper wrapper : getTaskWrapper().getSubTaskWrapper()) {
FtpUrlEntity urlEntity = wrapper.asFtp().getUrlEntity(); @Override public boolean taskExists() {
urlEntity.needLogin = tUrlEntity.needLogin; return mDirDelegate.taskExists();
urlEntity.account = tUrlEntity.account;
urlEntity.user = tUrlEntity.user;
urlEntity.password = tUrlEntity.password;
// 处理ftps详细
if (tUrlEntity.isFtps) {
urlEntity.isFtps = true;
urlEntity.protocol = tUrlEntity.protocol;
urlEntity.storePath = tUrlEntity.storePath;
urlEntity.storePass = tUrlEntity.storePass;
urlEntity.keyAlias = tUrlEntity.keyAlias;
}
}
}
}
if (getTaskWrapper().asFtp().getUrlEntity().isFtps) {
if (TextUtils.isEmpty(getTaskWrapper().asFtp().getUrlEntity().storePath)) {
ALog.e(TAG, "证书路径为空");
return false;
}
if (TextUtils.isEmpty(getTaskWrapper().asFtp().getUrlEntity().keyAlias)) {
ALog.e(TAG, "证书别名为空");
return false;
}
}
return b;
} }
/** /**
* 检查普通任务的下载地址 * 设置任务组的文件夹路径在Aria中任务组的所有子任务都会下载到以任务组组名的文件夹中
* groupDirPath = "/mnt/sdcard/download/group_test"
* <pre>
* {@code
* + mnt
* + sdcard
* + download
* + group_test
* - task1.apk
* - task2.apk
* - task3.apk
* ....
*
* }
* </pre>
* *
* @return {@code true}地址合法 * @param dirPath 任务组保存文件夹路径
*/ */
private boolean checkUrl() { @CheckResult
final String url = mGroupHash; public FtpDirDownloadTarget setDirPath(String dirPath) {
if (TextUtils.isEmpty(url)) { return mDirDelegate.setDirPath(dirPath);
ALog.e(TAG, "下载失败,url为null");
return false;
} else if (!url.startsWith("ftp")) {
ALog.e(TAG, "下载失败,url【" + url + "】错误");
return false;
}
int index = url.indexOf("://");
if (index == -1) {
ALog.e(TAG, "下载失败,url【" + url + "】不合法");
return false;
}
return true;
} }
/** /**
@ -125,20 +95,20 @@ public class FtpDirDownloadTarget extends AbsDGTarget<FtpDirDownloadTarget>
@CheckResult @CheckResult
@Override public FtpDirDownloadTarget charSet(String charSet) { @Override public FtpDirDownloadTarget charSet(String charSet) {
return mDelegate.charSet(charSet); return mFtpDelegate.charSet(charSet);
} }
@CheckResult @CheckResult
@Override public FtpDirDownloadTarget login(String userName, String password) { @Override public FtpDirDownloadTarget login(String userName, String password) {
return mDelegate.login(userName, password); return mFtpDelegate.login(userName, password);
} }
@CheckResult @CheckResult
@Override public FtpDirDownloadTarget login(String userName, String password, String account) { @Override public FtpDirDownloadTarget login(String userName, String password, String account) {
return mDelegate.login(userName, password, account); return mFtpDelegate.login(userName, password, account);
} }
@Override public FtpDirDownloadTarget setProxy(Proxy proxy) { @Override public FtpDirDownloadTarget setProxy(Proxy proxy) {
return mDelegate.setProxy(proxy); return mFtpDelegate.setProxy(proxy);
} }
} }

@ -30,7 +30,7 @@ import java.net.Proxy;
* Created by lyy on 2016/12/5. * Created by lyy on 2016/12/5.
* https://github.com/AriaLyy/Aria * https://github.com/AriaLyy/Aria
*/ */
public class FtpDownloadTarget extends AbsDownloadTarget<FtpDownloadTarget> public class FtpDownloadTarget extends AbsDTarget<FtpDownloadTarget>
implements IFtpTarget<FtpDownloadTarget> { implements IFtpTarget<FtpDownloadTarget> {
private FtpDelegate<FtpDownloadTarget> mFtpDelegate; private FtpDelegate<FtpDownloadTarget> mFtpDelegate;
private DNormalDelegate<FtpDownloadTarget> mNormalDelegate; private DNormalDelegate<FtpDownloadTarget> mNormalDelegate;

@ -0,0 +1,238 @@
/*
* 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.download;
import android.support.annotation.CheckResult;
import android.text.TextUtils;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Created by lyy on 2019/4/9.
*
* http组合任务功能代理
*/
class HttpGroupDelegate extends AbsGroupDelegate<DownloadGroupTarget> {
/**
* 子任务下载地址
*/
private List<String> mUrls = new ArrayList<>();
/**
* 子任务文件名
*/
private List<String> mSubNameTemp = new ArrayList<>();
HttpGroupDelegate(DownloadGroupTarget target, DGTaskWrapper wrapper) {
super(target, wrapper);
mUrls.addAll(wrapper.getEntity().getUrls());
}
@CheckResult
DownloadGroupTarget setGroupUrl(List<String> urls) {
mUrls.clear();
mUrls.addAll(urls);
return getTarget();
}
/**
* 设置子任务文件名该方法必须在{@link #setDirPath(String)}之后调用否则不生效
*/
@CheckResult
DownloadGroupTarget setSubFileName(List<String> subTaskFileName) {
if (subTaskFileName == null || subTaskFileName.isEmpty()) {
ALog.e(TAG, "修改子任务的文件名失败:列表为null");
return getTarget();
}
if (subTaskFileName.size() != getTaskWrapper().getSubTaskWrapper().size()) {
ALog.e(TAG, "修改子任务的文件名失败:子任务文件名列表数量和子任务的数量不匹配");
return getTarget();
}
mSubNameTemp.clear();
mSubNameTemp.addAll(subTaskFileName);
return getTarget();
}
/**
* 更新组合任务下载地址
*
* @param urls 新的组合任务下载地址列表
*/
@CheckResult
DownloadGroupTarget updateUrls(List<String> urls) {
if (urls == null || urls.isEmpty()) {
throw new NullPointerException("下载地址列表为空");
}
if (urls.size() != mUrls.size()) {
throw new IllegalArgumentException("新下载地址数量和旧下载地址数量不一致");
}
mUrls.clear();
mUrls.addAll(urls);
String newHash = CommonUtil.getMd5Code(urls);
setGroupHash(newHash);
getEntity().setGroupHash(newHash);
getEntity().update();
if (getEntity().getSubEntities() != null && !getEntity().getSubEntities().isEmpty()) {
for (DownloadEntity de : getEntity().getSubEntities()) {
de.setGroupHash(newHash);
de.update();
}
}
return getTarget();
}
@Override public boolean checkEntity() {
if (!checkDirPath()) {
return false;
}
if (!checkSubName()) {
return false;
}
if (!checkUrls()) {
return false;
}
if (getTaskWrapper().getEntity().getFileSize() == 0) {
ALog.e(TAG, "组合任务必须设置文件文件大小");
return false;
}
if (getTaskWrapper().asHttp().getRequestEnum() == RequestEnum.POST) {
for (DTaskWrapper subTask : getTaskWrapper().getSubTaskWrapper()) {
subTask.asHttp().setRequestEnum(RequestEnum.POST);
}
}
getEntity().save();
if (isNeedModifyPath()) {
reChangeDirPath(getDirPathTemp());
}
if (!mSubNameTemp.isEmpty()) {
updateSingleSubFileName();
}
return true;
}
/**
* 更新所有改动的子任务文件名
*/
private void updateSingleSubFileName() {
List<DTaskWrapper> entities = getTaskWrapper().getSubTaskWrapper();
int i = 0;
for (DTaskWrapper entity : entities) {
if (i < mSubNameTemp.size()) {
String newName = mSubNameTemp.get(i);
updateSingleSubFileName(entity, newName);
}
i++;
}
}
/**
* 检查urls是否合法并删除不合法的子任务
*
* @return {@code true} 合法
*/
private boolean checkUrls() {
if (mUrls.isEmpty()) {
ALog.e(TAG, "下载失败,子任务下载列表为null");
return false;
}
Set<Integer> delItem = new HashSet<>();
int i = 0;
for (String url : mUrls) {
if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "子任务url为null,即将删除该子任务。");
delItem.add(i);
continue;
} else if (!url.startsWith("http")) {
//} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
ALog.e(TAG, "子任务url【" + url + "】错误,即将删除该子任务。");
delItem.add(i);
continue;
}
int index = url.indexOf("://");
if (index == -1) {
ALog.e(TAG, "子任务url【" + url + "】不合法,即将删除该子任务。");
delItem.add(i);
continue;
}
i++;
}
for (int index : delItem) {
mUrls.remove(index);
if (mSubNameTemp != null && !mSubNameTemp.isEmpty()) {
mSubNameTemp.remove(index);
}
}
getEntity().setGroupHash(CommonUtil.getMd5Code(mUrls));
return true;
}
/**
* 更新单个子任务文件名
*/
private void updateSingleSubFileName(DTaskWrapper taskEntity, String newName) {
DownloadEntity entity = taskEntity.getEntity();
if (!newName.equals(entity.getFileName())) {
String oldPath = getEntity().getDirPath() + "/" + entity.getFileName();
String newPath = getEntity().getDirPath() + "/" + newName;
if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=? or isComplete='true'",
newPath)) {
ALog.w(TAG, String.format("更新文件名失败,路径【%s】已存在或文件已下载", newPath));
return;
}
CommonUtil.modifyTaskRecord(oldPath, newPath);
entity.setDownloadPath(newPath);
entity.setFileName(newName);
entity.update();
}
}
/**
* 如果用户设置了子任务文件名检查子任务文件名
*
* @return {@code true} 合法
*/
private boolean checkSubName() {
if (mSubNameTemp == null || mSubNameTemp.isEmpty()) {
return true;
}
if (mUrls.size() != mSubNameTemp.size()) {
ALog.e(TAG, "子任务文件名必须和子任务数量一致");
return false;
}
return true;
}
}

@ -0,0 +1,58 @@
/*
* 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;
/**
* Created by lyy on 2019/4/5.
* 组合任务接收器功能接口
*/
public interface IGroupTarget {
/**
* 获取实体
*/
AbsEntity getEntity();
/**
* 任务是否存在
*
* @return {@code true}任务存在{@code false} 任务不存在
*/
boolean taskExists();
/**
* 任务是否在执行
*
* @return {@code true} 任务正在执行{@code false} 任务没有执行
*/
boolean isRunning();
/**
* 检查实体是否合法
*
* @return {@code true}合法
*/
boolean checkEntity();
/**
* 检查文件夹路径
* 1文件夹路径不能为空
* 2文件夹路径不能是文件
*
* @return {@code true} 合法
*/
boolean checkDirPath();
}

@ -19,22 +19,7 @@ package com.arialyy.aria.core.inf;
* Created by lyy on 2019/4/5. * Created by lyy on 2019/4/5.
* 普通任务接收器功能接口 * 普通任务接收器功能接口
*/ */
public interface ITargetNormal<TARGET extends AbsTarget> { public interface INormalTarget {
/**
* 通过地址初始化target
*
* @param url 下载url上传url
* @param targetName 接收器名称
*/
void initTarget(String url, String targetName);
/**
* 更新下载url
*
* @param newUrl 新的下载url
*/
TARGET updateUrl(String newUrl);
/** /**
* 获取实体 * 获取实体

@ -17,7 +17,7 @@ package com.arialyy.aria.core.upload;
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.ITargetNormal; import com.arialyy.aria.core.inf.INormalTarget;
import com.arialyy.aria.core.manager.TaskWrapperManager; import com.arialyy.aria.core.manager.TaskWrapperManager;
import com.arialyy.aria.core.queue.UploadTaskQueue; import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
@ -29,7 +29,7 @@ import java.io.File;
* Created by Aria.Lao on 2019/4/5. * Created by Aria.Lao on 2019/4/5.
* 普通上传任务通用功能处理 * 普通上传任务通用功能处理
*/ */
class UNormalDelegate<TARGET extends AbsUploadTarget> implements ITargetNormal<TARGET> { class UNormalDelegate<TARGET extends AbsUploadTarget> implements INormalTarget {
private String TAG = "UNormalDelegate"; private String TAG = "UNormalDelegate";
private UploadEntity mEntity; private UploadEntity mEntity;
private TARGET mTarget; private TARGET mTarget;
@ -43,7 +43,7 @@ class UNormalDelegate<TARGET extends AbsUploadTarget> implements ITargetNormal<T
initTarget(filePath, targetName); initTarget(filePath, targetName);
} }
@Override public void initTarget(String filePath, String targetName) { private void initTarget(String filePath, String targetName) {
UTaskWrapper taskWrapper = UTaskWrapper taskWrapper =
TaskWrapperManager.getInstance().getHttpTaskWrapper(UTaskWrapper.class, filePath); TaskWrapperManager.getInstance().getHttpTaskWrapper(UTaskWrapper.class, filePath);
mEntity = taskWrapper.getEntity(); mEntity = taskWrapper.getEntity();
@ -55,7 +55,7 @@ class UNormalDelegate<TARGET extends AbsUploadTarget> implements ITargetNormal<T
mTempUrl = mEntity.getUrl(); mTempUrl = mEntity.getUrl();
} }
@Override public TARGET updateUrl(String newUrl) { TARGET updateUrl(String newUrl) {
mTempUrl = newUrl; mTempUrl = newUrl;
return mTarget; return mTarget;
} }

@ -1,263 +1,257 @@
/* /*
* 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.orm; package com.arialyy.aria.orm;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import android.text.TextUtils; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.core.download.DTaskWrapper; import java.util.ArrayList;
import com.arialyy.aria.core.download.DownloadEntity; import java.util.HashMap;
import com.arialyy.aria.util.ALog; import java.util.List;
import java.lang.reflect.Field; import java.util.Map;
import java.util.ArrayList; import java.util.Set;
import java.util.Arrays;
import java.util.HashMap; /**
import java.util.List; * Created by lyy on 2015/11/2.
import java.util.Map; * sql帮助类
import java.util.Set; */
final class SqlHelper extends SQLiteOpenHelper {
/** private static final String TAG = "SqlHelper";
* Created by lyy on 2015/11/2. static volatile SqlHelper INSTANCE = null;
* sql帮助类
*/ private DelegateCommon mDelegate;
final class SqlHelper extends SQLiteOpenHelper {
private static final String TAG = "SqlHelper"; synchronized static SqlHelper init(Context context) {
static volatile SqlHelper INSTANCE = null; if (INSTANCE == null) {
synchronized (SqlHelper.class) {
private DelegateCommon mDelegate; DelegateCommon delegate = DelegateManager.getInstance().getDelegate(DelegateCommon.class);
INSTANCE = new SqlHelper(context.getApplicationContext(), delegate);
static SqlHelper init(Context context) { SQLiteDatabase db = INSTANCE.getWritableDatabase();
if (INSTANCE == null) { db = delegate.checkDb(db);
synchronized (SqlHelper.class) { // SQLite在3.6.19版本中开始支持外键约束,
DelegateCommon delegate = DelegateManager.getInstance().getDelegate(DelegateCommon.class); // 而在Android中 2.1以前的版本使用的SQLite版本是3.5.9, 在2.2版本中使用的是3.6.22.
INSTANCE = new SqlHelper(context.getApplicationContext(), delegate); // 但是为了兼容以前的程序,默认并没有启用该功能,如果要启用该功能
SQLiteDatabase db = INSTANCE.getWritableDatabase(); // 需要使用如下语句:
db = delegate.checkDb(db); db.execSQL("PRAGMA foreign_keys=ON;");
// SQLite在3.6.19版本中开始支持外键约束, Set<String> tables = DBConfig.mapping.keySet();
// 而在Android中 2.1以前的版本使用的SQLite版本是3.5.9, 在2.2版本中使用的是3.6.22. for (String tableName : tables) {
// 但是为了兼容以前的程序,默认并没有启用该功能,如果要启用该功能 Class clazz = DBConfig.mapping.get(tableName);
// 需要使用如下语句:
db.execSQL("PRAGMA foreign_keys=ON;"); if (!delegate.tableExists(db, clazz)) {
Set<String> tables = DBConfig.mapping.keySet(); delegate.createTable(db, clazz);
for (String tableName : tables) { }
Class clazz = null; }
clazz = DBConfig.mapping.get(tableName); }
}
if (!delegate.tableExists(db, clazz)) { return INSTANCE;
delegate.createTable(db, clazz); }
}
} private SqlHelper(Context context, DelegateCommon delegate) {
} super(DBConfig.SAVE_IN_SDCARD ? new DatabaseContext(context) : context, DBConfig.DB_NAME, null,
} DBConfig.VERSION);
return INSTANCE; mDelegate = delegate;
} }
private SqlHelper(Context context, DelegateCommon delegate) { @Override public void onCreate(SQLiteDatabase db) {
super(DBConfig.SAVE_IN_SDCARD ? new DatabaseContext(context) : context, DBConfig.DB_NAME, null,
DBConfig.VERSION); }
mDelegate = delegate;
} @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < newVersion) {
@Override public void onCreate(SQLiteDatabase db) { if (oldVersion < 31) {
handle314AriaUpdate(db);
} } else if (oldVersion < 45) {
handle360AriaUpdate(db);
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } else {
if (oldVersion < newVersion) { handleDbUpdate(db, null, null);
if (oldVersion < 31) { }
handle314AriaUpdate(db); }
} else if (oldVersion < 45) { }
handle360AriaUpdate(db);
} else { @Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
handleDbUpdate(db, null, null); if (oldVersion > newVersion) {
} handleDbUpdate(db, null, null);
} }
} }
@Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { /**
if (oldVersion > newVersion) { * 处理数据库升级该段代码无法修改表字段
handleDbUpdate(db, null, null); *
} * @param modifyColumns 需要修改的表字段的映射key为表名
} * value{@code Map<String, String>}中的Map的key为老字段名称value为该老字段对应的新字段名称
* @param delColumns 需要删除的表字段key为表名value{@code List<String>}为需要删除的字段列表
/** */
* 处理数据库升级该段代码无法修改表字段 private void handleDbUpdate(SQLiteDatabase db, Map<String, Map<String, String>> modifyColumns,
* Map<String, List<String>> delColumns) {
* @param modifyColumns 需要修改的表字段的映射key为表名 if (db == null) {
* value{@code Map<String, String>}中的Map的key为老字段名称value为该老字段对应的新字段名称 ALog.e("SqlHelper", "db 为 null");
* @param delColumns 需要删除的表字段key为表名value{@code List<String>}为需要删除的字段列表 return;
*/ } else if (!db.isOpen()) {
private void handleDbUpdate(SQLiteDatabase db, Map<String, Map<String, String>> modifyColumns, ALog.e("SqlHelper", "db已关闭");
Map<String, List<String>> delColumns) { return;
if (db == null) { }
ALog.e("SqlHelper", "db 为 null");
return; try {
} else if (!db.isOpen()) { db.beginTransaction();
ALog.e("SqlHelper", "db已关闭"); Set<String> tables = DBConfig.mapping.keySet();
return; for (String tableName : tables) {
} Class clazz = DBConfig.mapping.get(tableName);
if (mDelegate.tableExists(db, clazz)) {
try { db = mDelegate.checkDb(db);
db.beginTransaction(); //修改表名为中介表名
Set<String> tables = DBConfig.mapping.keySet(); String alertSql = String.format("ALTER TABLE %s RENAME TO %s_temp", tableName, tableName);
for (String tableName : tables) { db.execSQL(alertSql);
Class clazz = DBConfig.mapping.get(tableName);
if (mDelegate.tableExists(db, clazz)) { //创建新表
db = mDelegate.checkDb(db); mDelegate.createTable(db, clazz);
//修改表名为中介表名
String alertSql = String.format("ALTER TABLE %s RENAME TO %s_temp", tableName, tableName); String sql = String.format("SELECT COUNT(*) FROM %s_temp", tableName);
db.execSQL(alertSql); Cursor cursor = db.rawQuery(sql, null);
cursor.moveToFirst();
//创建新表 long count = cursor.getLong(0);
mDelegate.createTable(db, clazz); cursor.close();
String sql = String.format("SELECT COUNT(*) FROM %s_temp", tableName); if (count > 0) {
Cursor cursor = db.rawQuery(sql, null); // 获取所有表字段名称
cursor.moveToFirst(); Cursor columnC =
long count = cursor.getLong(0); db.rawQuery(String.format("PRAGMA table_info(%s_temp)", tableName), null);
cursor.close(); StringBuilder params = new StringBuilder();
if (count > 0) { while (columnC.moveToNext()) {
// 获取所有表字段名称 String columnName = columnC.getString(columnC.getColumnIndex("name"));
Cursor columnC = if (delColumns != null && delColumns.get(tableName) != null) {
db.rawQuery(String.format("PRAGMA table_info(%s_temp)", tableName), null); List<String> delColumn = delColumns.get(tableName);
StringBuilder params = new StringBuilder(); if (delColumn != null && !delColumn.isEmpty()) {
if (delColumn.contains(columnName)) {
while (columnC.moveToNext()) { continue;
String columnName = columnC.getString(columnC.getColumnIndex("name")); }
if (delColumns != null && delColumns.get(tableName) != null) { }
List<String> delColumn = delColumns.get(tableName); }
if (delColumn != null && !delColumn.isEmpty()) {
if (delColumn.contains(columnName)) { params.append(columnName).append(",");
continue; }
} columnC.close();
}
} String oldParamStr = params.toString();
oldParamStr = oldParamStr.substring(0, oldParamStr.length() - 1);
params.append(columnName).append(","); String newParamStr = oldParamStr;
} // 处理字段名称改变
columnC.close(); if (modifyColumns != null) {
//newParamStr = params.toString();
String oldParamStr = params.toString(); Map<String, String> columnMap = modifyColumns.get(tableName);
oldParamStr = oldParamStr.substring(0, oldParamStr.length() - 1); if (columnMap != null && !columnMap.isEmpty()) {
String newParamStr = oldParamStr; Set<String> keys = columnMap.keySet();
// 处理字段名称改变 for (String key : keys) {
if (modifyColumns != null) { if (newParamStr.contains(key)) {
//newParamStr = params.toString(); newParamStr = newParamStr.replace(key, columnMap.get(key));
Map<String, String> columnMap = modifyColumns.get(tableName); }
if (columnMap != null && !columnMap.isEmpty()) { }
Set<String> keys = columnMap.keySet(); }
for (String key : keys) { }
if (newParamStr.contains(key)) { //恢复数据
newParamStr = newParamStr.replace(key, columnMap.get(key)); String insertSql =
} String.format("INSERT INTO %s (%s) SELECT %s FROM %s_temp", tableName, newParamStr,
} oldParamStr, tableName);
} ALog.d(TAG, "insertSql = " + insertSql);
} db.execSQL(insertSql);
//恢复数据 }
String insertSql = //删除中介表
String.format("INSERT INTO %s (%s) SELECT %s FROM %s_temp", tableName, newParamStr, mDelegate.dropTable(db, tableName + "_temp");
oldParamStr, tableName); }
ALog.d(TAG, "insertSql = " + insertSql); }
db.execSQL(insertSql); db.setTransactionSuccessful();
} } catch (Exception e) {
//删除中介表 ALog.e(TAG, e);
mDelegate.dropTable(db, tableName + "_temp"); } finally {
} db.endTransaction();
} }
db.setTransactionSuccessful();
} catch (Exception e) { mDelegate.close(db);
ALog.e(TAG, e); }
} finally {
db.endTransaction(); /**
} * 处理3.6以下版本的数据库升级
*/
mDelegate.close(db); private void handle360AriaUpdate(SQLiteDatabase db) {
} String[] taskTables =
new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" };
/** for (String taskTable : taskTables) {
* 处理3.6以下版本的数据库升级 if (mDelegate.tableExists(db, taskTable)) {
*/ mDelegate.dropTable(db, taskTable);
private void handle360AriaUpdate(SQLiteDatabase db) { }
String[] taskTables = }
new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" }; Map<String, Map<String, String>> columnMap = new HashMap<>();
for (String taskTable : taskTables) { Map<String, String> map = new HashMap<>();
if (mDelegate.tableExists(db, taskTable)) { map.put("groupName", "groupHash");
mDelegate.dropTable(db, taskTable); columnMap.put("DownloadEntity", map);
} columnMap.put("DownloadGroupEntity", map);
} handleDbUpdate(db, columnMap, null);
Map<String, Map<String, String>> columnMap = new HashMap<>(); }
Map<String, String> map = new HashMap<>();
map.put("groupName", "groupHash"); /**
columnMap.put("DownloadEntity", map); * 处理3.4版本之前数据库迁移主要是修改子表外键字段对应的值
columnMap.put("DownloadGroupEntity", map); */
handleDbUpdate(db, columnMap, null); private void handle314AriaUpdate(SQLiteDatabase db) {
} String[] taskTables =
new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" };
/** for (String taskTable : taskTables) {
* 处理3.4版本之前数据库迁移主要是修改子表外键字段对应的值 if (mDelegate.tableExists(db, taskTable)) {
*/ mDelegate.dropTable(db, taskTable);
private void handle314AriaUpdate(SQLiteDatabase db) { }
String[] taskTables = }
new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" };
for (String taskTable : taskTables) { //删除所有主键为null和逐渐重复的数据
if (mDelegate.tableExists(db, taskTable)) { String[] tables = new String[] { "DownloadEntity", "DownloadGroupEntity" };
mDelegate.dropTable(db, taskTable); String[] keys = new String[] { "downloadPath", "groupName" };
} int i = 0;
} for (String tableName : tables) {
String pColumn = keys[i];
//删除所有主键为null和逐渐重复的数据 String nullSql =
String[] tables = new String[] { "DownloadEntity", "DownloadGroupEntity" }; String.format("DELETE FROM %s WHERE %s='' OR %s IS NULL", tableName, pColumn, pColumn);
String[] keys = new String[] { "downloadPath", "groupName" }; ALog.d(TAG, nullSql);
int i = 0; db.execSQL(nullSql);
for (String tableName : tables) {
String pColumn = keys[i]; //删除所有主键重复的数据
String nullSql = String repeatSql =
String.format("DELETE FROM %s WHERE %s='' OR %s IS NULL", tableName, pColumn, pColumn); String.format(
ALog.d(TAG, nullSql); "DELETE FROM %s WHERE %s IN(SELECT %s FROM %s GROUP BY %s HAVING COUNT(%s) > 1)",
db.execSQL(nullSql); tableName, pColumn, pColumn, tableName, pColumn, pColumn);
//删除所有主键重复的数据 ALog.d(TAG, repeatSql);
String repeatSql = db.execSQL(repeatSql);
String.format( i++;
"DELETE FROM %s WHERE %s IN(SELECT %s FROM %s GROUP BY %s HAVING COUNT(%s) > 1)", }
tableName, pColumn, pColumn, tableName, pColumn, pColumn);
Map<String, Map<String, String>> modifyColumnMap = new HashMap<>();
ALog.d(TAG, repeatSql); Map<String, String> map = new HashMap<>();
db.execSQL(repeatSql); map.put("groupName", "groupHash");
i++; modifyColumnMap.put("DownloadEntity", map);
} modifyColumnMap.put("DownloadGroupEntity", map);
Map<String, Map<String, String>> modifyColumnMap = new HashMap<>(); Map<String, List<String>> delColumnMap = new HashMap<>();
Map<String, String> map = new HashMap<>(); List<String> dEntityDel = new ArrayList<>();
map.put("groupName", "groupHash"); dEntityDel.add("taskKey");
modifyColumnMap.put("DownloadEntity", map); delColumnMap.put("DownloadEntity", dEntityDel);
modifyColumnMap.put("DownloadGroupEntity", map); List<String> dgEntityDel = new ArrayList<>();
dgEntityDel.add("subtask");
Map<String, List<String>> delColumnMap = new HashMap<>(); delColumnMap.put("DownloadGroupEntity", dgEntityDel);
List<String> dEntityDel = new ArrayList<>();
dEntityDel.add("taskKey"); handleDbUpdate(db, modifyColumnMap, delColumnMap);
delColumnMap.put("DownloadEntity", dEntityDel); }
List<String> dgEntityDel = new ArrayList<>();
dgEntityDel.add("subtask");
delColumnMap.put("DownloadGroupEntity", dgEntityDel);
handleDbUpdate(db, modifyColumnMap, delColumnMap);
}
} }

@ -7,8 +7,9 @@ Aria项目源于工作中遇到的一个文件下载管理的需求,当时被
Aria有以下特点: Aria有以下特点:
+ 简单、方便 + 简单、方便
- 可以在Activity、Service、Fragment、Dialog、popupWindow、Notification等组件中使用 - 可以在Activity、Service、Fragment、Dialog、popupWindow、Notification等组件中使用
- 支持HTTP\FTP断点续传、多任务自动调度 - 支持HTTP\FTP断点续传下载、多任务自动调度
- 支持HTTP任务组\FTP文件夹,断点续传下载 - 支持多文件打包下载,多文件共享同一进度(如:视频 + 封面 + 字幕)
- 支持下载FTP文件夹
- 支持HTTP表单上传 - 支持HTTP表单上传
- 支持文件FTP断点续传上传 - 支持文件FTP断点续传上传
- 支持FTPS/SFTP断点续传,[see](https://aria.laoyuyu.me/aria_doc/download/ftps.html) - 支持FTPS/SFTP断点续传,[see](https://aria.laoyuyu.me/aria_doc/download/ftps.html)
@ -23,12 +24,17 @@ Aria有以下特点:
如果你觉得Aria对你有帮助,您的star和issues将是对我最大支持.`^_^` 如果你觉得Aria对你有帮助,您的star和issues将是对我最大支持.`^_^`
## 示例 ## 示例
* 多任务下载
![多任务下载](https://github.com/AriaLyy/DownloadUtil/blob/master/img/download_img.gif) ![多任务下载](https://github.com/AriaLyy/DownloadUtil/blob/master/img/download_img.gif)
* 速度限制
![网速下载限制](https://github.com/AriaLyy/DownloadUtil/blob/master/img/max_speed.gif) ![网速下载限制](https://github.com/AriaLyy/DownloadUtil/blob/master/img/max_speed.gif)
![下载任务组](https://github.com/AriaLyy/DownloadUtil/blob/master/img/download_group.gif)
* 多文件打包下载
![多文件打包下载](https://github.com/AriaLyy/DownloadUtil/blob/master/img/group_task.gif)
## 下载 ## 引入库
[![Core](https://api.bintray.com/packages/arialyy/maven/AriaApi/images/download.svg)](https://bintray.com/arialyy/maven/AriaApi/_latestVersion) [![Core](https://api.bintray.com/packages/arialyy/maven/AriaApi/images/download.svg)](https://bintray.com/arialyy/maven/AriaApi/_latestVersion)
[![Compiler](https://api.bintray.com/packages/arialyy/maven/AriaCompiler/images/download.svg)](https://bintray.com/arialyy/maven/AriaCompiler/_latestVersion) [![Compiler](https://api.bintray.com/packages/arialyy/maven/AriaCompiler/images/download.svg)](https://bintray.com/arialyy/maven/AriaCompiler/_latestVersion)

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 KiB

Loading…
Cancel
Save