优化组合任务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> {
/**
* 组任务名
*/
String mGroupHash;
/**
* 文件夹临时路径
*/
String mDirPathTemp;
/**
* 是否需要修改路径
*/
boolean needModifyPath = false;
///**
// * 组任务名
// */
//String mGroupHash;
///**
// * 文件夹临时路径
// */
//String mDirPathTemp;
///**
// * 是否需要修改路径
// */
//boolean needModifyPath = false;
private SubTaskManager mSubTaskManager;
@ -79,93 +79,93 @@ abstract class AbsDGTarget<TARGET extends AbsDGTarget> extends AbsTarget<TARGET>
return (TARGET) this;
}
@Override public boolean taskExists() {
return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", mGroupHash);
}
//@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;
}
///**
// * 设置任务组的文件夹路径,在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();
}
//@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;
}
///**
// * 改变任务组文件夹路径,修改文件夹路径会将子任务所有路径更换
// *
// * @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);
// }
//}
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;
}
///**
// * 检查并设置文件夹路径
// *
// * @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;
//}
}

@ -23,7 +23,7 @@ import com.arialyy.aria.util.CommonUtil;
/**
* 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

@ -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 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.queue.DownloadTaskQueue;
import com.arialyy.aria.orm.DbEntity;
@ -29,7 +29,7 @@ import java.io.File;
* 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 DownloadEntity mEntity;
@ -54,7 +54,7 @@ class DNormalDelegate<TARGET extends AbsDownloadTarget> implements ITargetNormal
initTarget(url, targetName);
}
@Override public void initTarget(String url, String targetName) {
private void initTarget(String url, String targetName) {
DTaskWrapper taskWrapper =
TaskWrapperManager.getInstance().getHttpTaskWrapper(DTaskWrapper.class, url);
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)) {
ALog.e(TAG, "url更新失败,newUrl为null");
return mTarget;

@ -17,21 +17,15 @@ package com.arialyy.aria.core.download;
import android.support.annotation.CheckResult;
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.PostDelegate;
import com.arialyy.aria.core.inf.IHttpHeaderDelegate;
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.CommonUtil;
import java.net.Proxy;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Created by AriaL on 2017/6/29.
@ -39,43 +33,33 @@ import java.util.Set;
*/
public class DownloadGroupTarget extends AbsDGTarget<DownloadGroupTarget> implements
IHttpHeaderDelegate<DownloadGroupTarget> {
private HttpHeaderDelegate<DownloadGroupTarget> mDelegate;
/**
* 子任务下载地址
*/
private List<String> mUrls = new ArrayList<>();
/**
* 子任务文件名
*/
private List<String> mSubNameTemp = new ArrayList<>();
private HttpHeaderDelegate<DownloadGroupTarget> mHeaderDelegate;
private HttpGroupDelegate mGroupDelegate;
public DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) {
DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) {
setTargetName(targetName);
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) {
setTargetName(targetName);
this.mUrls = urls;
init();
init(urls);
}
private void init() {
mGroupHash = CommonUtil.getMd5Code(mUrls);
setTaskWrapper(TaskWrapperManager.getInstance().getDGTaskWrapper(DGTaskWrapper.class, mUrls));
if (getEntity() != null) {
mDirPathTemp = getEntity().getDirPath();
}
mDelegate = new HttpHeaderDelegate<>(this);
private void init(List<String> urls) {
mGroupDelegate = new HttpGroupDelegate(this,
TaskWrapperManager.getInstance().getDGTaskWrapper(DGTaskWrapper.class, urls));
mHeaderDelegate = new HttpHeaderDelegate<>(this);
}
/**
* Post处理
*/
@CheckResult
public PostDelegate asPost() {
return new PostDelegate<>(this);
}
@ -87,24 +71,7 @@ public class DownloadGroupTarget extends AbsDGTarget<DownloadGroupTarget> implem
*/
@CheckResult
public 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);
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;
return mGroupDelegate.updateUrls(urls);
}
/**
@ -132,9 +99,7 @@ public class DownloadGroupTarget extends AbsDGTarget<DownloadGroupTarget> implem
*/
@CheckResult
public DownloadGroupTarget setGroupUrl(List<String> urls) {
mUrls.clear();
mUrls.addAll(urls);
return this;
return mGroupDelegate.setGroupUrl(urls);
}
/**
@ -147,22 +112,36 @@ public class DownloadGroupTarget extends AbsDGTarget<DownloadGroupTarget> implem
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)}之后调用否则不生效
*/
@CheckResult
public DownloadGroupTarget setSubFileName(List<String> subTaskFileName) {
if (subTaskFileName == null || subTaskFileName.isEmpty()) {
ALog.e(TAG, "修改子任务的文件名失败:列表为null");
return this;
}
if (subTaskFileName.size() != getTaskWrapper().getSubTaskWrapper().size()) {
ALog.e(TAG, "修改子任务的文件名失败:子任务文件名列表数量和子任务的数量不匹配");
return this;
}
mSubNameTemp.clear();
mSubNameTemp.addAll(subTaskFileName);
return this;
return mGroupDelegate.setSubFileName(subTaskFileName);
}
@Override public int getTargetType() {
@ -170,161 +149,35 @@ public class DownloadGroupTarget extends AbsDGTarget<DownloadGroupTarget> implem
}
@Override protected boolean checkEntity() {
if (getTargetType() == GROUP_HTTP) {
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;
return mGroupDelegate.checkEntity();
}
/**
* 更新单个子任务文件名
*/
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 isRunning() {
return mGroupDelegate.isRunning();
}
/**
* 如果用户设置了子任务文件名检查子任务文件名
*
* @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;
@Override public boolean taskExists() {
return mGroupDelegate.taskExists();
}
@CheckResult
@Override public DownloadGroupTarget addHeader(@NonNull String key, @NonNull String value) {
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
@Override public DownloadGroupTarget addHeaders(Map<String, String> headers) {
for (DTaskWrapper subTask : getTaskWrapper().getSubTaskWrapper()) {
mDelegate.addHeaders(subTask, headers);
mHeaderDelegate.addHeaders(subTask, headers);
}
return mDelegate.addHeaders(headers);
return mHeaderDelegate.addHeaders(headers);
}
@CheckResult
@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)
*
* 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.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.command.normal.CancelAllCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.ProxyHelper;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsReceiver;
import com.arialyy.aria.core.inf.ReceiverType;
import com.arialyy.aria.core.manager.TaskWrapperManager;
import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers;
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Created by lyy on 2016/12/5.
* 下载功能接收器
*/
public class DownloadReceiver extends AbsReceiver {
private final String TAG = "DownloadReceiver";
/**
* 设置最大下载速度单位kb
*
* @param maxSpeed 为0表示不限速
* @deprecated {@code Aria.get(Context).getDownloadConfig().setMaxSpeed(int)}
*/
@Deprecated
public DownloadReceiver setMaxSpeed(int maxSpeed) {
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().setMaxSpeed(maxSpeed);
return this;
}
/**
* 使用下载实体执行下载操作
*
* @param entity 下载实体
*/
@CheckResult
public DownloadTarget load(DownloadEntity entity) {
CheckUtil.checkUrlInvalidThrow(entity.getUrl());
return new DownloadTarget(entity, targetName);
}
/**
* 加载Httphttps单任务下载地址
*
* @param url 下载地址
*/
@CheckResult
public DownloadTarget load(@NonNull String url) {
CheckUtil.checkUrlInvalidThrow(url);
return new DownloadTarget(url, targetName);
}
/**
* 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组
*
* @param urls 任务组子任务下载地址列表
* @deprecated {@link #loadGroup(DownloadGroupEntity)}
*/
@Deprecated
@CheckResult
public DownloadGroupTarget load(List<String> urls) {
return loadGroup(urls);
}
/**
* 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组
*/
@CheckResult
public DownloadGroupTarget loadGroup(List<String> urls) {
CheckUtil.checkDownloadUrls(urls);
return new DownloadGroupTarget(urls, targetName);
}
/**
* 使用下载实体执行FTP下载操作
*
* @param entity 下载实体
*/
@CheckResult
public FtpDownloadTarget loadFtp(DownloadEntity entity) {
CheckUtil.checkUrlInvalidThrow(entity.getUrl());
return new FtpDownloadTarget(entity, targetName);
}
/**
* 加载ftp单任务下载地址
*/
@CheckResult
public FtpDownloadTarget loadFtp(@NonNull String url) {
CheckUtil.checkUrlInvalidThrow(url);
return new FtpDownloadTarget(url, targetName);
}
/**
* 使用任务组实体执行任务组的实体执行任务组的下载操作后续版本会删除该api
*
* @param groupEntity 如果加载的任务实体没有子项的下载地址
* 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址
* @deprecated 请使用 {@link #loadGroup(DownloadGroupEntity)}
*/
@Deprecated
@CheckResult
public DownloadGroupTarget load(DownloadGroupEntity groupEntity) {
CheckUtil.checkDownloadUrls(groupEntity.getUrls());
return loadGroup(groupEntity);
}
/**
* 使用任务组实体执行任务组的实体执行任务组的下载操作
*
* @param groupEntity 如果加载的任务实体没有子项的下载地址
* 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址
*/
@CheckResult
public DownloadGroupTarget loadGroup(DownloadGroupEntity groupEntity) {
CheckUtil.checkDownloadUrls(groupEntity.getUrls());
return new DownloadGroupTarget(groupEntity, targetName);
}
/**
* 加载ftp文件夹下载地址
*/
@CheckResult
public FtpDirDownloadTarget loadFtpDir(@NonNull String dirUrl) {
CheckUtil.checkUrlInvalidThrow(dirUrl);
return new FtpDirDownloadTarget(dirUrl, targetName);
}
/**
* 将当前类注册到Aria
*/
public void register() {
if (TextUtils.isEmpty(targetName)) {
ALog.e(TAG, "download register target null");
return;
}
Object obj = OBJ_MAP.get(getKey());
if (obj == null) {
ALog.e(TAG, String.format("【%s】观察者为空", targetName));
return;
}
Set<Integer> set = ProxyHelper.getInstance().checkProxyType(obj.getClass());
if (set != null && !set.isEmpty()) {
for (Integer type : set) {
if (type == ProxyHelper.PROXY_TYPE_DOWNLOAD) {
DownloadSchedulers.getInstance().register(obj);
} else if (type == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) {
DownloadGroupSchedulers.getInstance().register(obj);
}
}
} else {
ALog.w(TAG, "没有Aria的注解方法");
}
}
/**
* 取消注册如果是Activity或fragmentAria会界面销毁时自动调用该方法不需要你手动调用
* 注意事项
* 1如果在activity中一定要调用该方法那么请在{@code onDestroy()}中调用
* 2不要在activity的{@code onStop()}中调用改方法
* 3如果是Dialog或popupwindow需要你在撤销界面时调用该方法
* 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>
*/
@Override public void unRegister() {
if (needRmListener) {
unRegisterListener();
}
AriaManager.getInstance(AriaManager.APP).removeReceiver(OBJ_MAP.get(getKey()));
}
@Override public String getType() {
return ReceiverType.DOWNLOAD;
}
@Override protected void unRegisterListener() {
if (TextUtils.isEmpty(targetName)) {
ALog.e(TAG, "download unRegisterListener target null");
return;
}
Object obj = OBJ_MAP.get(getKey());
if (obj == null) {
ALog.e(TAG, String.format("【%s】观察者为空", targetName));
return;
}
Set<Integer> set = ProxyHelper.getInstance().mProxyCache.get(obj.getClass().getName());
if (set != null) {
for (Integer integer : set) {
if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD) {
DownloadSchedulers.getInstance().unRegister(obj);
} else if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) {
DownloadGroupSchedulers.getInstance().unRegister(obj);
}
}
}
}
/**
* 通过下载链接获取下载实体
*
* @return 如果url错误或查找不到数据则返回null
*/
public DownloadEntity getDownloadEntity(String downloadUrl) {
if (!CheckUtil.checkUrl(downloadUrl)) {
return null;
}
return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl);
}
/**
* 通过下载地址和文件保存路径获取下载任务实体
*
* @param downloadUrl 下载地址
* @return 如果url错误或查找不到数据则返回null
*/
public DTaskWrapper getDownloadTask(String downloadUrl) {
if (!CheckUtil.checkUrl(downloadUrl)) {
return null;
}
if (!taskExists(downloadUrl)) {
return null;
}
return TaskWrapperManager.getInstance().getHttpTaskWrapper(DTaskWrapper.class, downloadUrl);
}
/**
* 通过下载链接获取保存在数据库的下载任务组实体
*
* @param urls 任务组子任务下载地址列表
* @return 返回对应的任务组实体如果查找不到对应的数据或子任务列表为null返回null
*/
public DGTaskWrapper getGroupTask(List<String> urls) {
if (urls == null || urls.isEmpty()) {
ALog.e(TAG, "获取任务组实体失败:任务组子任务下载地址列表为null");
return null;
}
if (!taskExists(urls)) {
return null;
}
return TaskWrapperManager.getInstance().getDGTaskWrapper(DGTaskWrapper.class, urls);
}
/**
* 获取FTP文件夹下载任务实体
*
* @param dirUrl FTP文件夹本地下载路径
* @return 返回对应的任务组实体如果查找不到对应的数据或路径为null返回null
*/
public DGTaskWrapper getFtpDirTask(String dirUrl) {
if (TextUtils.isEmpty(dirUrl)) {
ALog.e(TAG, "获取FTP文件夹实体失败:下载路径为null");
return null;
}
boolean b =
DownloadGroupEntity.findFirst(DownloadGroupEntity.class, "groupHash=?", dirUrl) != null;
if (!b) {
return null;
}
return TaskWrapperManager.getInstance().getFtpTaskWrapper(DGTaskWrapper.class, dirUrl);
}
/**
* 下载任务是否存在
*
* @return {@code true}存在{@code false} 不存在
*/
public boolean taskExists(String downloadUrl) {
return DbEntity.checkDataExist(DownloadEntity.class, "url=?", downloadUrl);
}
/**
* 判断任务组是否存在
*
* @return {@code true} 存在{@code false} 不存在
*/
public boolean taskExists(List<String> urls) {
if (urls == null || urls.isEmpty()) {
return false;
}
String groupHash = CommonUtil.getMd5Code(urls);
return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", groupHash);
}
/**
* 获取所有普通下载任务
* 获取未完成的普通任务列表{@link #getAllNotCompleteTask()}
* 获取已经完成的普通任务列表{@link #getAllCompleteTask()}
*/
public List<DownloadEntity> getTaskList() {
return DbEntity.findDatas(DownloadEntity.class, "isGroupChild=? and downloadPath!=''",
"false");
}
/**
* 分页获取所有普通下载任务
* 获取未完成的普通任务列表{@link #getAllNotCompleteTask()}
* 获取已经完成的普通任务列表{@link #getAllCompleteTask()}
*
* @param page 当前页不能小于1
* @param num 每页数量不能小于1
* @return 如果页数大于总页数返回null
*/
public List<DownloadEntity> getTaskList(int page, int num) {
CheckUtil.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class, page, num,
"isGroupChild=? and downloadPath!=''", "false");
}
/**
* 获取所有未完成的普通下载任务
*/
public List<DownloadEntity> getAllNotCompleteTask() {
return DbEntity.findDatas(DownloadEntity.class,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false");
}
/**
* 分页获取所有未完成的普通下载任务
*
* @param page 当前页不能小于1
* @param num 每页数量不能小于1
* @return 如果页数大于总页数返回null
*/
public List<DownloadEntity> getAllNotCompleteTask(int page, int num) {
CheckUtil.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class, page, num,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false");
}
/**
* 获取所有已经完成的普通任务
*/
public List<DownloadEntity> getAllCompleteTask() {
return DbEntity.findDatas(DownloadEntity.class,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true");
}
/**
* 分页获取所有已经完成的普通任务
*
* @param page 当前页不能小于1
* @param num 每页数量不能小于1
* @return 如果页数大于总页数返回null
*/
public List<DownloadEntity> getAllCompleteTask(int page, int num) {
CheckUtil.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true");
}
/**
* 获取任务组列表
*
* @return 如果没有任务组列表则返回null
*/
public List<DownloadGroupEntity> getGroupTaskList() {
List<DGEntityWrapper> wrappers = DbEntity.findRelationData(DGEntityWrapper.class);
if (wrappers == null || wrappers.isEmpty()) {
return null;
}
List<DownloadGroupEntity> entities = new ArrayList<>();
for (DGEntityWrapper wrapper : wrappers) {
entities.add(wrapper.groupEntity);
}
return entities;
}
/**
* 分页获取祝贺任务列表
*
* @param page 当前页不能小于1
* @param num 每页数量不能小于1
* @return 如果没有任务组列表则返回null
*/
public List<DownloadGroupEntity> getGroupTaskList(int page, int num) {
List<DGEntityWrapper> wrappers = DbEntity.findRelationData(DGEntityWrapper.class, page, num);
if (wrappers == null || wrappers.isEmpty()) {
return null;
}
List<DownloadGroupEntity> entities = new ArrayList<>();
for (DGEntityWrapper wrapper : wrappers) {
entities.add(wrapper.groupEntity);
}
return entities;
}
/**
* 获取普通任务和任务组的任务列表
*/
public List<AbsEntity> getTotalTaskList() {
List<AbsEntity> list = new ArrayList<>();
List<DownloadEntity> simpleTask = getTaskList();
List<DownloadGroupEntity> groupTask = getGroupTaskList();
if (simpleTask != null && !simpleTask.isEmpty()) {
list.addAll(simpleTask);
}
if (groupTask != null && !groupTask.isEmpty()) {
list.addAll(groupTask);
}
return list;
}
/**
* 停止所有正在下载的任务并清空等待队列
*/
public void stopAllTask() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(NormalCmdFactory.getInstance()
.createCmd(new DTaskWrapper(null), NormalCmdFactory.TASK_STOP_ALL,
ICmd.TASK_TYPE_DOWNLOAD))
.exe();
}
/**
* 恢复所有正在下载的任务
* 1.如果执行队列没有满则开始下载任务直到执行队列满
* 2.如果队列执行队列已经满了则将所有任务添加到等待队列中
*/
public void resumeAllTask() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(NormalCmdFactory.getInstance()
.createCmd(new DTaskWrapper(null), NormalCmdFactory.TASK_RESUME_ALL,
ICmd.TASK_TYPE_DOWNLOAD))
.exe();
}
/**
* 删除所有任务
*
* @param removeFile {@code true} 删除已经下载完成的任务不仅删除下载记录还会删除已经下载完成的文件{@code false}
* 如果文件已经下载完成只删除下载记录
*/
public void removeAllTask(boolean removeFile) {
final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
CancelAllCmd cancelCmd =
(CancelAllCmd) CommonUtil.createNormalCmd(new DTaskWrapper(null),
NormalCmdFactory.TASK_CANCEL_ALL, ICmd.TASK_TYPE_DOWNLOAD);
cancelCmd.removeFile = removeFile;
ariaManager.setCmd(cancelCmd).exe();
Set<String> keys = ariaManager.getReceiver().keySet();
for (String key : keys) {
ariaManager.getReceiver().remove(key);
}
}
/*
* 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.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.command.normal.CancelAllCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.ProxyHelper;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsReceiver;
import com.arialyy.aria.core.inf.ReceiverType;
import com.arialyy.aria.core.manager.TaskWrapperManager;
import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers;
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Created by lyy on 2016/12/5.
* 下载功能接收器
*/
public class DownloadReceiver extends AbsReceiver {
private final String TAG = "DownloadReceiver";
/**
* 设置最大下载速度单位kb
*
* @param maxSpeed 为0表示不限速
* @deprecated {@code Aria.get(Context).getDownloadConfig().setMaxSpeed(int)}
*/
@Deprecated
public DownloadReceiver setMaxSpeed(int maxSpeed) {
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().setMaxSpeed(maxSpeed);
return this;
}
/**
* 使用下载实体执行下载操作
*
* @param entity 下载实体
*/
@CheckResult
public DownloadTarget load(DownloadEntity entity) {
CheckUtil.checkUrlInvalidThrow(entity.getUrl());
return new DownloadTarget(entity, targetName);
}
/**
* 加载Httphttps单任务下载地址
*
* @param url 下载地址
*/
@CheckResult
public DownloadTarget load(@NonNull String url) {
CheckUtil.checkUrlInvalidThrow(url);
return new DownloadTarget(url, targetName);
}
/**
* 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组
*
* @param urls 任务组子任务下载地址列表
* @deprecated {@link #loadGroup(DownloadGroupEntity)}
*/
@Deprecated
@CheckResult
public DownloadGroupTarget load(List<String> urls) {
return loadGroup(urls);
}
/**
* 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组
*/
@CheckResult
public DownloadGroupTarget loadGroup(List<String> urls) {
CheckUtil.checkDownloadUrls(urls);
return new DownloadGroupTarget(urls, targetName);
}
/**
* 使用下载实体执行FTP下载操作
*
* @param entity 下载实体
*/
@CheckResult
public FtpDownloadTarget loadFtp(DownloadEntity entity) {
CheckUtil.checkUrlInvalidThrow(entity.getUrl());
return new FtpDownloadTarget(entity, targetName);
}
/**
* 加载ftp单任务下载地址
*/
@CheckResult
public FtpDownloadTarget loadFtp(@NonNull String url) {
CheckUtil.checkUrlInvalidThrow(url);
return new FtpDownloadTarget(url, targetName);
}
/**
* 使用任务组实体执行任务组的实体执行任务组的下载操作后续版本会删除该api
*
* @param groupEntity 如果加载的任务实体没有子项的下载地址
* 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址
* @deprecated 请使用 {@link #loadGroup(DownloadGroupEntity)}
*/
@Deprecated
@CheckResult
public DownloadGroupTarget load(DownloadGroupEntity groupEntity) {
CheckUtil.checkDownloadUrls(groupEntity.getUrls());
return loadGroup(groupEntity);
}
/**
* 使用任务组实体执行任务组的实体执行任务组的下载操作
*
* @param groupEntity 如果加载的任务实体没有子项的下载地址
* 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址
*/
@CheckResult
public DownloadGroupTarget loadGroup(DownloadGroupEntity groupEntity) {
CheckUtil.checkDownloadUrls(groupEntity.getUrls());
return new DownloadGroupTarget(groupEntity, targetName);
}
/**
* 加载ftp文件夹下载地址
*/
@CheckResult
public FtpDirDownloadTarget loadFtpDir(@NonNull String dirUrl) {
CheckUtil.checkUrlInvalidThrow(dirUrl);
return new FtpDirDownloadTarget(dirUrl, targetName);
}
/**
* 将当前类注册到Aria
*/
public void register() {
if (TextUtils.isEmpty(targetName)) {
ALog.e(TAG, "download register target null");
return;
}
Object obj = OBJ_MAP.get(getKey());
if (obj == null) {
ALog.e(TAG, String.format("【%s】观察者为空", targetName));
return;
}
Set<Integer> set = ProxyHelper.getInstance().checkProxyType(obj.getClass());
if (set != null && !set.isEmpty()) {
for (Integer type : set) {
if (type == ProxyHelper.PROXY_TYPE_DOWNLOAD) {
DownloadSchedulers.getInstance().register(obj);
} else if (type == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) {
DownloadGroupSchedulers.getInstance().register(obj);
}
}
} else {
ALog.w(TAG, "没有Aria的注解方法");
}
}
/**
* 取消注册如果是Activity或fragmentAria会界面销毁时自动调用该方法不需要你手动调用
* 注意事项
* 1如果在activity中一定要调用该方法那么请在{@code onDestroy()}中调用
* 2不要在activity的{@code onStop()}中调用改方法
* 3如果是Dialog或popupwindow需要你在撤销界面时调用该方法
* 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>
*/
@Override public void unRegister() {
if (needRmListener) {
unRegisterListener();
}
AriaManager.getInstance(AriaManager.APP).removeReceiver(OBJ_MAP.get(getKey()));
}
@Override public String getType() {
return ReceiverType.DOWNLOAD;
}
@Override protected void unRegisterListener() {
if (TextUtils.isEmpty(targetName)) {
ALog.e(TAG, "download unRegisterListener target null");
return;
}
Object obj = OBJ_MAP.get(getKey());
if (obj == null) {
ALog.e(TAG, String.format("【%s】观察者为空", targetName));
return;
}
Set<Integer> set = ProxyHelper.getInstance().mProxyCache.get(obj.getClass().getName());
if (set != null) {
for (Integer integer : set) {
if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD) {
DownloadSchedulers.getInstance().unRegister(obj);
} else if (integer == ProxyHelper.PROXY_TYPE_DOWNLOAD_GROUP) {
DownloadGroupSchedulers.getInstance().unRegister(obj);
}
}
}
}
/**
* 通过下载链接获取下载实体
*
* @return 如果url错误或查找不到数据则返回null
*/
public DownloadEntity getDownloadEntity(String downloadUrl) {
if (!CheckUtil.checkUrl(downloadUrl)) {
return null;
}
return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl);
}
/**
* 通过下载地址和文件保存路径获取下载任务实体
*
* @param downloadUrl 下载地址
* @return 如果url错误或查找不到数据则返回null
*/
public DTaskWrapper getDownloadTask(String downloadUrl) {
if (!CheckUtil.checkUrl(downloadUrl)) {
return null;
}
if (!taskExists(downloadUrl)) {
return null;
}
return TaskWrapperManager.getInstance().getHttpTaskWrapper(DTaskWrapper.class, downloadUrl);
}
/**
* 通过下载链接获取保存在数据库的下载任务组实体
*
* @param urls 任务组子任务下载地址列表
* @return 返回对应的任务组实体如果查找不到对应的数据或子任务列表为null返回null
*/
public DGTaskWrapper getGroupTask(List<String> urls) {
if (urls == null || urls.isEmpty()) {
ALog.e(TAG, "获取任务组实体失败:任务组子任务下载地址列表为null");
return null;
}
if (!taskExists(urls)) {
return null;
}
return TaskWrapperManager.getInstance().getDGTaskWrapper(DGTaskWrapper.class, urls);
}
/**
* 获取FTP文件夹下载任务实体
*
* @param dirUrl FTP文件夹本地下载路径
* @return 返回对应的任务组实体如果查找不到对应的数据或路径为null返回null
*/
public DGTaskWrapper getFtpDirTask(String dirUrl) {
if (TextUtils.isEmpty(dirUrl)) {
ALog.e(TAG, "获取FTP文件夹实体失败:下载路径为null");
return null;
}
boolean b =
DownloadGroupEntity.findFirst(DownloadGroupEntity.class, "groupHash=?", dirUrl) != null;
if (!b) {
return null;
}
return TaskWrapperManager.getInstance().getFtpTaskWrapper(DGTaskWrapper.class, dirUrl);
}
/**
* 下载任务是否存在
*
* @return {@code true}存在{@code false} 不存在
*/
public boolean taskExists(String downloadUrl) {
return DbEntity.checkDataExist(DownloadEntity.class, "url=?", downloadUrl);
}
/**
* 判断任务组是否存在
*
* @return {@code true} 存在{@code false} 不存在
*/
public boolean taskExists(List<String> urls) {
if (urls == null || urls.isEmpty()) {
return false;
}
String groupHash = CommonUtil.getMd5Code(urls);
return DbEntity.checkDataExist(DownloadGroupEntity.class, "groupHash=?", groupHash);
}
/**
* 获取所有普通下载任务
* 获取未完成的普通任务列表{@link #getAllNotCompleteTask()}
* 获取已经完成的普通任务列表{@link #getAllCompleteTask()}
*/
public List<DownloadEntity> getTaskList() {
return DbEntity.findDatas(DownloadEntity.class, "isGroupChild=? and downloadPath!=''",
"false");
}
/**
* 分页获取所有普通下载任务
* 获取未完成的普通任务列表{@link #getAllNotCompleteTask()}
* 获取已经完成的普通任务列表{@link #getAllCompleteTask()}
*
* @param page 当前页不能小于1
* @param num 每页数量不能小于1
* @return 如果页数大于总页数返回null
*/
public List<DownloadEntity> getTaskList(int page, int num) {
CheckUtil.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class, page, num,
"isGroupChild=? and downloadPath!=''", "false");
}
/**
* 获取所有未完成的普通下载任务
*/
public List<DownloadEntity> getAllNotCompleteTask() {
return DbEntity.findDatas(DownloadEntity.class,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false");
}
/**
* 分页获取所有未完成的普通下载任务
*
* @param page 当前页不能小于1
* @param num 每页数量不能小于1
* @return 如果页数大于总页数返回null
*/
public List<DownloadEntity> getAllNotCompleteTask(int page, int num) {
CheckUtil.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class, page, num,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "false");
}
/**
* 获取所有已经完成的普通任务
*/
public List<DownloadEntity> getAllCompleteTask() {
return DbEntity.findDatas(DownloadEntity.class,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true");
}
/**
* 分页获取所有已经完成的普通任务
*
* @param page 当前页不能小于1
* @param num 每页数量不能小于1
* @return 如果页数大于总页数返回null
*/
public List<DownloadEntity> getAllCompleteTask(int page, int num) {
CheckUtil.checkPageParams(page, num);
return DbEntity.findDatas(DownloadEntity.class,
"isGroupChild=? and downloadPath!='' and isComplete=?", "false", "true");
}
/**
* 获取任务组列表
*
* @return 如果没有任务组列表则返回null
*/
public List<DownloadGroupEntity> getGroupTaskList() {
List<DGEntityWrapper> wrappers = DbEntity.findRelationData(DGEntityWrapper.class);
if (wrappers == null || wrappers.isEmpty()) {
return null;
}
List<DownloadGroupEntity> entities = new ArrayList<>();
for (DGEntityWrapper wrapper : wrappers) {
entities.add(wrapper.groupEntity);
}
return entities;
}
/**
* 分页获取祝贺任务列表
*
* @param page 当前页不能小于1
* @param num 每页数量不能小于1
* @return 如果没有任务组列表则返回null
*/
public List<DownloadGroupEntity> getGroupTaskList(int page, int num) {
List<DGEntityWrapper> wrappers = DbEntity.findRelationData(DGEntityWrapper.class, page, num);
if (wrappers == null || wrappers.isEmpty()) {
return null;
}
List<DownloadGroupEntity> entities = new ArrayList<>();
for (DGEntityWrapper wrapper : wrappers) {
entities.add(wrapper.groupEntity);
}
return entities;
}
/**
* 获取普通任务和任务组的任务列表
*/
public List<AbsEntity> getTotalTaskList() {
List<AbsEntity> list = new ArrayList<>();
List<DownloadEntity> simpleTask = getTaskList();
List<DownloadGroupEntity> groupTask = getGroupTaskList();
if (simpleTask != null && !simpleTask.isEmpty()) {
list.addAll(simpleTask);
}
if (groupTask != null && !groupTask.isEmpty()) {
list.addAll(groupTask);
}
return list;
}
/**
* 停止所有正在下载的任务并清空等待队列
*/
public void stopAllTask() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(NormalCmdFactory.getInstance()
.createCmd(new DTaskWrapper(null), NormalCmdFactory.TASK_STOP_ALL,
ICmd.TASK_TYPE_DOWNLOAD))
.exe();
}
/**
* 恢复所有正在下载的任务
* 1.如果执行队列没有满则开始下载任务直到执行队列满
* 2.如果队列执行队列已经满了则将所有任务添加到等待队列中
*/
public void resumeAllTask() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(NormalCmdFactory.getInstance()
.createCmd(new DTaskWrapper(null), NormalCmdFactory.TASK_RESUME_ALL,
ICmd.TASK_TYPE_DOWNLOAD))
.exe();
}
/**
* 删除所有任务
*
* @param removeFile {@code true} 删除已经下载完成的任务不仅删除下载记录还会删除已经下载完成的文件{@code false}
* 如果文件已经下载完成只删除下载记录
*/
public void removeAllTask(boolean removeFile) {
final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
CancelAllCmd cancelCmd =
(CancelAllCmd) CommonUtil.createNormalCmd(new DTaskWrapper(null),
NormalCmdFactory.TASK_CANCEL_ALL, ICmd.TASK_TYPE_DOWNLOAD);
cancelCmd.removeFile = removeFile;
ariaManager.setCmd(cancelCmd).exe();
Set<String> keys = ariaManager.getReceiver().keySet();
for (String key : keys) {
ariaManager.getReceiver().remove(key);
}
}
}

@ -28,7 +28,7 @@ import java.util.Map;
* Created by lyy on 2016/12/5.
* https://github.com/AriaLyy/Aria
*/
public class DownloadTarget extends AbsDownloadTarget<DownloadTarget>
public class DownloadTarget extends AbsDTarget<DownloadTarget>
implements IHttpHeaderDelegate<DownloadTarget> {
private HttpHeaderDelegate<DownloadTarget> mHeaderDelegate;
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;
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.FtpDelegate;
import com.arialyy.aria.core.inf.AbsTaskWrapper;
import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.core.manager.TaskWrapperManager;
import com.arialyy.aria.util.ALog;
import java.net.Proxy;
/**
@ -32,7 +28,8 @@ import java.net.Proxy;
*/
public class FtpDirDownloadTarget extends AbsDGTarget<FtpDirDownloadTarget>
implements IFtpTarget<FtpDirDownloadTarget> {
private FtpDelegate<FtpDirDownloadTarget> mDelegate;
private FtpDelegate<FtpDirDownloadTarget> mFtpDelegate;
private FtpDirDelegate mDirDelegate;
FtpDirDownloadTarget(String url, String targetName) {
setTargetName(targetName);
@ -40,13 +37,9 @@ public class FtpDirDownloadTarget extends AbsDGTarget<FtpDirDownloadTarget>
}
private void init(String key) {
mGroupHash = key;
setTaskWrapper(TaskWrapperManager.getInstance().getFtpTaskWrapper(DGTaskWrapper.class, key));
getTaskWrapper().setRequestType(AbsTaskWrapper.D_FTP_DIR);
if (getEntity() != null) {
mDirPathTemp = getEntity().getDirPath();
}
mDelegate = new FtpDelegate<>(this);
mDirDelegate = new FtpDirDelegate(this,
TaskWrapperManager.getInstance().getFtpTaskWrapper(DGTaskWrapper.class, key));
mFtpDelegate = new FtpDelegate<>(this);
}
@Override public int getTargetType() {
@ -54,62 +47,39 @@ public class FtpDirDownloadTarget extends AbsDGTarget<FtpDirDownloadTarget>
}
@Override protected boolean checkEntity() {
boolean b = getTargetType() == GROUP_FTP_DIR && 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 mDirDelegate.checkEntity();
}
@Override public boolean isRunning() {
return mDirDelegate.isRunning();
}
@Override public boolean taskExists() {
return mDirDelegate.taskExists();
}
/**
* 检查普通任务的下载地址
* 设置任务组的文件夹路径在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() {
final String url = mGroupHash;
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;
@CheckResult
public FtpDirDownloadTarget setDirPath(String dirPath) {
return mDirDelegate.setDirPath(dirPath);
}
/**
@ -125,20 +95,20 @@ public class FtpDirDownloadTarget extends AbsDGTarget<FtpDirDownloadTarget>
@CheckResult
@Override public FtpDirDownloadTarget charSet(String charSet) {
return mDelegate.charSet(charSet);
return mFtpDelegate.charSet(charSet);
}
@CheckResult
@Override public FtpDirDownloadTarget login(String userName, String password) {
return mDelegate.login(userName, password);
return mFtpDelegate.login(userName, password);
}
@CheckResult
@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) {
return mDelegate.setProxy(proxy);
return mFtpDelegate.setProxy(proxy);
}
}

@ -30,7 +30,7 @@ import java.net.Proxy;
* Created by lyy on 2016/12/5.
* https://github.com/AriaLyy/Aria
*/
public class FtpDownloadTarget extends AbsDownloadTarget<FtpDownloadTarget>
public class FtpDownloadTarget extends AbsDTarget<FtpDownloadTarget>
implements IFtpTarget<FtpDownloadTarget> {
private FtpDelegate<FtpDownloadTarget> mFtpDelegate;
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.
* 普通任务接收器功能接口
*/
public interface ITargetNormal<TARGET extends AbsTarget> {
/**
* 通过地址初始化target
*
* @param url 下载url上传url
* @param targetName 接收器名称
*/
void initTarget(String url, String targetName);
/**
* 更新下载url
*
* @param newUrl 新的下载url
*/
TARGET updateUrl(String newUrl);
public interface INormalTarget {
/**
* 获取实体

@ -17,7 +17,7 @@ package com.arialyy.aria.core.upload;
import android.text.TextUtils;
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.queue.UploadTaskQueue;
import com.arialyy.aria.orm.DbEntity;
@ -29,7 +29,7 @@ import java.io.File;
* 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 UploadEntity mEntity;
private TARGET mTarget;
@ -43,7 +43,7 @@ class UNormalDelegate<TARGET extends AbsUploadTarget> implements ITargetNormal<T
initTarget(filePath, targetName);
}
@Override public void initTarget(String filePath, String targetName) {
private void initTarget(String filePath, String targetName) {
UTaskWrapper taskWrapper =
TaskWrapperManager.getInstance().getHttpTaskWrapper(UTaskWrapper.class, filePath);
mEntity = taskWrapper.getEntity();
@ -55,7 +55,7 @@ class UNormalDelegate<TARGET extends AbsUploadTarget> implements ITargetNormal<T
mTempUrl = mEntity.getUrl();
}
@Override public TARGET updateUrl(String newUrl) {
TARGET updateUrl(String newUrl) {
mTempUrl = newUrl;
return mTarget;
}

@ -1,263 +1,257 @@
/*
* 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.orm;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.text.TextUtils;
import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.util.ALog;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Created by lyy on 2015/11/2.
* sql帮助类
*/
final class SqlHelper extends SQLiteOpenHelper {
private static final String TAG = "SqlHelper";
static volatile SqlHelper INSTANCE = null;
private DelegateCommon mDelegate;
static SqlHelper init(Context context) {
if (INSTANCE == null) {
synchronized (SqlHelper.class) {
DelegateCommon delegate = DelegateManager.getInstance().getDelegate(DelegateCommon.class);
INSTANCE = new SqlHelper(context.getApplicationContext(), delegate);
SQLiteDatabase db = INSTANCE.getWritableDatabase();
db = delegate.checkDb(db);
// SQLite在3.6.19版本中开始支持外键约束,
// 而在Android中 2.1以前的版本使用的SQLite版本是3.5.9, 在2.2版本中使用的是3.6.22.
// 但是为了兼容以前的程序,默认并没有启用该功能,如果要启用该功能
// 需要使用如下语句:
db.execSQL("PRAGMA foreign_keys=ON;");
Set<String> tables = DBConfig.mapping.keySet();
for (String tableName : tables) {
Class clazz = null;
clazz = DBConfig.mapping.get(tableName);
if (!delegate.tableExists(db, clazz)) {
delegate.createTable(db, clazz);
}
}
}
}
return INSTANCE;
}
private SqlHelper(Context context, DelegateCommon delegate) {
super(DBConfig.SAVE_IN_SDCARD ? new DatabaseContext(context) : context, DBConfig.DB_NAME, null,
DBConfig.VERSION);
mDelegate = delegate;
}
@Override public void onCreate(SQLiteDatabase db) {
}
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < newVersion) {
if (oldVersion < 31) {
handle314AriaUpdate(db);
} else if (oldVersion < 45) {
handle360AriaUpdate(db);
} else {
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) {
if (db == null) {
ALog.e("SqlHelper", "db 为 null");
return;
} else if (!db.isOpen()) {
ALog.e("SqlHelper", "db已关闭");
return;
}
try {
db.beginTransaction();
Set<String> tables = DBConfig.mapping.keySet();
for (String tableName : tables) {
Class clazz = DBConfig.mapping.get(tableName);
if (mDelegate.tableExists(db, clazz)) {
db = mDelegate.checkDb(db);
//修改表名为中介表名
String alertSql = String.format("ALTER TABLE %s RENAME TO %s_temp", tableName, tableName);
db.execSQL(alertSql);
//创建新表
mDelegate.createTable(db, clazz);
String sql = String.format("SELECT COUNT(*) FROM %s_temp", tableName);
Cursor cursor = db.rawQuery(sql, null);
cursor.moveToFirst();
long count = cursor.getLong(0);
cursor.close();
if (count > 0) {
// 获取所有表字段名称
Cursor columnC =
db.rawQuery(String.format("PRAGMA table_info(%s_temp)", tableName), null);
StringBuilder params = new StringBuilder();
while (columnC.moveToNext()) {
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)) {
continue;
}
}
}
params.append(columnName).append(",");
}
columnC.close();
String oldParamStr = params.toString();
oldParamStr = oldParamStr.substring(0, oldParamStr.length() - 1);
String newParamStr = oldParamStr;
// 处理字段名称改变
if (modifyColumns != null) {
//newParamStr = params.toString();
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);
}
//删除中介表
mDelegate.dropTable(db, tableName + "_temp");
}
}
db.setTransactionSuccessful();
} catch (Exception e) {
ALog.e(TAG, e);
} finally {
db.endTransaction();
}
mDelegate.close(db);
}
/**
* 处理3.6以下版本的数据库升级
*/
private void handle360AriaUpdate(SQLiteDatabase db) {
String[] taskTables =
new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" };
for (String taskTable : taskTables) {
if (mDelegate.tableExists(db, taskTable)) {
mDelegate.dropTable(db, taskTable);
}
}
Map<String, Map<String, String>> columnMap = new HashMap<>();
Map<String, String> map = new HashMap<>();
map.put("groupName", "groupHash");
columnMap.put("DownloadEntity", map);
columnMap.put("DownloadGroupEntity", map);
handleDbUpdate(db, columnMap, null);
}
/**
* 处理3.4版本之前数据库迁移主要是修改子表外键字段对应的值
*/
private void handle314AriaUpdate(SQLiteDatabase db) {
String[] taskTables =
new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" };
for (String taskTable : taskTables) {
if (mDelegate.tableExists(db, taskTable)) {
mDelegate.dropTable(db, taskTable);
}
}
//删除所有主键为null和逐渐重复的数据
String[] tables = new String[] { "DownloadEntity", "DownloadGroupEntity" };
String[] keys = new String[] { "downloadPath", "groupName" };
int i = 0;
for (String tableName : tables) {
String pColumn = keys[i];
String nullSql =
String.format("DELETE FROM %s WHERE %s='' OR %s IS NULL", tableName, pColumn, pColumn);
ALog.d(TAG, nullSql);
db.execSQL(nullSql);
//删除所有主键重复的数据
String repeatSql =
String.format(
"DELETE FROM %s WHERE %s IN(SELECT %s FROM %s GROUP BY %s HAVING COUNT(%s) > 1)",
tableName, pColumn, pColumn, tableName, pColumn, pColumn);
ALog.d(TAG, repeatSql);
db.execSQL(repeatSql);
i++;
}
Map<String, Map<String, String>> modifyColumnMap = new HashMap<>();
Map<String, String> map = new HashMap<>();
map.put("groupName", "groupHash");
modifyColumnMap.put("DownloadEntity", map);
modifyColumnMap.put("DownloadGroupEntity", map);
Map<String, List<String>> delColumnMap = new HashMap<>();
List<String> dEntityDel = new ArrayList<>();
dEntityDel.add("taskKey");
delColumnMap.put("DownloadEntity", dEntityDel);
List<String> dgEntityDel = new ArrayList<>();
dgEntityDel.add("subtask");
delColumnMap.put("DownloadGroupEntity", dgEntityDel);
handleDbUpdate(db, modifyColumnMap, delColumnMap);
}
/*
* 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.orm;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.arialyy.aria.util.ALog;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Created by lyy on 2015/11/2.
* sql帮助类
*/
final class SqlHelper extends SQLiteOpenHelper {
private static final String TAG = "SqlHelper";
static volatile SqlHelper INSTANCE = null;
private DelegateCommon mDelegate;
synchronized static SqlHelper init(Context context) {
if (INSTANCE == null) {
synchronized (SqlHelper.class) {
DelegateCommon delegate = DelegateManager.getInstance().getDelegate(DelegateCommon.class);
INSTANCE = new SqlHelper(context.getApplicationContext(), delegate);
SQLiteDatabase db = INSTANCE.getWritableDatabase();
db = delegate.checkDb(db);
// SQLite在3.6.19版本中开始支持外键约束,
// 而在Android中 2.1以前的版本使用的SQLite版本是3.5.9, 在2.2版本中使用的是3.6.22.
// 但是为了兼容以前的程序,默认并没有启用该功能,如果要启用该功能
// 需要使用如下语句:
db.execSQL("PRAGMA foreign_keys=ON;");
Set<String> tables = DBConfig.mapping.keySet();
for (String tableName : tables) {
Class clazz = DBConfig.mapping.get(tableName);
if (!delegate.tableExists(db, clazz)) {
delegate.createTable(db, clazz);
}
}
}
}
return INSTANCE;
}
private SqlHelper(Context context, DelegateCommon delegate) {
super(DBConfig.SAVE_IN_SDCARD ? new DatabaseContext(context) : context, DBConfig.DB_NAME, null,
DBConfig.VERSION);
mDelegate = delegate;
}
@Override public void onCreate(SQLiteDatabase db) {
}
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < newVersion) {
if (oldVersion < 31) {
handle314AriaUpdate(db);
} else if (oldVersion < 45) {
handle360AriaUpdate(db);
} else {
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) {
if (db == null) {
ALog.e("SqlHelper", "db 为 null");
return;
} else if (!db.isOpen()) {
ALog.e("SqlHelper", "db已关闭");
return;
}
try {
db.beginTransaction();
Set<String> tables = DBConfig.mapping.keySet();
for (String tableName : tables) {
Class clazz = DBConfig.mapping.get(tableName);
if (mDelegate.tableExists(db, clazz)) {
db = mDelegate.checkDb(db);
//修改表名为中介表名
String alertSql = String.format("ALTER TABLE %s RENAME TO %s_temp", tableName, tableName);
db.execSQL(alertSql);
//创建新表
mDelegate.createTable(db, clazz);
String sql = String.format("SELECT COUNT(*) FROM %s_temp", tableName);
Cursor cursor = db.rawQuery(sql, null);
cursor.moveToFirst();
long count = cursor.getLong(0);
cursor.close();
if (count > 0) {
// 获取所有表字段名称
Cursor columnC =
db.rawQuery(String.format("PRAGMA table_info(%s_temp)", tableName), null);
StringBuilder params = new StringBuilder();
while (columnC.moveToNext()) {
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)) {
continue;
}
}
}
params.append(columnName).append(",");
}
columnC.close();
String oldParamStr = params.toString();
oldParamStr = oldParamStr.substring(0, oldParamStr.length() - 1);
String newParamStr = oldParamStr;
// 处理字段名称改变
if (modifyColumns != null) {
//newParamStr = params.toString();
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);
}
//删除中介表
mDelegate.dropTable(db, tableName + "_temp");
}
}
db.setTransactionSuccessful();
} catch (Exception e) {
ALog.e(TAG, e);
} finally {
db.endTransaction();
}
mDelegate.close(db);
}
/**
* 处理3.6以下版本的数据库升级
*/
private void handle360AriaUpdate(SQLiteDatabase db) {
String[] taskTables =
new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" };
for (String taskTable : taskTables) {
if (mDelegate.tableExists(db, taskTable)) {
mDelegate.dropTable(db, taskTable);
}
}
Map<String, Map<String, String>> columnMap = new HashMap<>();
Map<String, String> map = new HashMap<>();
map.put("groupName", "groupHash");
columnMap.put("DownloadEntity", map);
columnMap.put("DownloadGroupEntity", map);
handleDbUpdate(db, columnMap, null);
}
/**
* 处理3.4版本之前数据库迁移主要是修改子表外键字段对应的值
*/
private void handle314AriaUpdate(SQLiteDatabase db) {
String[] taskTables =
new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" };
for (String taskTable : taskTables) {
if (mDelegate.tableExists(db, taskTable)) {
mDelegate.dropTable(db, taskTable);
}
}
//删除所有主键为null和逐渐重复的数据
String[] tables = new String[] { "DownloadEntity", "DownloadGroupEntity" };
String[] keys = new String[] { "downloadPath", "groupName" };
int i = 0;
for (String tableName : tables) {
String pColumn = keys[i];
String nullSql =
String.format("DELETE FROM %s WHERE %s='' OR %s IS NULL", tableName, pColumn, pColumn);
ALog.d(TAG, nullSql);
db.execSQL(nullSql);
//删除所有主键重复的数据
String repeatSql =
String.format(
"DELETE FROM %s WHERE %s IN(SELECT %s FROM %s GROUP BY %s HAVING COUNT(%s) > 1)",
tableName, pColumn, pColumn, tableName, pColumn, pColumn);
ALog.d(TAG, repeatSql);
db.execSQL(repeatSql);
i++;
}
Map<String, Map<String, String>> modifyColumnMap = new HashMap<>();
Map<String, String> map = new HashMap<>();
map.put("groupName", "groupHash");
modifyColumnMap.put("DownloadEntity", map);
modifyColumnMap.put("DownloadGroupEntity", map);
Map<String, List<String>> delColumnMap = new HashMap<>();
List<String> dEntityDel = new ArrayList<>();
dEntityDel.add("taskKey");
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有以下特点:
+ 简单、方便
- 可以在Activity、Service、Fragment、Dialog、popupWindow、Notification等组件中使用
- 支持HTTP\FTP断点续传、多任务自动调度
- 支持HTTP任务组\FTP文件夹,断点续传下载
- 支持HTTP\FTP断点续传下载、多任务自动调度
- 支持多文件打包下载,多文件共享同一进度(如:视频 + 封面 + 字幕)
- 支持下载FTP文件夹
- 支持HTTP表单上传
- 支持文件FTP断点续传上传
- 支持FTPS/SFTP断点续传,[see](https://aria.laoyuyu.me/aria_doc/download/ftps.html)
@ -23,12 +24,17 @@ Aria有以下特点:
如果你觉得Aria对你有帮助,您的star和issues将是对我最大支持.`^_^`
## 示例
* 多任务下载
![多任务下载](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/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)
[![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