移除`getDownloadTask(String url)`、`getGroupTask(List<String>urls)`、`getFtpDirTask(String path)`等获取任务的api 修复使用`Content-Disposition`的文件名时,第一次下载无法重命名文件的问题 修复使用`Content-Disposition`的文件名时,多次重命名文件的问题
This commit is contained in:
@@ -141,10 +141,11 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
}
|
||||
resetState();
|
||||
mConstance.resetState();
|
||||
ALog.d(TAG, "path: " + getFilePath());
|
||||
checkRecord();
|
||||
mConstance.isRunning = true;
|
||||
mConstance.TASK_RECORD = mRecord;
|
||||
if (!mTaskWrapper.isSupportBP()) {
|
||||
if (!mTaskWrapper.isSupportBP() || mTaskWrapper.asHttp().isChunked()) {
|
||||
mTotalThreadNum = 1;
|
||||
} else {
|
||||
mTotalThreadNum =
|
||||
@@ -348,6 +349,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
if (mRecord.isOpenDynamicFile) {
|
||||
ThreadRecord tr = mRecord.threadRecords.get(0);
|
||||
if (tr == null) {
|
||||
ALog.d(TAG, "线程记录为空,任务为新任务");
|
||||
mTaskWrapper.setNewTask(true);
|
||||
mTotalThreadNum = 1;
|
||||
return;
|
||||
@@ -438,6 +440,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
if (records == null || records.size() == 0) {
|
||||
Properties pro = CommonUtil.loadConfig(mConfigFile);
|
||||
if (pro.isEmpty()) {
|
||||
ALog.d(TAG, "老版本的线程记录为空,任务为新任务");
|
||||
mTaskWrapper.setNewTask(true);
|
||||
return;
|
||||
}
|
||||
@@ -453,6 +456,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
}
|
||||
int threadNum = set.size();
|
||||
if (threadNum == 0) {
|
||||
ALog.d(TAG, "线程数为空,任务为新任务");
|
||||
mTaskWrapper.setNewTask(true);
|
||||
return;
|
||||
}
|
||||
@@ -495,6 +499,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
mRecord.dGroupHash = ((DownloadEntity) mTaskWrapper.getEntity()).getGroupHash();
|
||||
}
|
||||
}
|
||||
ALog.d(TAG, String.format("初始化记录,任务为%s任务", isNewTask ? "新" : "旧"));
|
||||
mTaskWrapper.setNewTask(isNewTask);
|
||||
}
|
||||
|
||||
@@ -569,6 +574,10 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
long fileLength = mEntity.getFileSize();
|
||||
long blockSize = fileLength / mTotalThreadNum;
|
||||
Set<Integer> threads = new HashSet<>();
|
||||
// 如果是新任务,检查下历史记录,如果有遗留的记录,删除并删除分块文件
|
||||
if (mTaskWrapper.isNewTask()) {
|
||||
CommonUtil.delTaskRecord(getFilePath(), 1, true);
|
||||
}
|
||||
|
||||
mRecord.fileLength = fileLength;
|
||||
if (mTaskWrapper.isNewTask() && !handleNewTask()) {
|
||||
|
||||
@@ -316,7 +316,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
|
||||
*/
|
||||
protected void progress(long len) {
|
||||
synchronized (AriaManager.LOCK) {
|
||||
if (STATE.CURRENT_LOCATION > mEntity.getFileSize()) {
|
||||
if (STATE.CURRENT_LOCATION > mEntity.getFileSize() && !mTaskWrapper.asHttp().isChunked()) {
|
||||
String errorMsg =
|
||||
String.format("下载失败,下载长度超出文件真实长度;currentLocation=%s, fileSize=%s",
|
||||
STATE.CURRENT_LOCATION,
|
||||
|
||||
@@ -145,6 +145,10 @@ class DNormalDelegate<TARGET extends AbsDTarget> implements INormalTarget {
|
||||
File newFile = new File(filePath);
|
||||
mEntity.setDownloadPath(filePath);
|
||||
mEntity.setFileName(newFile.getName());
|
||||
// 如过使用Content-Disposition中的文件名,将不会执行重命名工作
|
||||
if (mTarget.getTaskWrapper().asHttp().isUseServerFileName()) {
|
||||
return true;
|
||||
}
|
||||
if (oldFile.exists()) {
|
||||
// 处理普通任务的重命名
|
||||
CommonUtil.modifyTaskRecord(oldFile.getPath(), newFile.getPath());
|
||||
|
||||
@@ -1,475 +1,458 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载Http、https单任务下载地址
|
||||
*
|
||||
* @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或fragment,Aria会界面销毁时自动调用该方法,不需要你手动调用。
|
||||
* 注意事项:
|
||||
* 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.annotations.DownloadGroup;
|
||||
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 com.arialyy.aria.util.DbDataHelper;
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载Http、https单任务下载地址
|
||||
*
|
||||
* @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或fragment,Aria会界面销毁时自动调用该方法,不需要你手动调用。
|
||||
* 注意事项:
|
||||
* 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) {
|
||||
CheckUtil.checkUrl(downloadUrl);
|
||||
return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组合任务实在实体
|
||||
*
|
||||
* @param urls 组合任务的url
|
||||
* @return 如果实体不存在,返回null
|
||||
*/
|
||||
public DownloadGroupEntity getDownloadGroupEntity(List<String> urls) {
|
||||
CheckUtil.checkDownloadUrls(urls);
|
||||
return DbDataHelper.getDGEntity(CommonUtil.getMd5Code(urls));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组合任务实在实体
|
||||
*
|
||||
* @param key 组合任务的key,{@link DownloadGroupEntity#getKey()}
|
||||
* @return 如果实体不存在,返回null
|
||||
*/
|
||||
public DownloadGroupEntity getDownloadGroupEntity(String key) {
|
||||
if (TextUtils.isEmpty(key)) {
|
||||
throw new IllegalArgumentException("key为空");
|
||||
}
|
||||
return DbDataHelper.getDGEntity(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Ftp文件夹任务的实体
|
||||
*
|
||||
* @param url ftp文件夹下载路径
|
||||
* @return 如果实体不存在,返回null
|
||||
*/
|
||||
public DownloadGroupEntity getFtpDirEntity(String url) {
|
||||
CheckUtil.checkUrl(url);
|
||||
return DbDataHelper.getDGEntity(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载任务是否存在
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.downloader;
|
||||
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
// Data is expected to be a series of data chunks in the form <chunk size><chunk bytes><chunk size><chunk bytes>
|
||||
// The final data chunk should be a 0-length chunk which will indicate end of input.
|
||||
@Deprecated
|
||||
public class ChunkedInputStream extends InputStream {
|
||||
private static final String TAG = "ChunkedInputStream";
|
||||
|
||||
private DataInputStream din;
|
||||
private int unreadBytes = 0; // Bytes remaining in the current chunk of data
|
||||
private byte[] singleByte = new byte[1];
|
||||
private boolean endOfData = false;
|
||||
private String id;
|
||||
|
||||
public ChunkedInputStream(InputStream in, String id) {
|
||||
din = new DataInputStream(in);
|
||||
this.id = id;
|
||||
ALog.d(TAG, String.format("Creating chunked input for %s", id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
ALog.d(TAG, String.format("%s: Closing chunked input.", id));
|
||||
din.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int bytesRead = read(singleByte, 0, 1);
|
||||
return (bytesRead == -1) ? -1 : (int) singleByte[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
int bytesRead = 0;
|
||||
|
||||
if (len < 0) {
|
||||
throw new IllegalArgumentException(id + ": Negative read length");
|
||||
} else if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If there is a current unread chunk, read from that, or else get the next chunk.
|
||||
if (unreadBytes == 0) {
|
||||
try {
|
||||
// Find the next chunk size
|
||||
unreadBytes = din.readInt();
|
||||
if (ALog.DEBUG) {
|
||||
ALog.d(TAG, String.format("%s: Chunk size %s", id, unreadBytes));
|
||||
}
|
||||
if (unreadBytes == 0) {
|
||||
ALog.d(TAG, String.format("%s: Hit end of data", id));
|
||||
endOfData = true;
|
||||
return -1;
|
||||
}
|
||||
} catch (IOException err) {
|
||||
throw new IOException(id + ": Error while attempting to read chunk length", err);
|
||||
}
|
||||
}
|
||||
|
||||
int bytesToRead = Math.min(len, unreadBytes);
|
||||
try {
|
||||
din.readFully(b, off, bytesToRead);
|
||||
} catch (IOException err) {
|
||||
throw new IOException(
|
||||
id + ": Error while attempting to read " + bytesToRead + " bytes from current chunk",
|
||||
err);
|
||||
}
|
||||
unreadBytes -= bytesToRead;
|
||||
bytesRead += bytesToRead;
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
public boolean isEndOfData() {
|
||||
return endOfData;
|
||||
}
|
||||
}
|
||||
@@ -163,27 +163,27 @@ class ConnectionHelp {
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
|
||||
}
|
||||
if (conn.getRequestProperty("Accept") == null) {
|
||||
//StringBuilder accept = new StringBuilder();
|
||||
//accept
|
||||
//.append("image/gif, ")
|
||||
//.append("image/jpeg, ")
|
||||
//.append("image/pjpeg, ")
|
||||
//.append("image/webp, ")
|
||||
//.append("image/apng, ")
|
||||
//.append("application/xml, ")
|
||||
//.append("application/xaml+xml, ")
|
||||
//.append("application/xhtml+xml, ")
|
||||
//.append("application/x-shockwave-flash, ")
|
||||
//.append("application/x-ms-xbap, ")
|
||||
//.append("application/x-ms-application, ")
|
||||
//.append("application/msword, ")
|
||||
//.append("application/vnd.ms-excel, ")
|
||||
//.append("application/vnd.ms-xpsdocument, ")
|
||||
//.append("application/vnd.ms-powerpoint, ")
|
||||
//.append("text/plain, ")
|
||||
//.append("text/html, ")
|
||||
//.append("*/*");
|
||||
conn.setRequestProperty("Accept", "*/*");
|
||||
StringBuilder accept = new StringBuilder();
|
||||
accept.append("image/gif, ")
|
||||
.append("image/jpeg, ")
|
||||
.append("image/pjpeg, ")
|
||||
.append("image/webp, ")
|
||||
.append("image/apng, ")
|
||||
.append("application/xml, ")
|
||||
.append("application/xaml+xml, ")
|
||||
.append("application/xhtml+xml, ")
|
||||
.append("application/x-shockwave-flash, ")
|
||||
.append("application/x-ms-xbap, ")
|
||||
.append("application/x-ms-application, ")
|
||||
.append("application/msword, ")
|
||||
.append("application/vnd.ms-excel, ")
|
||||
.append("application/vnd.ms-xpsdocument, ")
|
||||
.append("application/vnd.ms-powerpoint, ")
|
||||
.append("application/signed-exchange, ")
|
||||
.append("text/plain, ")
|
||||
.append("text/html, ")
|
||||
.append("*/*");
|
||||
conn.setRequestProperty("Accept", accept.toString());
|
||||
}
|
||||
//302获取重定向地址
|
||||
conn.setInstanceFollowRedirects(false);
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.arialyy.aria.core.inf.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.inf.IDownloadListener;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.exception.TaskException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -83,6 +84,20 @@ public class Downloader extends AbsFileer<DownloadEntity, DTaskWrapper> {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果使用"Content-Disposition"中的文件名,需要更新{@link #mTempFile}的路径
|
||||
*/
|
||||
void updateTempFile() {
|
||||
if (!mTempFile.getPath().equals(mEntity.getDownloadPath())) {
|
||||
if (!mTempFile.exists()) {
|
||||
mTempFile = new File(mEntity.getDownloadPath());
|
||||
} else {
|
||||
boolean b = mTempFile.renameTo(new File(mEntity.getDownloadPath()));
|
||||
ALog.d(TAG, String.format("更新tempFile文件名%s", b ? "成功" : "失败"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected int getType() {
|
||||
return DOWNLOAD;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.CookieManager;
|
||||
import java.net.HttpCookie;
|
||||
import java.net.HttpURLConnection;
|
||||
@@ -77,7 +78,6 @@ public class HttpFileInfoThread implements Runnable {
|
||||
ConnectionHelp.setConnectParam(mTaskDelegate, conn);
|
||||
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
|
||||
conn.setConnectTimeout(mConnectTimeOut);
|
||||
//conn.setChunkedStreamingMode(0);
|
||||
conn.connect();
|
||||
handleConnect(conn);
|
||||
} catch (IOException e) {
|
||||
@@ -149,20 +149,7 @@ public class HttpFileInfoThread implements Runnable {
|
||||
String disposition = conn.getHeaderField("Content-Disposition");
|
||||
if (mTaskDelegate.isUseServerFileName() && !TextUtils.isEmpty(disposition)) {
|
||||
mEntity.setDisposition(CommonUtil.encryptBASE64(disposition));
|
||||
if (disposition.contains(";")) {
|
||||
String[] infos = disposition.split(";");
|
||||
for (String info : infos) {
|
||||
if (info.startsWith("filename") && info.contains("=")) {
|
||||
String[] temp = info.split("=");
|
||||
if (temp.length > 1) {
|
||||
String newName = URLDecoder.decode(temp[1], "utf-8").replaceAll("\"", "");
|
||||
mEntity.setServerFileName(newName);
|
||||
renameFile(newName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
handleContentDisposition(disposition);
|
||||
}
|
||||
CookieManager msCookieManager = new CookieManager();
|
||||
List<String> cookiesHeader = headers.get("Set-Cookie");
|
||||
@@ -240,6 +227,40 @@ public class HttpFileInfoThread implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理"Content-Disposition"参数
|
||||
* <a href=https://cloud.tencent.com/developer/section/1189916>Content-Disposition</a></>
|
||||
*
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
private void handleContentDisposition(String disposition) throws UnsupportedEncodingException {
|
||||
if (disposition.contains(";")) {
|
||||
String[] infos = disposition.split(";");
|
||||
if (infos[0].equals("attachment")) {
|
||||
for (String info : infos) {
|
||||
if (info.startsWith("filename") && info.contains("=")) {
|
||||
String[] temp = info.split("=");
|
||||
if (temp.length > 1) {
|
||||
String newName = URLDecoder.decode(temp[1], "utf-8").replaceAll("\"", "");
|
||||
mEntity.setServerFileName(newName);
|
||||
renameFile(newName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (infos[0].equals("form-data") && infos.length > 2) {
|
||||
String[] temp = infos[2].split("=");
|
||||
if (temp.length > 1) {
|
||||
String newName = URLDecoder.decode(temp[1], "utf-8").replaceAll("\"", "");
|
||||
mEntity.setServerFileName(newName);
|
||||
renameFile(newName);
|
||||
}
|
||||
} else {
|
||||
ALog.w(TAG, "不识别的Content-Disposition参数");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重命名文件
|
||||
*/
|
||||
@@ -248,10 +269,12 @@ public class HttpFileInfoThread implements Runnable {
|
||||
ALog.w(TAG, "重命名失败【服务器返回的文件名为空】");
|
||||
return;
|
||||
}
|
||||
ALog.d(TAG, String.format("文件重命名为:%s", newName));
|
||||
File oldFile = new File(mEntity.getDownloadPath());
|
||||
String newPath = oldFile.getParent() + "/" + newName;
|
||||
if (oldFile.exists()) {
|
||||
oldFile.renameTo(new File(newPath));
|
||||
boolean b = oldFile.renameTo(new File(newPath));
|
||||
ALog.d(TAG, String.format("文件重命名%s", b ? "成功" : "失败"));
|
||||
}
|
||||
mEntity.setFileName(newName);
|
||||
mEntity.setDownloadPath(newPath);
|
||||
@@ -269,7 +292,7 @@ public class HttpFileInfoThread implements Runnable {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!CheckUtil.checkUrl(newUrl)) {
|
||||
if (!CheckUtil.checkUrlNotThrow(newUrl)) {
|
||||
failDownload(new TaskException(TAG, "下载失败,重定向url错误"), false);
|
||||
return;
|
||||
}
|
||||
@@ -296,6 +319,7 @@ public class HttpFileInfoThread implements Runnable {
|
||||
*/
|
||||
private boolean checkLen(long len) {
|
||||
if (len != mEntity.getFileSize()) {
|
||||
ALog.d(TAG, "长度不一致,任务为新任务");
|
||||
mTaskWrapper.setNewTask(true);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -19,7 +19,6 @@ import com.arialyy.aria.core.common.AbsThreadTask;
|
||||
import com.arialyy.aria.core.common.RequestEnum;
|
||||
import com.arialyy.aria.core.common.StateConstance;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.config.BaseTaskConfig;
|
||||
import com.arialyy.aria.core.config.DownloadConfig;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
@@ -30,6 +29,7 @@ import com.arialyy.aria.exception.TaskException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -44,6 +44,7 @@ import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2017/1/18. 下载线程
|
||||
@@ -87,7 +88,12 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
|
||||
ConnectionHelp.setConnectParam(taskDelegate, conn);
|
||||
conn.setConnectTimeout(getTaskConfig().getConnectTimeOut());
|
||||
conn.setReadTimeout(getTaskConfig().getIOTimeOut()); //设置读取流的等待时间,必须设置该参数
|
||||
if (taskDelegate.isChunked()) {
|
||||
conn.setDoInput(true);
|
||||
conn.setChunkedStreamingMode(0);
|
||||
}
|
||||
conn.connect();
|
||||
// 传递参数
|
||||
if (taskDelegate.getRequestEnum() == RequestEnum.POST) {
|
||||
Map<String, String> params = taskDelegate.getParams();
|
||||
if (params != null) {
|
||||
@@ -106,7 +112,9 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
|
||||
}
|
||||
|
||||
is = new BufferedInputStream(ConnectionHelp.convertInputStream(conn));
|
||||
if (isOpenDynamicFile) {
|
||||
if (taskDelegate.isChunked()) {
|
||||
readChunked(is);
|
||||
} else if (isOpenDynamicFile) {
|
||||
readDynamicFile(is);
|
||||
} else {
|
||||
//创建可设置位置的文件
|
||||
@@ -114,11 +122,7 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
|
||||
new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", getTaskConfig().getBuffSize());
|
||||
//设置每条线程写入文件的位置
|
||||
file.seek(mConfig.START_LOCATION);
|
||||
if (taskDelegate.isChunked()) {
|
||||
readChunk(is, file);
|
||||
} else {
|
||||
readNormal(is, file);
|
||||
}
|
||||
readNormal(is, file);
|
||||
handleComplete();
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
@@ -151,6 +155,41 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取chunked数据
|
||||
*/
|
||||
private void readChunked(InputStream is) {
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(mConfig.TEMP_FILE, true);
|
||||
byte[] buffer = new byte[getTaskConfig().getBuffSize()];
|
||||
int len;
|
||||
while (isLive() && (len = is.read(buffer)) != -1) {
|
||||
if (isBreak()) {
|
||||
break;
|
||||
}
|
||||
if (mSpeedBandUtil != null) {
|
||||
mSpeedBandUtil.limitNextBytes(len);
|
||||
}
|
||||
fos.write(buffer, 0, len);
|
||||
progress(len);
|
||||
}
|
||||
handleComplete();
|
||||
} catch (IOException e) {
|
||||
fail(mChildCurrentLocation, new AriaIOException(TAG,
|
||||
String.format("文件下载失败,savePath: %s, url: %s", mEntity.getDownloadPath(), mConfig.URL),
|
||||
e));
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态长度文件读取方式
|
||||
*/
|
||||
@@ -210,16 +249,6 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取chunk模式的文件流
|
||||
*
|
||||
* @deprecated 暂时先这样处理,无chun
|
||||
*/
|
||||
private void readChunk(InputStream is, BufferedRandomAccessFile file)
|
||||
throws IOException {
|
||||
readNormal(is, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取普通的文件流
|
||||
*/
|
||||
@@ -249,6 +278,12 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DTaskWrapper> {
|
||||
if (!checkBlock()) {
|
||||
return;
|
||||
}
|
||||
if (mTaskWrapper.asHttp().isChunked()) {
|
||||
ALog.i(TAG, "任务下载完成");
|
||||
STATE.isRunning = false;
|
||||
mListener.onComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mChildCurrentLocation == mConfig.END_LOCATION) {
|
||||
//支持断点的处理
|
||||
|
||||
@@ -126,6 +126,7 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
|
||||
case AbsTaskWrapper.D_FTP:
|
||||
return new FtpFileInfoThread(mTaskWrapper, new OnFileInfoCallback() {
|
||||
@Override public void onComplete(String url, CompleteInfo info) {
|
||||
mDownloader.updateTempFile();
|
||||
mDownloader.start();
|
||||
}
|
||||
|
||||
@@ -137,6 +138,7 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
|
||||
case AbsTaskWrapper.D_HTTP:
|
||||
return new HttpFileInfoThread(mTaskWrapper, new OnFileInfoCallback() {
|
||||
@Override public void onComplete(String url, CompleteInfo info) {
|
||||
mDownloader.updateTempFile();
|
||||
mDownloader.start();
|
||||
}
|
||||
|
||||
|
||||
@@ -44,14 +44,14 @@ class DGTaskWrapperFactory implements IGTEFactory<DownloadGroupEntity, DGTaskWra
|
||||
}
|
||||
|
||||
@Override public DGTaskWrapper getGTE(String groupHash, List<String> urls) {
|
||||
DownloadGroupEntity entity = DbDataHelper.getHttpDGEntity(groupHash, urls);
|
||||
DownloadGroupEntity entity = DbDataHelper.getOrCreateHttpDGEntity(groupHash, urls);
|
||||
DGTaskWrapper wrapper = new DGTaskWrapper(entity);
|
||||
wrapper.setSubTaskWrapper(createDGSubTaskWrapper(entity));
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@Override public DGTaskWrapper getFTE(String ftpUrl) {
|
||||
DownloadGroupEntity entity = DbDataHelper.getFtpDGEntity(ftpUrl);
|
||||
DownloadGroupEntity entity = DbDataHelper.getOrCreateFtpDGEntity(ftpUrl);
|
||||
DGTaskWrapper fte = new DGTaskWrapper(entity);
|
||||
fte.asFtp().setUrlEntity(CommonUtil.getFtpUrlInfo(ftpUrl));
|
||||
|
||||
|
||||
@@ -73,24 +73,27 @@ class DTaskWrapperFactory implements INormalTEFactory<DownloadEntity, DTaskWrapp
|
||||
entity.setDownloadPath(UUID.randomUUID().toString().replace("-", "")); //设置临时路径
|
||||
}
|
||||
File file = new File(entity.getDownloadPath());
|
||||
TaskRecord record =
|
||||
TaskRecord.findFirst(TaskRecord.class, "filePath=?", entity.getDownloadPath());
|
||||
if (record == null) {
|
||||
resetEntity(entity);
|
||||
} else {
|
||||
if (record.isBlock) {
|
||||
int count = 0;
|
||||
for (int i = 0, len = record.threadNum; i < len; i++) {
|
||||
File temp = new File(String.format(AbsFileer.SUB_PATH, record.filePath, i));
|
||||
if (!temp.exists()) {
|
||||
count++;
|
||||
|
||||
if (!entity.isComplete()) {
|
||||
TaskRecord record =
|
||||
TaskRecord.findFirst(TaskRecord.class, "filePath=?", entity.getDownloadPath());
|
||||
if (record == null) {
|
||||
resetEntity(entity);
|
||||
} else {
|
||||
if (record.isBlock) {
|
||||
int count = 0;
|
||||
for (int i = 0, len = record.threadNum; i < len; i++) {
|
||||
File temp = new File(String.format(AbsFileer.SUB_PATH, record.filePath, i));
|
||||
if (!temp.exists()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count == record.threadNum) {
|
||||
if (count == record.threadNum) {
|
||||
resetEntity(entity);
|
||||
}
|
||||
} else if (!file.exists()) { // 非分块文件需要判断文件是否存在
|
||||
resetEntity(entity);
|
||||
}
|
||||
} else if (!file.exists()) { // 非分块文件需要判断文件是否存在
|
||||
resetEntity(entity);
|
||||
}
|
||||
}
|
||||
return entity;
|
||||
|
||||
@@ -15,11 +15,9 @@
|
||||
*/
|
||||
package com.arialyy.aria.core.upload;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.CheckResult;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.Aria;
|
||||
import com.arialyy.aria.core.AriaManager;
|
||||
import com.arialyy.aria.core.command.ICmd;
|
||||
import com.arialyy.aria.core.command.normal.CancelAllCmd;
|
||||
|
||||
@@ -17,7 +17,6 @@ package com.arialyy.aria.orm;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.support.v4.util.LruCache;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -28,60 +27,6 @@ import java.net.URLEncoder;
|
||||
*/
|
||||
abstract class AbsDelegate {
|
||||
static final String TAG = "AbsDelegate";
|
||||
static final int CREATE_TABLE = 0;
|
||||
static final int TABLE_EXISTS = 1;
|
||||
static final int INSERT_DATA = 2;
|
||||
static final int MODIFY_DATA = 3;
|
||||
static final int FIND_DATA = 4;
|
||||
static final int DEL_DATA = 6;
|
||||
static final int ROW_ID = 7;
|
||||
static final int RELATION = 8;
|
||||
static final int DROP_TABLE = 9;
|
||||
|
||||
static LruCache<String, DbEntity> mDataCache = new LruCache<>(1024);
|
||||
|
||||
/**
|
||||
* 打印数据库日志
|
||||
*
|
||||
* @param type {@link DelegateWrapper}
|
||||
*/
|
||||
static void print(int type, String sql) {
|
||||
if (ALog.DEBUG) {
|
||||
return;
|
||||
}
|
||||
String str = "";
|
||||
switch (type) {
|
||||
case CREATE_TABLE:
|
||||
str = "创建表 >>>> ";
|
||||
break;
|
||||
case TABLE_EXISTS:
|
||||
str = "表是否存在 >>>> ";
|
||||
break;
|
||||
case INSERT_DATA:
|
||||
str = "插入数据 >>>> ";
|
||||
break;
|
||||
case MODIFY_DATA:
|
||||
str = "修改数据 >>>> ";
|
||||
break;
|
||||
case FIND_DATA:
|
||||
str = "查询数据 >>>> ";
|
||||
break;
|
||||
case ROW_ID:
|
||||
str = "查询RowId >>> ";
|
||||
break;
|
||||
case RELATION:
|
||||
str = "查询关联表 >>> ";
|
||||
break;
|
||||
case DROP_TABLE:
|
||||
str = "删除表 >>> ";
|
||||
break;
|
||||
}
|
||||
ALog.d(TAG, str.concat(sql));
|
||||
}
|
||||
|
||||
String getCacheKey(DbEntity dbEntity) {
|
||||
return dbEntity.getClass().getName() + "_" + dbEntity.rowID;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL编码字符串
|
||||
@@ -140,10 +85,6 @@ abstract class AbsDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
void close(SQLiteDatabase db) {
|
||||
//if (db != null && db.isOpen()) db.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数据库是否关闭,已经关闭的话,打开数据库
|
||||
*
|
||||
@@ -151,7 +92,7 @@ abstract class AbsDelegate {
|
||||
*/
|
||||
SQLiteDatabase checkDb(SQLiteDatabase db) {
|
||||
if (db == null || !db.isOpen()) {
|
||||
db = SqlHelper.INSTANCE.getWritableDatabase();
|
||||
db = SqlHelper.getInstance().getDb();
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import java.util.Map;
|
||||
*/
|
||||
class DBConfig {
|
||||
/*adb pull /mnt/sdcard/Android/data/com.arialyy.simple/files/DB/AriaLyyDb d:/db*/
|
||||
static boolean DEBUG = false;
|
||||
static Map<String, Class> mapping = new HashMap<>();
|
||||
static String DB_NAME;
|
||||
static int VERSION = 45;
|
||||
|
||||
@@ -42,7 +42,6 @@ class DelegateCommon extends AbsDelegate {
|
||||
void dropTable(SQLiteDatabase db, String tableName) {
|
||||
db = checkDb(db);
|
||||
String deleteSQL = String.format("DROP TABLE IF EXISTS %s", tableName);
|
||||
print(DROP_TABLE, deleteSQL);
|
||||
//db.beginTransaction();
|
||||
db.execSQL(deleteSQL);
|
||||
//db.setTransactionSuccessful();
|
||||
@@ -71,7 +70,6 @@ class DelegateCommon extends AbsDelegate {
|
||||
return tableExists(db, CommonUtil.getClassName(clazz));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查找表是否存在
|
||||
*
|
||||
@@ -85,7 +83,6 @@ class DelegateCommon extends AbsDelegate {
|
||||
String sql =
|
||||
String.format("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='%s'",
|
||||
tableName);
|
||||
print(TABLE_EXISTS, sql);
|
||||
cursor = db.rawQuery(sql, null);
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
int count = cursor.getInt(0);
|
||||
@@ -97,7 +94,6 @@ class DelegateCommon extends AbsDelegate {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
closeCursor(cursor);
|
||||
close(db);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -119,11 +115,9 @@ class DelegateCommon extends AbsDelegate {
|
||||
params[i] = String.format("'%s'", encodeStr(expression[i + 1]));
|
||||
}
|
||||
sql = String.format(sql, params);
|
||||
print(FIND_DATA, sql);
|
||||
Cursor cursor = db.rawQuery(sql, null);
|
||||
final boolean isExist = cursor.getCount() > 0;
|
||||
closeCursor(cursor);
|
||||
close(db);
|
||||
return isExist;
|
||||
}
|
||||
|
||||
@@ -223,9 +217,7 @@ class DelegateCommon extends AbsDelegate {
|
||||
|
||||
String str = sb.toString();
|
||||
str = str.substring(0, str.length() - 1) + ");";
|
||||
print(CREATE_TABLE, str);
|
||||
db.execSQL(str);
|
||||
}
|
||||
close(db);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -49,9 +49,7 @@ class DelegateUpdate extends AbsDelegate {
|
||||
params[i] = String.format("'%s'", encodeStr(expression[i + 1]));
|
||||
}
|
||||
sql = String.format(sql, params);
|
||||
print(DEL_DATA, sql);
|
||||
db.execSQL(sql);
|
||||
close(db);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,7 +64,6 @@ class DelegateUpdate extends AbsDelegate {
|
||||
} else {
|
||||
ALog.e(TAG, "更新记录失败,记录没有属性字段");
|
||||
}
|
||||
close(db);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,7 +136,6 @@ class DelegateUpdate extends AbsDelegate {
|
||||
} else {
|
||||
ALog.e(TAG, "保存记录失败,记录没有属性字段");
|
||||
}
|
||||
close(db);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,7 @@ public class DelegateWrapper {
|
||||
|
||||
private DelegateWrapper(Context context) {
|
||||
SqlHelper helper = SqlHelper.init(context.getApplicationContext());
|
||||
mDb = helper.getWritableDatabase();
|
||||
mDb = helper.getDb();
|
||||
mDManager = DelegateManager.getInstance();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,257 +1,302 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
/*
|
||||
* 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.os.Build;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import java.io.File;
|
||||
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";
|
||||
private static volatile SqlHelper INSTANCE = null;
|
||||
private Context mContext;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
static SqlHelper getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private SqlHelper(Context context, DelegateCommon delegate) {
|
||||
super(DBConfig.SAVE_IN_SDCARD ? new DatabaseContext(context) : context, DBConfig.DB_NAME, null,
|
||||
DBConfig.VERSION);
|
||||
mContext = context;
|
||||
mDelegate = delegate;
|
||||
}
|
||||
|
||||
@Override public void onOpen(SQLiteDatabase db) {
|
||||
super.onOpen(db);
|
||||
}
|
||||
|
||||
@Override public void onConfigure(SQLiteDatabase db) {
|
||||
super.onConfigure(db);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
db.setForeignKeyConstraintsEnabled(true);
|
||||
} else {
|
||||
// SQLite在3.6.19版本中开始支持外键约束,
|
||||
// 而在Android中 2.1以前的版本使用的SQLite版本是3.5.9, 在2.2版本中使用的是3.6.22.
|
||||
// 但是为了兼容以前的程序,默认并没有启用该功能,如果要启用该功能
|
||||
// 需要使用如下语句:
|
||||
db.execSQL("PRAGMA foreign_keys=ON;");
|
||||
}
|
||||
if (DBConfig.DEBUG) {
|
||||
db.enableWriteAheadLogging();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onCreate(SQLiteDatabase db) {
|
||||
DelegateCommon delegate = DelegateManager.getInstance().getDelegate(DelegateCommon.class);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库连接
|
||||
*/
|
||||
SQLiteDatabase getDb() {
|
||||
SQLiteDatabase db;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder().setOpenFlags(
|
||||
SQLiteDatabase.NO_LOCALIZED_COLLATORS | SQLiteDatabase.OPEN_READWRITE |
|
||||
SQLiteDatabase.CREATE_IF_NECESSARY).build();
|
||||
setOpenParams(params);
|
||||
db = getWritableDatabase();
|
||||
} else {
|
||||
//SQLiteDatabase.openOrCreateDatabase()
|
||||
File dbFile = mContext.getDatabasePath(DBConfig.DB_NAME);
|
||||
if (!dbFile.exists()) {
|
||||
db = getWritableDatabase();
|
||||
} else {
|
||||
// 触发一次SQLiteOpenHelper的流程,再使用NO_LOCALIZED_COLLATORS标志打开数据库
|
||||
db = getReadableDatabase();
|
||||
db.close();
|
||||
db = SQLiteDatabase.openDatabase(dbFile.getPath(), null,
|
||||
SQLiteDatabase.NO_LOCALIZED_COLLATORS | SQLiteDatabase.OPEN_READWRITE |
|
||||
SQLiteDatabase.CREATE_IF_NECESSARY);
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理数据库升级,该段代码无法修改表字段
|
||||
*
|
||||
* @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)) {
|
||||
//修改表名为中介表名
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理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);
|
||||
}
|
||||
}
|
||||
@@ -1,254 +1,269 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.exception.ParamException;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Created by Lyy on 2016/9/23.
|
||||
* 检查帮助类
|
||||
*/
|
||||
public class CheckUtil {
|
||||
private static final String TAG = "CheckUtil";
|
||||
|
||||
/**
|
||||
* 检查ftp上传路径,如果ftp上传路径为空,抛出空指针异常
|
||||
* 如果ftp上传路径不是以"ftp"或"sftp",抛出参数异常
|
||||
*
|
||||
* @param ftpUrl ftp上传路径
|
||||
*/
|
||||
public static void checkFtpUploadUrl(String ftpUrl) {
|
||||
if (TextUtils.isEmpty(ftpUrl)) {
|
||||
throw new ParamException("ftp上传路径为空");
|
||||
} else if (!ftpUrl.startsWith("ftp") || !ftpUrl.startsWith("sftp")) {
|
||||
throw new ParamException("ftp上传路径无效");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判空
|
||||
*/
|
||||
public static void checkNull(Object obj) {
|
||||
if (obj == null) throw new IllegalArgumentException("不能传入空对象");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查分页数据,需要查询的页数,从1开始,如果page小于1 或 num 小于1,则抛出{@link NullPointerException}
|
||||
*
|
||||
* @param page 从1 开始
|
||||
* @param num 每页数量
|
||||
*/
|
||||
public static void checkPageParams(int page, int num) {
|
||||
if (page < 1 || num < 1) throw new NullPointerException("page和num不能小于1");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查sql的expression是否合法
|
||||
*/
|
||||
public static void checkSqlExpression(String... expression) {
|
||||
if (expression.length == 0) {
|
||||
throw new IllegalArgumentException("sql语句表达式不能为null");
|
||||
}
|
||||
if (expression.length == 1) {
|
||||
throw new IllegalArgumentException("表达式需要写入参数");
|
||||
}
|
||||
String where = expression[0];
|
||||
if (!where.contains("?")) {
|
||||
throw new IllegalArgumentException("请在where语句的'='后编写?");
|
||||
}
|
||||
Pattern pattern = Pattern.compile("\\?");
|
||||
Matcher matcher = pattern.matcher(where);
|
||||
int count = 0;
|
||||
while (matcher.find()) {
|
||||
count++;
|
||||
}
|
||||
if (count < expression.length - 1) {
|
||||
throw new IllegalArgumentException("条件语句的?个数不能小于参数个数");
|
||||
}
|
||||
if (count > expression.length - 1) {
|
||||
throw new IllegalArgumentException("条件语句的?个数不能大于参数个数");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查下载实体
|
||||
*/
|
||||
public static void checkDownloadEntity(DownloadEntity entity) {
|
||||
checkUrlInvalidThrow(entity.getUrl());
|
||||
entity.setUrl(entity.getUrl());
|
||||
checkPath(entity.getDownloadPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测下载链接是否为null
|
||||
*/
|
||||
public static void checkPath(String path) {
|
||||
if (TextUtils.isEmpty(path)) {
|
||||
throw new IllegalArgumentException("保存路径不能为null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测url是否合法,如果url不合法,将抛异常
|
||||
*/
|
||||
public static void checkUrlInvalidThrow(String url) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
throw new IllegalArgumentException("url不能为null");
|
||||
} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
|
||||
throw new IllegalArgumentException("url错误");
|
||||
}
|
||||
int index = url.indexOf("://");
|
||||
if (index == -1) {
|
||||
throw new IllegalArgumentException("url不合法");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测url是否合法
|
||||
*
|
||||
* @return {@code true} 合法,{@code false} 非法
|
||||
*/
|
||||
public static boolean checkUrl(String url) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
ALog.e(TAG, "url不能为null");
|
||||
return false;
|
||||
} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
|
||||
ALog.e(TAG, "url【" + url + "】错误");
|
||||
return false;
|
||||
}
|
||||
int index = url.indexOf("://");
|
||||
if (index == -1) {
|
||||
ALog.e(TAG, "url【" + url + "】不合法");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测下载链接组是否为null
|
||||
*/
|
||||
public static void checkDownloadUrls(List<String> urls) {
|
||||
if (urls == null || urls.isEmpty()) {
|
||||
throw new IllegalArgumentException("链接组不能为null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查下载任务组保存路径
|
||||
*/
|
||||
public static void checkDownloadPaths(List<String> paths) {
|
||||
if (paths == null || paths.isEmpty()) {
|
||||
throw new IllegalArgumentException("链接保存路径不能为null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测上传地址是否为null
|
||||
*/
|
||||
public static void checkUploadPath(String uploadPath) {
|
||||
if (TextUtils.isEmpty(uploadPath)) {
|
||||
throw new IllegalArgumentException("上传地址不能为null");
|
||||
}
|
||||
File file = new File(uploadPath);
|
||||
if (!file.exists()) {
|
||||
throw new IllegalArgumentException("上传文件不存在");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查任务实体
|
||||
*/
|
||||
public static void checkTaskEntity(AbsTaskWrapper entity) {
|
||||
if (entity instanceof DTaskWrapper) {
|
||||
checkDownloadTaskEntity(((DTaskWrapper) entity).getEntity());
|
||||
} else if (entity instanceof UTaskWrapper) {
|
||||
checkUploadTaskEntity(((UTaskWrapper) entity).getEntity());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查命令实体
|
||||
*
|
||||
* @param checkType 删除命令和停止命令不需要检查下载链接和保存路径
|
||||
* @return {@code false}实体无效
|
||||
*/
|
||||
public static boolean checkCmdEntity(AbsTaskWrapper entity, boolean checkType) {
|
||||
boolean b = false;
|
||||
if (entity instanceof DTaskWrapper) {
|
||||
DownloadEntity entity1 = ((DTaskWrapper) entity).getEntity();
|
||||
if (entity1 == null) {
|
||||
ALog.e(TAG, "下载实体不能为空");
|
||||
} else if (checkType && TextUtils.isEmpty(entity1.getUrl())) {
|
||||
ALog.e(TAG, "下载链接不能为空");
|
||||
} else if (checkType && TextUtils.isEmpty(entity1.getDownloadPath())) {
|
||||
ALog.e(TAG, "保存路径不能为空");
|
||||
} else {
|
||||
b = true;
|
||||
}
|
||||
} else if (entity instanceof UTaskWrapper) {
|
||||
UploadEntity entity1 = ((UTaskWrapper) entity).getEntity();
|
||||
if (entity1 == null) {
|
||||
ALog.e(TAG, "上传实体不能为空");
|
||||
} else if (TextUtils.isEmpty(entity1.getFilePath())) {
|
||||
ALog.e(TAG, "上传文件路径不能为空");
|
||||
} else {
|
||||
b = true;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查上传实体是否合法
|
||||
*/
|
||||
private static void checkUploadTaskEntity(UploadEntity entity) {
|
||||
if (entity == null) {
|
||||
throw new NullPointerException("上传实体不能为空");
|
||||
} else if (TextUtils.isEmpty(entity.getFilePath())) {
|
||||
throw new IllegalArgumentException("上传文件路径不能为空");
|
||||
} else if (TextUtils.isEmpty(entity.getFileName())) {
|
||||
throw new IllegalArgumentException("上传文件名不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测下载实体是否合法
|
||||
* 合法(true)
|
||||
*
|
||||
* @param entity 下载实体
|
||||
*/
|
||||
private static void checkDownloadTaskEntity(DownloadEntity entity) {
|
||||
if (entity == null) {
|
||||
throw new NullPointerException("下载实体不能为空");
|
||||
} else if (TextUtils.isEmpty(entity.getUrl())) {
|
||||
throw new IllegalArgumentException("下载链接不能为空");
|
||||
} else if (TextUtils.isEmpty(entity.getFileName())) {
|
||||
throw new NullPointerException("文件名不能为null");
|
||||
} else if (TextUtils.isEmpty(entity.getDownloadPath())) {
|
||||
throw new NullPointerException("文件保存路径不能为null");
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.exception.ParamException;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Created by Lyy on 2016/9/23.
|
||||
* 检查帮助类
|
||||
*/
|
||||
public class CheckUtil {
|
||||
private static final String TAG = "CheckUtil";
|
||||
|
||||
/**
|
||||
* 检查ftp上传路径,如果ftp上传路径为空,抛出空指针异常
|
||||
* 如果ftp上传路径不是以"ftp"或"sftp",抛出参数异常
|
||||
*
|
||||
* @param ftpUrl ftp上传路径
|
||||
*/
|
||||
public static void checkFtpUploadUrl(String ftpUrl) {
|
||||
if (TextUtils.isEmpty(ftpUrl)) {
|
||||
throw new ParamException("ftp上传路径为空");
|
||||
} else if (!ftpUrl.startsWith("ftp") || !ftpUrl.startsWith("sftp")) {
|
||||
throw new ParamException("ftp上传路径无效");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判空
|
||||
*/
|
||||
public static void checkNull(Object obj) {
|
||||
if (obj == null) throw new IllegalArgumentException("不能传入空对象");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查分页数据,需要查询的页数,从1开始,如果page小于1 或 num 小于1,则抛出{@link NullPointerException}
|
||||
*
|
||||
* @param page 从1 开始
|
||||
* @param num 每页数量
|
||||
*/
|
||||
public static void checkPageParams(int page, int num) {
|
||||
if (page < 1 || num < 1) throw new NullPointerException("page和num不能小于1");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查sql的expression是否合法
|
||||
*/
|
||||
public static void checkSqlExpression(String... expression) {
|
||||
if (expression.length == 0) {
|
||||
throw new IllegalArgumentException("sql语句表达式不能为null");
|
||||
}
|
||||
if (expression.length == 1) {
|
||||
throw new IllegalArgumentException("表达式需要写入参数");
|
||||
}
|
||||
String where = expression[0];
|
||||
if (!where.contains("?")) {
|
||||
throw new IllegalArgumentException("请在where语句的'='后编写?");
|
||||
}
|
||||
Pattern pattern = Pattern.compile("\\?");
|
||||
Matcher matcher = pattern.matcher(where);
|
||||
int count = 0;
|
||||
while (matcher.find()) {
|
||||
count++;
|
||||
}
|
||||
if (count < expression.length - 1) {
|
||||
throw new IllegalArgumentException("条件语句的?个数不能小于参数个数");
|
||||
}
|
||||
if (count > expression.length - 1) {
|
||||
throw new IllegalArgumentException("条件语句的?个数不能大于参数个数");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查下载实体
|
||||
*/
|
||||
public static void checkDownloadEntity(DownloadEntity entity) {
|
||||
checkUrlInvalidThrow(entity.getUrl());
|
||||
entity.setUrl(entity.getUrl());
|
||||
checkPath(entity.getDownloadPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测下载链接是否为null
|
||||
*/
|
||||
public static void checkPath(String path) {
|
||||
if (TextUtils.isEmpty(path)) {
|
||||
throw new IllegalArgumentException("保存路径不能为null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测url是否合法,如果url不合法,将抛异常
|
||||
*/
|
||||
public static void checkUrlInvalidThrow(String url) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
throw new IllegalArgumentException("url不能为null");
|
||||
} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
|
||||
throw new IllegalArgumentException("url错误");
|
||||
}
|
||||
int index = url.indexOf("://");
|
||||
if (index == -1) {
|
||||
throw new IllegalArgumentException("url不合法");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测url是否合法,如果url不合法,将抛出{@link IllegalArgumentException}异常
|
||||
*/
|
||||
public static void checkUrl(String url) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
throw new NullPointerException("url为空");
|
||||
} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
|
||||
throw new IllegalArgumentException(String.format("url【%s】错误", url));
|
||||
}
|
||||
int index = url.indexOf("://");
|
||||
if (index == -1) {
|
||||
throw new IllegalArgumentException(String.format("url【%s】不合法", url));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测url是否合法
|
||||
*
|
||||
* @return {@code true} 合法,{@code false} 非法
|
||||
*/
|
||||
public static boolean checkUrlNotThrow(String url) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
ALog.e(TAG, "url不能为null");
|
||||
return false;
|
||||
} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
|
||||
ALog.e(TAG, "url【" + url + "】错误");
|
||||
return false;
|
||||
}
|
||||
int index = url.indexOf("://");
|
||||
if (index == -1) {
|
||||
ALog.e(TAG, "url【" + url + "】不合法");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测下载链接组是否为null
|
||||
*/
|
||||
public static void checkDownloadUrls(List<String> urls) {
|
||||
if (urls == null || urls.isEmpty()) {
|
||||
throw new IllegalArgumentException("链接组不能为null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查下载任务组保存路径
|
||||
*/
|
||||
public static void checkDownloadPaths(List<String> paths) {
|
||||
if (paths == null || paths.isEmpty()) {
|
||||
throw new IllegalArgumentException("链接保存路径不能为null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测上传地址是否为null
|
||||
*/
|
||||
public static void checkUploadPath(String uploadPath) {
|
||||
if (TextUtils.isEmpty(uploadPath)) {
|
||||
throw new IllegalArgumentException("上传地址不能为null");
|
||||
}
|
||||
File file = new File(uploadPath);
|
||||
if (!file.exists()) {
|
||||
throw new IllegalArgumentException("上传文件不存在");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查任务实体
|
||||
*/
|
||||
public static void checkTaskEntity(AbsTaskWrapper entity) {
|
||||
if (entity instanceof DTaskWrapper) {
|
||||
checkDownloadTaskEntity(((DTaskWrapper) entity).getEntity());
|
||||
} else if (entity instanceof UTaskWrapper) {
|
||||
checkUploadTaskEntity(((UTaskWrapper) entity).getEntity());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查命令实体
|
||||
*
|
||||
* @param checkType 删除命令和停止命令不需要检查下载链接和保存路径
|
||||
* @return {@code false}实体无效
|
||||
*/
|
||||
public static boolean checkCmdEntity(AbsTaskWrapper entity, boolean checkType) {
|
||||
boolean b = false;
|
||||
if (entity instanceof DTaskWrapper) {
|
||||
DownloadEntity entity1 = ((DTaskWrapper) entity).getEntity();
|
||||
if (entity1 == null) {
|
||||
ALog.e(TAG, "下载实体不能为空");
|
||||
} else if (checkType && TextUtils.isEmpty(entity1.getUrl())) {
|
||||
ALog.e(TAG, "下载链接不能为空");
|
||||
} else if (checkType && TextUtils.isEmpty(entity1.getDownloadPath())) {
|
||||
ALog.e(TAG, "保存路径不能为空");
|
||||
} else {
|
||||
b = true;
|
||||
}
|
||||
} else if (entity instanceof UTaskWrapper) {
|
||||
UploadEntity entity1 = ((UTaskWrapper) entity).getEntity();
|
||||
if (entity1 == null) {
|
||||
ALog.e(TAG, "上传实体不能为空");
|
||||
} else if (TextUtils.isEmpty(entity1.getFilePath())) {
|
||||
ALog.e(TAG, "上传文件路径不能为空");
|
||||
} else {
|
||||
b = true;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查上传实体是否合法
|
||||
*/
|
||||
private static void checkUploadTaskEntity(UploadEntity entity) {
|
||||
if (entity == null) {
|
||||
throw new NullPointerException("上传实体不能为空");
|
||||
} else if (TextUtils.isEmpty(entity.getFilePath())) {
|
||||
throw new IllegalArgumentException("上传文件路径不能为空");
|
||||
} else if (TextUtils.isEmpty(entity.getFileName())) {
|
||||
throw new IllegalArgumentException("上传文件名不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测下载实体是否合法
|
||||
* 合法(true)
|
||||
*
|
||||
* @param entity 下载实体
|
||||
*/
|
||||
private static void checkDownloadTaskEntity(DownloadEntity entity) {
|
||||
if (entity == null) {
|
||||
throw new NullPointerException("下载实体不能为空");
|
||||
} else if (TextUtils.isEmpty(entity.getUrl())) {
|
||||
throw new IllegalArgumentException("下载链接不能为空");
|
||||
} else if (TextUtils.isEmpty(entity.getFileName())) {
|
||||
throw new NullPointerException("文件名不能为null");
|
||||
} else if (TextUtils.isEmpty(entity.getDownloadPath())) {
|
||||
throw new NullPointerException("文件保存路径不能为null");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,13 +45,27 @@ public class DbDataHelper {
|
||||
return records.get(0).taskRecord;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组合任务实体、ftpDir任务实体
|
||||
*
|
||||
* @param groupHash 组合任务Hash
|
||||
* @return 实体不存在,返回null
|
||||
*/
|
||||
public static DownloadGroupEntity getDGEntity(String groupHash) {
|
||||
List<DGEntityWrapper> wrapper =
|
||||
DbEntity.findRelationData(DGEntityWrapper.class, "DownloadGroupEntity.groupHash=?",
|
||||
groupHash);
|
||||
|
||||
return wrapper == null ? null : wrapper.get(0).groupEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组合任务实体 如果数据库不存在该实体,则新创建一个新的任务组实体
|
||||
*
|
||||
* @param groupHash 组合任务Hash
|
||||
* @param urls 子任务url列表
|
||||
*/
|
||||
public static DownloadGroupEntity getHttpDGEntity(String groupHash, List<String> urls) {
|
||||
public static DownloadGroupEntity getOrCreateHttpDGEntity(String groupHash, List<String> urls) {
|
||||
List<DGEntityWrapper> wrapper =
|
||||
DbEntity.findRelationData(DGEntityWrapper.class, "DownloadGroupEntity.groupHash=?",
|
||||
groupHash);
|
||||
@@ -96,7 +110,7 @@ public class DbDataHelper {
|
||||
*
|
||||
* @param ftpUrl ftp下载地址
|
||||
*/
|
||||
public static DownloadGroupEntity getFtpDGEntity(String ftpUrl) {
|
||||
public static DownloadGroupEntity getOrCreateFtpDGEntity(String ftpUrl) {
|
||||
List<DGEntityWrapper> wrapper =
|
||||
DbEntity.findRelationData(DGEntityWrapper.class, "DownloadGroupEntity.groupHash=?",
|
||||
ftpUrl);
|
||||
|
||||
443
DEV_LOG.md
443
DEV_LOG.md
@@ -1,219 +1,226 @@
|
||||
## 开发日志
|
||||
+ v_3.6.4
|
||||
- 优化任务接收器的代码结构
|
||||
- 修复`DbEntity.saveAll()`失败的问题
|
||||
- 修复分块任务重命名失败的问题
|
||||
+ v_3.6.3 (2019/4/2)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/377
|
||||
+ v_3.6.2 (2019/4/1)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/368
|
||||
- 增加gradle 5.0支持
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/374
|
||||
- 增加分页功能,详情见:https://aria.laoyuyu.me/aria_doc/api/task_list.html#%E4%BB%BB%E5%8A%A1%E5%88%97%E8%A1%A8%E5%88%86%E9%A1%B5%EF%BC%88362%E4%BB%A5%E4%B8%8A%E7%89%88%E6%9C%AC%E6%94%AF%E6%8C%81%EF%BC%89
|
||||
+ v_3.6.1 (2019/3/5)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/367
|
||||
+ v_3.6 (2019/2/27)
|
||||
- 优化数据库写入\修改的速度
|
||||
- 精减任务实体的存储
|
||||
- 增加下载组合任务的配置
|
||||
- useBroadcast\notNetRetry这两个配置,统一在AppConfig中配置
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/361
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/365
|
||||
+ v_3.5.4 (2019/1/8)
|
||||
- 修复不支持断点的下载地址,重复下载出现的数据库主键冲突问题
|
||||
+ v_3.5.3 (2018/12/23)
|
||||
- 修复ftps不能加载默认证书的bug https://github.com/AriaLyy/Aria/issues/334
|
||||
- 优化注解性能,移除不必要的判断代码
|
||||
- 增加广播支持,详情见:http://aria.laoyuyu.me/aria_doc/api/use_broadcast.html
|
||||
- 增加get参数支持
|
||||
```java
|
||||
Aria.download(SingleTaskActivity.this)
|
||||
.load(DOWNLOAD_URL) // url 必须是主体url,也就是?前面的内容
|
||||
.setFilePath(path, true)
|
||||
.asGet()
|
||||
.setParams(params) // 设置参数
|
||||
.start();
|
||||
```
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/335
|
||||
- 新增进度百分比保存 https://github.com/AriaLyy/Aria/issues/336
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/335
|
||||
+ v_3.5.2
|
||||
- 添加Serializable接口支持 https://github.com/AriaLyy/Aria/issues/320
|
||||
- 失败回调增加错误原因 https://github.com/AriaLyy/Aria/issues/310
|
||||
```
|
||||
@Download.onTaskFail void taskFail(DownloadTask task, Exception e) {
|
||||
e.getMessage();
|
||||
...
|
||||
}
|
||||
```
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/322
|
||||
- 新增201 重定向支持 https://github.com/AriaLyy/Aria/issues/318
|
||||
- 修复使用`useServerFileName(true)`中含有`"`导致的文件后缀名错误问题
|
||||
- 优化logcat日志提示
|
||||
- 修改下载线程的优先级为`Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);`
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/319
|
||||
- 修复分卡下载失败的问题 https://github.com/AriaLyy/Aria/issues/326
|
||||
- 初始化Aria时会将所有数据库状态为下载中的任务改为已停止,防止应用被kill后,任务状态错误
|
||||
- 初始化时自动判断文件是否被删除,文件被删除的任务将自动重置默认值
|
||||
- 修复刷新url后,文件无法删除的 bug
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/309
|
||||
- 优化配置文件的读取
|
||||
+ v_3.5.1
|
||||
- 优化`taskExists`方法
|
||||
- 添加`post`参数请求支持
|
||||
```java
|
||||
Aria.download(SingleTaskActivity.this)
|
||||
.load(DOWNLOAD_URL)
|
||||
.setFilePath(path)
|
||||
.asPost() // post请求
|
||||
.setParam("key", "value") //传递参数
|
||||
//.setParams(Map<String, String>) // 传递多参数
|
||||
.start();
|
||||
```
|
||||
- 增加强制设置文件路径的api, https://github.com/AriaLyy/Aria/issues/311
|
||||
```
|
||||
Aria.download(SingleTaskActivity.this)
|
||||
.load(DOWNLOAD_URL)
|
||||
.setFilePath(path, true) // true表示忽略路径是否被占用
|
||||
.start();
|
||||
```
|
||||
+ v_3.5
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/302
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/283
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/305
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/306
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/272 (现在,停止所有任务,未开始的任务状态将变为停止)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/277
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/303
|
||||
- 优化停止任务的速度
|
||||
- 修复组合任务修改子任务文件名失败的问题
|
||||
+ v_3.4.12
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/286
|
||||
- 优化线程池任务
|
||||
+ v_3.4.11
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/288
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/282
|
||||
+ v_3.4.10
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/280
|
||||
+ v_3.4.9
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/276
|
||||
+ v_3.4.8
|
||||
- 组合任务新增`updateUrls(List<String>)`用于修改组合子任务的url,[see](https://aria.laoyuyu.me/aria_doc/api/update_url.html)
|
||||
- 出于安全考虑,FTP数据库去掉密码的保存
|
||||
- 增加FTPS支持 [see](https://aria.laoyuyu.me/aria_doc/download/ftps.html)
|
||||
- 增加速度限制支持[see](https://aria.laoyuyu.me/aria_doc/api/speed_handle.html)
|
||||
- 增加内存空间不足验证
|
||||
+ v_3.4.7
|
||||
- 修复分块任务异常操作导致的问题
|
||||
+ v_3.4.6
|
||||
- 修复android 4.4.4 版本多dex下无法进行回调的问题
|
||||
- 新增`updateUrl(newUrl)`用于修改任务的url,[see](https://aria.laoyuyu.me/aria_doc/api/task_handle.html#%E6%9B%B4%E6%96%B0%E4%BB%BB%E5%8A%A1url)
|
||||
- 优化分块下载
|
||||
- 修复了字符串中有特殊字符导致的路径冲突问题;修复ftp分块下载失败问题
|
||||
- 修复连接中有`+`导致的地址呗使用问题。
|
||||
- 修复表重复创建导致的崩溃问题 https://github.com/AriaLyy/Aria/issues/264
|
||||
+ v_3.4.4
|
||||
- 实现[多线程分块下载](https://aria.laoyuyu.me/aria_doc/start/config.html)
|
||||
- 修复`stopAll()`和`resumeAll()`导致的进度为0问题
|
||||
- 修复任务组添加header无效的问题
|
||||
+ v_3.4.3
|
||||
- 修复在activity 的onStop中取消注册导致的内存泄露问题
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/258
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/259
|
||||
+ v_3.4.2
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/248
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/247
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/250
|
||||
- 添加任务判断是否存在的api
|
||||
- 添加代理api
|
||||
- 修复删除所有没有进出等待的问题
|
||||
- 进度有时出错的问题
|
||||
- FTP添加超时处理
|
||||
+ v_3.4.1
|
||||
- 移除记录配置文件,改用数据库记录任务记录
|
||||
- 上传配置添加io超时时间、缓存大小配置
|
||||
- 添加没有网络也会重试的开关
|
||||
- 修复多次删除记录的bug
|
||||
- 文件长度现在可动态增加,详情见 https://aria.laoyuyu.me/aria_doc/start/config.html
|
||||
- 修复多module同时引用Aria导致打正式包出错的问题 https://github.com/AriaLyy/Aria/issues/240
|
||||
+ v_3.4
|
||||
- 优化大量代码
|
||||
- 重构Aria的ORM模型,提高了数据读取的可靠性和读写速度
|
||||
- 现在可在任意类中使用Aria了,[使用方法](http://aria.laoyuyu.me/aria_doc/start/any_java.html)
|
||||
- 添加`window.location.replace("http://xxxx")`类型的网页重定向支持
|
||||
- 支持gzip、deflate 压缩类型的输入流
|
||||
- 添加`useServerFileName`,可使用服务端响应header的`Content-Disposition`携带的文件名
|
||||
+ v_3.3.16
|
||||
- 修复一个activity启动多次,无法进行回掉的bug https://github.com/AriaLyy/Aria/issues/200
|
||||
- 优化target代码结构,移除路径被占用的提示
|
||||
- 添加支持chunked模式的下载
|
||||
- 去掉上一个版本"//"的限制
|
||||
+ v_3.3.14
|
||||
- 修复ftp上传和下载的兼容性问题
|
||||
- 如果url中的path有"//"将替换为"/"
|
||||
- 修复http上传成功后,如果服务器没有设置返回码导致上传失败的问题
|
||||
- 上传实体UploadEntity增加responseStr字段,http上传完成后,在被`@Upload.onComplete`注解的方法中,可通过`task.getEntity().getResponseStr())`获取服务器返回的数据
|
||||
- 如果服务器存在已上传了一部分的文件,用户执行删除该FTP上传任务,再次重新上传,会出现550,权限错误;本版本已修复该问题
|
||||
+ v_3.3.13
|
||||
- 添加`@Download.onWait、@Upload.onWait、@DownloadGroup.onWait`三个新注解,队列已经满了,继续创建新任务,任务处于等待中,将会执行被这三个注解标志的方法
|
||||
- app被kill,但是还存在等待中的任务A;第二次重新启动,先创建一个新的任务B,Aria会自动把B放进等待队列中,这时再次创建任务A,会导致重复下载,进度错乱的问题;本版本已修复这个问题
|
||||
+ v_3.3.11
|
||||
- 添加进度更新间隔api,在`aria_config.xml`配置`<updateInterval value="1000"/>`或在代码中调用
|
||||
`AriaManager.getInstance(AriaManager.APP).getDownloadConfig().setUpdateInterval(3000)`便可以改变进度刷新间隔
|
||||
- 修复下载过程中kill进程可能出现的文件错误的问题 https://github.com/AriaLyy/Aria/issues/192
|
||||
- 修复http上传的空指针问题 https://github.com/AriaLyy/Aria/issues/193
|
||||
- 修复下载地址中含有`'`导致的崩溃问题 https://github.com/AriaLyy/Aria/issues/194
|
||||
+ v_3.3.10
|
||||
- 修复地址切换导致下载失败的问题 https://github.com/AriaLyy/Aria/issues/181
|
||||
- 添加重置状态的api,当下载信息不改变,只是替换了服务器的对应的文件,可用`Aria.download(this).load(url).resetState()`重置下载状态 https://github.com/AriaLyy/Aria/issues/182
|
||||
+ v_3.3.9
|
||||
- 添加POST支持
|
||||
- 任务执行的过程中,如果调用removeRecord()方法,将会取消任务 https://github.com/AriaLyy/Aria/issues/174
|
||||
- 修复一个数据库初始化的问题 https://github.com/AriaLyy/Aria/issues/173
|
||||
- 修复head头部信息过长时出现的崩溃问题 https://github.com/AriaLyy/Aria/issues/177
|
||||
+ v_3.3.7
|
||||
- 修复一个线程重启的问题 https://github.com/AriaLyy/Aria/issues/160
|
||||
- 修复配置文件异常问题、格式化速度为0问题 https://github.com/AriaLyy/Aria/issues/161
|
||||
+ v_3.3.6
|
||||
- 增加日志输出级别控制
|
||||
- 修复公网FTP地址不能下载的问题 https://github.com/AriaLyy/Aria/issues/146
|
||||
- 修复http下载地址有空格的时候下载失败的问题 https://github.com/AriaLyy/Aria/issues/131
|
||||
- 修复Activity在`onDestroy()`中调用`Aria.download(this).unRegister();`导致回调失效的问题
|
||||
- 修复Adapter下载FTP任务问题、任务调度问题 https://github.com/AriaLyy/Aria/issues/157
|
||||
- 优化代码,优化了IO性能
|
||||
+ v_3.3.5 修复任务组、上传任务无法启动的bug
|
||||
+ v_3.3.4 优化任务代码结构,修复上一个版本暂停后无法自动执行任务的问题
|
||||
+ v_3.3.3 修复进度条错乱的问题,修复同一时间多次调用start导致重复下载的问题
|
||||
+ v_3.3.2 新加reTry(),修复上一个版本不会回调失败事件的问题;增加running状态下5秒钟保存一次数据库的功能;修复FTP断点上传文件不完整的问题
|
||||
+ v_3.3.1 增加网络事件,网络未连接,将不会重试下载,修复删除未开始任务,状态回调错误
|
||||
+ v_3.3.0 增加任务组子任务暂停和开始控制功能、修复5.0系统以上数据库多生成两个字段的bug、去掉addSchedulerListener事件
|
||||
+ v_3.2.26 修复任务组有时注解不起作用的问题
|
||||
+ v_3.2.25 修复删除任务组文件,记录无法删除的问题
|
||||
+ v_3.2.17 修复一个版本兼容性问题,线程中使用Aria出错问题
|
||||
+ v_3.2.15 修复大型文件分段下载失败的问题,修复中文URL乱码问题
|
||||
+ v_3.2.14 修复恢复所有任务的api接口,不能恢复下载组任务的问题
|
||||
+ v_3.2.13 修复某些服务器头文件返回描述文件格式错误的问题、修复有时删除任务,需要两次删除的问题
|
||||
+ v_3.2.12 实现FTP多线程断点续传下载,FTP断点续传上传功能
|
||||
+ v_3.2.9 修复任务组下载完成两次回掉的问题,修复又是获取不到下载状态的问题
|
||||
+ v_3.2.8 修复下载超过2G大小的文件失败的问题
|
||||
+ v_3.2.7 移除设置文件名的api接口,修复断开网络时出现的进度条错误的问题
|
||||
+ v_3.2.6 移除广播事件,增加任务组下载功能
|
||||
+ v_3.1.9 修复stopAll队列没有任务时崩溃的问题,增加针对单个任务监听的功能
|
||||
+ v_3.1.7 修复某些文件下载不了的bug,增加apt注解方法,事件获取更加简单了
|
||||
+ v_3.1.6 取消任务时onTaskCancel回调两次的bug
|
||||
+ v_3.1.5 优化代码结构,增加优先下载任务功能。
|
||||
+ v_3.1.4 修复快速切换,暂停、恢复功能时,概率性出现的重新下载问题,添加onPre()回调,onPre()用于请求地址之前执行界面UI更新操作。
|
||||
+ v_3.1.0 添加Aria配置文件,优化代码
|
||||
+ v_3.0.3 修复暂停后删除任务,闪退问题,添加删除记录的api
|
||||
+ v_3.0.2 支持30x重定向链接下载
|
||||
+ v_3.0.0 添加上传任务支持,修复一些已发现的bug
|
||||
+ v_2.4.4 修复不支持断点的下载链接拿不到文件大小的问题
|
||||
+ v_2.4.3 修复404链接卡顿的问题
|
||||
+ v_2.4.2 修复失败重试无效的bug
|
||||
+ v_2.4.1 修复下载慢的问题,修复application、service 不能使用的问题
|
||||
+ v_2.4.0 支持https链接下载
|
||||
+ v_2.3.8 修复数据错乱的bug、添加fragment支持
|
||||
+ v_2.3.6 添加dialog、popupWindow支持
|
||||
+ v_2.3.3 添加断点支持、修改下载逻辑,让使用更加简单、修复一个内存泄露的bug
|
||||
+ v_2.3.1 重命名为Aria,下载流程简化
|
||||
## 开发日志
|
||||
+ v_3.6.4
|
||||
- 优化任务接收器的代码结构
|
||||
- 修复`DbEntity.saveAll()`失败的问题
|
||||
- 修复分块任务重命名失败的问题
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/379
|
||||
- 移除`getDownloadTask(String url)`、`getGroupTask(List<String> urls)`、`getFtpDirTask(String path)`
|
||||
等获取任务的api,如果你希望获取对应状态,请使用实体的状态判断,如:`getDownloadEntity()`、`getDownloadGroupEntity()`
|
||||
`getFtpDirEntity()`
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/388
|
||||
- 修复使用`Content-Disposition`的文件名时,第一次下载无法重命名文件的问题
|
||||
- 修复使用`Content-Disposition`的文件名时,多次重命名文件的问题
|
||||
+ v_3.6.3 (2019/4/2)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/377
|
||||
+ v_3.6.2 (2019/4/1)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/368
|
||||
- 增加gradle 5.0支持
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/374
|
||||
- 增加分页功能,详情见:https://aria.laoyuyu.me/aria_doc/api/task_list.html#%E4%BB%BB%E5%8A%A1%E5%88%97%E8%A1%A8%E5%88%86%E9%A1%B5%EF%BC%88362%E4%BB%A5%E4%B8%8A%E7%89%88%E6%9C%AC%E6%94%AF%E6%8C%81%EF%BC%89
|
||||
+ v_3.6.1 (2019/3/5)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/367
|
||||
+ v_3.6 (2019/2/27)
|
||||
- 优化数据库写入\修改的速度
|
||||
- 精减任务实体的存储
|
||||
- 增加下载组合任务的配置
|
||||
- useBroadcast\notNetRetry这两个配置,统一在AppConfig中配置
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/361
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/365
|
||||
+ v_3.5.4 (2019/1/8)
|
||||
- 修复不支持断点的下载地址,重复下载出现的数据库主键冲突问题
|
||||
+ v_3.5.3 (2018/12/23)
|
||||
- 修复ftps不能加载默认证书的bug https://github.com/AriaLyy/Aria/issues/334
|
||||
- 优化注解性能,移除不必要的判断代码
|
||||
- 增加广播支持,详情见:http://aria.laoyuyu.me/aria_doc/api/use_broadcast.html
|
||||
- 增加get参数支持
|
||||
```java
|
||||
Aria.download(SingleTaskActivity.this)
|
||||
.load(DOWNLOAD_URL) // url 必须是主体url,也就是?前面的内容
|
||||
.setFilePath(path, true)
|
||||
.asGet()
|
||||
.setParams(params) // 设置参数
|
||||
.start();
|
||||
```
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/335
|
||||
- 新增进度百分比保存 https://github.com/AriaLyy/Aria/issues/336
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/335
|
||||
+ v_3.5.2
|
||||
- 添加Serializable接口支持 https://github.com/AriaLyy/Aria/issues/320
|
||||
- 失败回调增加错误原因 https://github.com/AriaLyy/Aria/issues/310
|
||||
```
|
||||
@Download.onTaskFail void taskFail(DownloadTask task, Exception e) {
|
||||
e.getMessage();
|
||||
...
|
||||
}
|
||||
```
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/322
|
||||
- 新增201 重定向支持 https://github.com/AriaLyy/Aria/issues/318
|
||||
- 修复使用`useServerFileName(true)`中含有`"`导致的文件后缀名错误问题
|
||||
- 优化logcat日志提示
|
||||
- 修改下载线程的优先级为`Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);`
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/319
|
||||
- 修复分卡下载失败的问题 https://github.com/AriaLyy/Aria/issues/326
|
||||
- 初始化Aria时会将所有数据库状态为下载中的任务改为已停止,防止应用被kill后,任务状态错误
|
||||
- 初始化时自动判断文件是否被删除,文件被删除的任务将自动重置默认值
|
||||
- 修复刷新url后,文件无法删除的 bug
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/309
|
||||
- 优化配置文件的读取
|
||||
+ v_3.5.1
|
||||
- 优化`taskExists`方法
|
||||
- 添加`post`参数请求支持
|
||||
```java
|
||||
Aria.download(SingleTaskActivity.this)
|
||||
.load(DOWNLOAD_URL)
|
||||
.setFilePath(path)
|
||||
.asPost() // post请求
|
||||
.setParam("key", "value") //传递参数
|
||||
//.setParams(Map<String, String>) // 传递多参数
|
||||
.start();
|
||||
```
|
||||
- 增加强制设置文件路径的api, https://github.com/AriaLyy/Aria/issues/311
|
||||
```java
|
||||
Aria.download(SingleTaskActivity.this)
|
||||
.load(DOWNLOAD_URL)
|
||||
.setFilePath(path, true) // true表示忽略路径是否被占用
|
||||
.start();
|
||||
```
|
||||
+ v_3.5
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/302
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/283
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/305
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/306
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/272 (现在,停止所有任务,未开始的任务状态将变为停止)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/277
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/303
|
||||
- 优化停止任务的速度
|
||||
- 修复组合任务修改子任务文件名失败的问题
|
||||
+ v_3.4.12
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/286
|
||||
- 优化线程池任务
|
||||
+ v_3.4.11
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/288
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/282
|
||||
+ v_3.4.10
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/280
|
||||
+ v_3.4.9
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/276
|
||||
+ v_3.4.8
|
||||
- 组合任务新增`updateUrls(List<String>)`用于修改组合子任务的url,[see](https://aria.laoyuyu.me/aria_doc/api/update_url.html)
|
||||
- 出于安全考虑,FTP数据库去掉密码的保存
|
||||
- 增加FTPS支持 [see](https://aria.laoyuyu.me/aria_doc/download/ftps.html)
|
||||
- 增加速度限制支持[see](https://aria.laoyuyu.me/aria_doc/api/speed_handle.html)
|
||||
- 增加内存空间不足验证
|
||||
+ v_3.4.7
|
||||
- 修复分块任务异常操作导致的问题
|
||||
+ v_3.4.6
|
||||
- 修复android 4.4.4 版本多dex下无法进行回调的问题
|
||||
- 新增`updateUrl(newUrl)`用于修改任务的url,[see](https://aria.laoyuyu.me/aria_doc/api/task_handle.html#%E6%9B%B4%E6%96%B0%E4%BB%BB%E5%8A%A1url)
|
||||
- 优化分块下载
|
||||
- 修复了字符串中有特殊字符导致的路径冲突问题;修复ftp分块下载失败问题
|
||||
- 修复连接中有`+`导致的地址呗使用问题。
|
||||
- 修复表重复创建导致的崩溃问题 https://github.com/AriaLyy/Aria/issues/264
|
||||
+ v_3.4.4
|
||||
- 实现[多线程分块下载](https://aria.laoyuyu.me/aria_doc/start/config.html)
|
||||
- 修复`stopAll()`和`resumeAll()`导致的进度为0问题
|
||||
- 修复任务组添加header无效的问题
|
||||
+ v_3.4.3
|
||||
- 修复在activity 的onStop中取消注册导致的内存泄露问题
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/258
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/259
|
||||
+ v_3.4.2
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/248
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/247
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/250
|
||||
- 添加任务判断是否存在的api
|
||||
- 添加代理api
|
||||
- 修复删除所有没有进出等待的问题
|
||||
- 进度有时出错的问题
|
||||
- FTP添加超时处理
|
||||
+ v_3.4.1
|
||||
- 移除记录配置文件,改用数据库记录任务记录
|
||||
- 上传配置添加io超时时间、缓存大小配置
|
||||
- 添加没有网络也会重试的开关
|
||||
- 修复多次删除记录的bug
|
||||
- 文件长度现在可动态增加,详情见 https://aria.laoyuyu.me/aria_doc/start/config.html
|
||||
- 修复多module同时引用Aria导致打正式包出错的问题 https://github.com/AriaLyy/Aria/issues/240
|
||||
+ v_3.4
|
||||
- 优化大量代码
|
||||
- 重构Aria的ORM模型,提高了数据读取的可靠性和读写速度
|
||||
- 现在可在任意类中使用Aria了,[使用方法](http://aria.laoyuyu.me/aria_doc/start/any_java.html)
|
||||
- 添加`window.location.replace("http://xxxx")`类型的网页重定向支持
|
||||
- 支持gzip、deflate 压缩类型的输入流
|
||||
- 添加`useServerFileName`,可使用服务端响应header的`Content-Disposition`携带的文件名
|
||||
+ v_3.3.16
|
||||
- 修复一个activity启动多次,无法进行回掉的bug https://github.com/AriaLyy/Aria/issues/200
|
||||
- 优化target代码结构,移除路径被占用的提示
|
||||
- 添加支持chunked模式的下载
|
||||
- 去掉上一个版本"//"的限制
|
||||
+ v_3.3.14
|
||||
- 修复ftp上传和下载的兼容性问题
|
||||
- 如果url中的path有"//"将替换为"/"
|
||||
- 修复http上传成功后,如果服务器没有设置返回码导致上传失败的问题
|
||||
- 上传实体UploadEntity增加responseStr字段,http上传完成后,在被`@Upload.onComplete`注解的方法中,可通过`task.getEntity().getResponseStr())`获取服务器返回的数据
|
||||
- 如果服务器存在已上传了一部分的文件,用户执行删除该FTP上传任务,再次重新上传,会出现550,权限错误;本版本已修复该问题
|
||||
+ v_3.3.13
|
||||
- 添加`@Download.onWait、@Upload.onWait、@DownloadGroup.onWait`三个新注解,队列已经满了,继续创建新任务,任务处于等待中,将会执行被这三个注解标志的方法
|
||||
- app被kill,但是还存在等待中的任务A;第二次重新启动,先创建一个新的任务B,Aria会自动把B放进等待队列中,这时再次创建任务A,会导致重复下载,进度错乱的问题;本版本已修复这个问题
|
||||
+ v_3.3.11
|
||||
- 添加进度更新间隔api,在`aria_config.xml`配置`<updateInterval value="1000"/>`或在代码中调用
|
||||
`AriaManager.getInstance(AriaManager.APP).getDownloadConfig().setUpdateInterval(3000)`便可以改变进度刷新间隔
|
||||
- 修复下载过程中kill进程可能出现的文件错误的问题 https://github.com/AriaLyy/Aria/issues/192
|
||||
- 修复http上传的空指针问题 https://github.com/AriaLyy/Aria/issues/193
|
||||
- 修复下载地址中含有`'`导致的崩溃问题 https://github.com/AriaLyy/Aria/issues/194
|
||||
+ v_3.3.10
|
||||
- 修复地址切换导致下载失败的问题 https://github.com/AriaLyy/Aria/issues/181
|
||||
- 添加重置状态的api,当下载信息不改变,只是替换了服务器的对应的文件,可用`Aria.download(this).load(url).resetState()`重置下载状态 https://github.com/AriaLyy/Aria/issues/182
|
||||
+ v_3.3.9
|
||||
- 添加POST支持
|
||||
- 任务执行的过程中,如果调用removeRecord()方法,将会取消任务 https://github.com/AriaLyy/Aria/issues/174
|
||||
- 修复一个数据库初始化的问题 https://github.com/AriaLyy/Aria/issues/173
|
||||
- 修复head头部信息过长时出现的崩溃问题 https://github.com/AriaLyy/Aria/issues/177
|
||||
+ v_3.3.7
|
||||
- 修复一个线程重启的问题 https://github.com/AriaLyy/Aria/issues/160
|
||||
- 修复配置文件异常问题、格式化速度为0问题 https://github.com/AriaLyy/Aria/issues/161
|
||||
+ v_3.3.6
|
||||
- 增加日志输出级别控制
|
||||
- 修复公网FTP地址不能下载的问题 https://github.com/AriaLyy/Aria/issues/146
|
||||
- 修复http下载地址有空格的时候下载失败的问题 https://github.com/AriaLyy/Aria/issues/131
|
||||
- 修复Activity在`onDestroy()`中调用`Aria.download(this).unRegister();`导致回调失效的问题
|
||||
- 修复Adapter下载FTP任务问题、任务调度问题 https://github.com/AriaLyy/Aria/issues/157
|
||||
- 优化代码,优化了IO性能
|
||||
+ v_3.3.5 修复任务组、上传任务无法启动的bug
|
||||
+ v_3.3.4 优化任务代码结构,修复上一个版本暂停后无法自动执行任务的问题
|
||||
+ v_3.3.3 修复进度条错乱的问题,修复同一时间多次调用start导致重复下载的问题
|
||||
+ v_3.3.2 新加reTry(),修复上一个版本不会回调失败事件的问题;增加running状态下5秒钟保存一次数据库的功能;修复FTP断点上传文件不完整的问题
|
||||
+ v_3.3.1 增加网络事件,网络未连接,将不会重试下载,修复删除未开始任务,状态回调错误
|
||||
+ v_3.3.0 增加任务组子任务暂停和开始控制功能、修复5.0系统以上数据库多生成两个字段的bug、去掉addSchedulerListener事件
|
||||
+ v_3.2.26 修复任务组有时注解不起作用的问题
|
||||
+ v_3.2.25 修复删除任务组文件,记录无法删除的问题
|
||||
+ v_3.2.17 修复一个版本兼容性问题,线程中使用Aria出错问题
|
||||
+ v_3.2.15 修复大型文件分段下载失败的问题,修复中文URL乱码问题
|
||||
+ v_3.2.14 修复恢复所有任务的api接口,不能恢复下载组任务的问题
|
||||
+ v_3.2.13 修复某些服务器头文件返回描述文件格式错误的问题、修复有时删除任务,需要两次删除的问题
|
||||
+ v_3.2.12 实现FTP多线程断点续传下载,FTP断点续传上传功能
|
||||
+ v_3.2.9 修复任务组下载完成两次回掉的问题,修复又是获取不到下载状态的问题
|
||||
+ v_3.2.8 修复下载超过2G大小的文件失败的问题
|
||||
+ v_3.2.7 移除设置文件名的api接口,修复断开网络时出现的进度条错误的问题
|
||||
+ v_3.2.6 移除广播事件,增加任务组下载功能
|
||||
+ v_3.1.9 修复stopAll队列没有任务时崩溃的问题,增加针对单个任务监听的功能
|
||||
+ v_3.1.7 修复某些文件下载不了的bug,增加apt注解方法,事件获取更加简单了
|
||||
+ v_3.1.6 取消任务时onTaskCancel回调两次的bug
|
||||
+ v_3.1.5 优化代码结构,增加优先下载任务功能。
|
||||
+ v_3.1.4 修复快速切换,暂停、恢复功能时,概率性出现的重新下载问题,添加onPre()回调,onPre()用于请求地址之前执行界面UI更新操作。
|
||||
+ v_3.1.0 添加Aria配置文件,优化代码
|
||||
+ v_3.0.3 修复暂停后删除任务,闪退问题,添加删除记录的api
|
||||
+ v_3.0.2 支持30x重定向链接下载
|
||||
+ v_3.0.0 添加上传任务支持,修复一些已发现的bug
|
||||
+ v_2.4.4 修复不支持断点的下载链接拿不到文件大小的问题
|
||||
+ v_2.4.3 修复404链接卡顿的问题
|
||||
+ v_2.4.2 修复失败重试无效的bug
|
||||
+ v_2.4.1 修复下载慢的问题,修复application、service 不能使用的问题
|
||||
+ v_2.4.0 支持https链接下载
|
||||
+ v_2.3.8 修复数据错乱的bug、添加fragment支持
|
||||
+ v_2.3.6 添加dialog、popupWindow支持
|
||||
+ v_2.3.3 添加断点支持、修改下载逻辑,让使用更加简单、修复一个内存泄露的bug
|
||||
+ v_2.3.1 重命名为Aria,下载流程简化
|
||||
+ v_2.1.1 增加,选择最大下载任务数接口
|
||||
344
README.md
344
README.md
@@ -1,172 +1,172 @@
|
||||
# Aria
|
||||
</br>
|
||||
## [ENGLISH DOC](https://github.com/AriaLyy/Aria/blob/master/ENGLISH_README.md)</br>
|
||||
## [中文文档](https://aria.laoyuyu.me/aria_doc)
|
||||
Aria项目源于工作中遇到的一个文件下载管理的需求,当时被下载折磨的痛不欲生,从那时起便萌生了编写一个简单易用,稳当高效的下载框架,aria经历了1.0到3.0的开发,算是越来越接近当初所制定的目标了。
|
||||
|
||||
Aria有以下特点:
|
||||
+ 简单、方便
|
||||
- 可以在Activity、Service、Fragment、Dialog、popupWindow、Notification等组件中使用
|
||||
- 支持HTTP\FTP断点续传下载、多任务自动调度
|
||||
- 支持多文件打包下载,多文件共享同一进度(如:视频 + 封面 + 字幕)
|
||||
- 支持下载FTP文件夹
|
||||
- 支持HTTP表单上传
|
||||
- 支持文件FTP断点续传上传
|
||||
- 支持FTPS/SFTP断点续传,[see](https://aria.laoyuyu.me/aria_doc/download/ftps.html)
|
||||
+ 支持https地址下载
|
||||
- 在配置文件中很容易就可以设置CA证书的信息
|
||||
+ 支持[多线程分块下载](https://aria.laoyuyu.me/aria_doc/start/config.html),能更有效的发挥机器IO性能
|
||||
+ 支持300、301、302重定向下载链接下载
|
||||
+ 下载支持文件长度动态增加,文件下载初始化时将不再占用过多的内存空间,见[动态长度配置](https://aria.laoyuyu.me/aria_doc/start/config.html#%E4%B8%8B%E8%BD%BD%E5%8A%A8%E6%80%81%E6%96%87%E4%BB%B6%E8%AF%B4%E6%98%8E)
|
||||
|
||||
[怎样使用Aria?](#使用)
|
||||
|
||||
如果你觉得Aria对你有帮助,您的star和issues将是对我最大支持.`^_^`
|
||||
|
||||
## 示例
|
||||
* 多任务下载
|
||||
|
||||

|
||||
|
||||
* 速度限制
|
||||
|
||||

|
||||
|
||||
* 多文件打包下载
|
||||
|
||||
<img src="https://github.com/AriaLyy/DownloadUtil/blob/master/img/group_task.gif" width="360" height="640"/>
|
||||
|
||||
|
||||
## 引入库
|
||||
[](https://bintray.com/arialyy/maven/AriaApi/_latestVersion)
|
||||
[](https://bintray.com/arialyy/maven/AriaCompiler/_latestVersion)
|
||||
|
||||
```java
|
||||
compile 'com.arialyy.aria:aria-core:3.6.3'
|
||||
annotationProcessor 'com.arialyy.aria:aria-compiler:3.6.3'
|
||||
```
|
||||
如果出现android support依赖错误,请将 `compile 'com.arialyy.aria:aria-core:<last-version>'`替换为
|
||||
```
|
||||
api('com.arialyy.aria:aria-core:<last-version>'){
|
||||
exclude group: 'com.android.support'
|
||||
}
|
||||
```
|
||||
如果你使用的是kotlin,请使用kotlin官方提供的方法配置apt,[kotlin kapt官方配置传送门](https://www.kotlincn.net/docs/reference/kapt.html)
|
||||
|
||||
__注意:3.5.4以下版本升级时,需要更新[配置文件]!!(https://aria.laoyuyu.me/aria_doc/start/config.html)__
|
||||
|
||||
***
|
||||
## 使用
|
||||
由于Aria涉及到文件和网络的操作,因此需要你在manifest文件中添加以下权限,如果你希望在6.0以上的系统中使用Aria,那么你需要动态向安卓系统申请文件系统读写权限,[如何使用安卓系统权限](https://developer.android.com/training/permissions/index.html?hl=zh-cn)
|
||||
```xml
|
||||
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
```
|
||||
|
||||
## 使用Aria
|
||||
### 基本使用
|
||||
例子为单任务下载,只需要很简单的代码,便可以实现下载功能
|
||||
```java
|
||||
Aria.download(this)
|
||||
.load(DOWNLOAD_URL) //读取下载地址
|
||||
.setDownloadPath(DOWNLOAD_PATH) //设置文件保存的完整路径
|
||||
.start(); //启动下载
|
||||
```
|
||||
|
||||
### 任务状态的获取
|
||||
基于解耦合的考虑,Aria的下载功能是和状态获取相分离的,状态的获取并不会集成到链式代码中,但是Aria提供了另一种更简单更灵活的方案。
|
||||
通过注解,你可以很容易获取任务的所有状态。
|
||||
|
||||
1. 将对象注册到Aria
|
||||
```java
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Aria.download(this).register();
|
||||
}
|
||||
```
|
||||
|
||||
2. 通过注解获取任务执行状态
|
||||
**注意:**
|
||||
- 注解回掉采用Apt的方式实现,所以,你不需要担心这会影响你机器的性能
|
||||
- 被注解的方法**不能被private修饰**
|
||||
- 被注解的方法**只能有一个参数,并且参数类型必须是`DownloadTask`或`UploadTask`或`DownloadGroupTask`**
|
||||
- 方法名可以为任意字符串
|
||||
|
||||
```java
|
||||
//在这里处理任务执行中的状态,如进度进度条的刷新
|
||||
@Download.onTaskRunning protected void running(DownloadTask task) {
|
||||
if(task.getUrl().eques(url)){
|
||||
....
|
||||
可以通过url判断是否是指定任务的回调
|
||||
}
|
||||
int p = task.getPercent(); //任务进度百分比
|
||||
String speed = task.getConvertSpeed(); //转换单位后的下载速度,单位转换需要在配置文件中打开
|
||||
String speed1 = task.getSpeed(); //原始byte长度速度
|
||||
}
|
||||
|
||||
@Download.onTaskComplete void taskComplete(DownloadTask task) {
|
||||
//在这里处理任务完成的状态
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 版本日志
|
||||
* v3.6.3 (2019/4/2)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/368
|
||||
- 增加gradle 5.0支持
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/374
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/377
|
||||
- 增加分页获取任务列表api, 详情见:https://aria.laoyuyu.me/aria_doc/api/task_list.html#%E4%BB%BB%E5%8A%A1%E5%88%97%E8%A1%A8%E5%88%86%E9%A1%B5%EF%BC%88362%E4%BB%A5%E4%B8%8A%E7%89%88%E6%9C%AC%E6%94%AF%E6%8C%81%EF%BC%89
|
||||
|
||||
[更多版本记录](https://github.com/AriaLyy/Aria/blob/master/DEV_LOG.md)
|
||||
|
||||
## 混淆配置
|
||||
```
|
||||
-dontwarn com.arialyy.aria.**
|
||||
-keep class com.arialyy.aria.**{*;}
|
||||
-keep class **$$DownloadListenerProxy{ *; }
|
||||
-keep class **$$UploadListenerProxy{ *; }
|
||||
-keep class **$$DownloadGroupListenerProxy{ *; }
|
||||
-keepclasseswithmembernames class * {
|
||||
@Download.* <methods>;
|
||||
@Upload.* <methods>;
|
||||
@DownloadGroup.* <methods>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 其他
|
||||
有任何问题,可以在[issues](https://github.com/AriaLyy/Aria/issues)给我留言反馈。</br>
|
||||
在提交问题前,希望你已经查看过[wiki](https://aria.laoyuyu.me/aria_doc/)或搜索过[issues](https://github.com/AriaLyy/Aria/issues)。</br>
|
||||
交流群:524329160
|
||||
|
||||
***
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Copyright 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.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Aria
|
||||
</br>
|
||||
## [ENGLISH DOC](https://github.com/AriaLyy/Aria/blob/master/ENGLISH_README.md)</br>
|
||||
## [中文文档](https://aria.laoyuyu.me/aria_doc)
|
||||
Aria项目源于工作中遇到的一个文件下载管理的需求,当时被下载折磨的痛不欲生,从那时起便萌生了编写一个简单易用,稳当高效的下载框架,aria经历了1.0到3.0的开发,算是越来越接近当初所制定的目标了。
|
||||
|
||||
Aria有以下特点:
|
||||
+ 简单、方便
|
||||
- 可以在Activity、Service、Fragment、Dialog、popupWindow、Notification等组件中使用
|
||||
- 支持HTTP\FTP断点续传下载、多任务自动调度
|
||||
- 支持多文件打包下载,多文件共享同一进度(如:视频 + 封面 + 字幕)
|
||||
- 支持下载FTP文件夹
|
||||
- 支持HTTP表单上传
|
||||
- 支持文件FTP断点续传上传
|
||||
- 支持FTPS/SFTP断点续传,[see](https://aria.laoyuyu.me/aria_doc/download/ftps.html)
|
||||
+ 支持https地址下载
|
||||
- 在配置文件中很容易就可以设置CA证书的信息
|
||||
+ 支持[多线程分块下载](https://aria.laoyuyu.me/aria_doc/start/config.html),能更有效的发挥机器IO性能
|
||||
+ 支持300、301、302重定向下载链接下载
|
||||
+ 下载支持文件长度动态增加,文件下载初始化时将不再占用过多的内存空间,见[动态长度配置](https://aria.laoyuyu.me/aria_doc/start/config.html#%E4%B8%8B%E8%BD%BD%E5%8A%A8%E6%80%81%E6%96%87%E4%BB%B6%E8%AF%B4%E6%98%8E)
|
||||
|
||||
[怎样使用Aria?](#使用)
|
||||
|
||||
如果你觉得Aria对你有帮助,您的star和issues将是对我最大支持.`^_^`
|
||||
|
||||
## 示例
|
||||
* 多任务下载
|
||||
|
||||

|
||||
|
||||
* 速度限制
|
||||
|
||||

|
||||
|
||||
* 多文件打包下载
|
||||
|
||||
<img src="https://github.com/AriaLyy/DownloadUtil/blob/master/img/group_task.gif" width="360" height="640"/>
|
||||
|
||||
|
||||
## 引入库
|
||||
[](https://bintray.com/arialyy/maven/AriaApi/_latestVersion)
|
||||
[](https://bintray.com/arialyy/maven/AriaCompiler/_latestVersion)
|
||||
|
||||
```java
|
||||
compile 'com.arialyy.aria:aria-core:3.6.3'
|
||||
annotationProcessor 'com.arialyy.aria:aria-compiler:3.6.3'
|
||||
```
|
||||
如果出现android support依赖错误,请将 `compile 'com.arialyy.aria:aria-core:<last-version>'`替换为
|
||||
```
|
||||
api('com.arialyy.aria:aria-core:<last-version>'){
|
||||
exclude group: 'com.android.support'
|
||||
}
|
||||
```
|
||||
如果你使用的是kotlin,请使用kotlin官方提供的方法配置apt,[kotlin kapt官方配置传送门](https://www.kotlincn.net/docs/reference/kapt.html)
|
||||
|
||||
__注意:3.5.4以下版本升级时,需要更新[配置文件]!!(https://aria.laoyuyu.me/aria_doc/start/config.html)__
|
||||
|
||||
***
|
||||
## 使用
|
||||
由于Aria涉及到文件和网络的操作,因此需要你在manifest文件中添加以下权限,如果你希望在6.0以上的系统中使用Aria,那么你需要动态向安卓系统申请文件系统读写权限,[如何使用安卓系统权限](https://developer.android.com/training/permissions/index.html?hl=zh-cn)
|
||||
```xml
|
||||
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
```
|
||||
|
||||
## 使用Aria
|
||||
### 基本使用
|
||||
例子为单任务下载,只需要很简单的代码,便可以实现下载功能
|
||||
```java
|
||||
Aria.download(this)
|
||||
.load(DOWNLOAD_URL) //读取下载地址
|
||||
.setDownloadPath(DOWNLOAD_PATH) //设置文件保存的完整路径
|
||||
.start(); //启动下载
|
||||
```
|
||||
|
||||
### 任务状态的获取
|
||||
基于解耦合的考虑,Aria的下载功能是和状态获取相分离的,状态的获取并不会集成到链式代码中,但是Aria提供了另一种更简单更灵活的方案。
|
||||
通过注解,你可以很容易获取任务的所有状态。
|
||||
|
||||
1. 将对象注册到Aria
|
||||
```java
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Aria.download(this).register();
|
||||
}
|
||||
```
|
||||
|
||||
2. 通过注解获取任务执行状态
|
||||
**注意:**
|
||||
- 注解回掉采用Apt的方式实现,所以,你不需要担心这会影响你机器的性能
|
||||
- 被注解的方法**不能被private修饰**
|
||||
- 被注解的方法**只能有一个参数,并且参数类型必须是`DownloadTask`或`UploadTask`或`DownloadGroupTask`**
|
||||
- 方法名可以为任意字符串
|
||||
|
||||
```java
|
||||
//在这里处理任务执行中的状态,如进度进度条的刷新
|
||||
@Download.onTaskRunning protected void running(DownloadTask task) {
|
||||
if(task.getKey().eques(url)){
|
||||
....
|
||||
可以通过url判断是否是指定任务的回调
|
||||
}
|
||||
int p = task.getPercent(); //任务进度百分比
|
||||
String speed = task.getConvertSpeed(); //转换单位后的下载速度,单位转换需要在配置文件中打开
|
||||
String speed1 = task.getSpeed(); //原始byte长度速度
|
||||
}
|
||||
|
||||
@Download.onTaskComplete void taskComplete(DownloadTask task) {
|
||||
//在这里处理任务完成的状态
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 版本日志
|
||||
* v3.6.3 (2019/4/2)
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/368
|
||||
- 增加gradle 5.0支持
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/374
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/377
|
||||
- 增加分页获取任务列表api, 详情见:https://aria.laoyuyu.me/aria_doc/api/task_list.html#%E4%BB%BB%E5%8A%A1%E5%88%97%E8%A1%A8%E5%88%86%E9%A1%B5%EF%BC%88362%E4%BB%A5%E4%B8%8A%E7%89%88%E6%9C%AC%E6%94%AF%E6%8C%81%EF%BC%89
|
||||
|
||||
[更多版本记录](https://github.com/AriaLyy/Aria/blob/master/DEV_LOG.md)
|
||||
|
||||
## 混淆配置
|
||||
```
|
||||
-dontwarn com.arialyy.aria.**
|
||||
-keep class com.arialyy.aria.**{*;}
|
||||
-keep class **$$DownloadListenerProxy{ *; }
|
||||
-keep class **$$UploadListenerProxy{ *; }
|
||||
-keep class **$$DownloadGroupListenerProxy{ *; }
|
||||
-keepclasseswithmembernames class * {
|
||||
@Download.* <methods>;
|
||||
@Upload.* <methods>;
|
||||
@DownloadGroup.* <methods>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 其他
|
||||
有任何问题,可以在[issues](https://github.com/AriaLyy/Aria/issues)给我留言反馈。</br>
|
||||
在提交问题前,希望你已经查看过[wiki](https://aria.laoyuyu.me/aria_doc/)或搜索过[issues](https://github.com/AriaLyy/Aria/issues)。</br>
|
||||
交流群:524329160
|
||||
|
||||
***
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Copyright 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.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,161 +1,161 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<aria>
|
||||
<!--注意,修改该配置文件中的属性会覆盖代码中所设置的属性-->
|
||||
|
||||
<!--Aria框架配置-->
|
||||
<app>
|
||||
<!--是否使用AriaCrashHandler来捕获异常,异常日志保存在:/mnt/sdcard/Android/data/{package_name}/files/log/-->
|
||||
<useAriaCrashHandler value="true"/>
|
||||
<!--设置Aria的日志级别,{@link ALog#LOG_LEVEL_VERBOSE}-->
|
||||
<logLevel value="2"/>
|
||||
<!-- 是否检查网络 true: 检查网络,false: 不检查网络-->
|
||||
<netCheck value="false"/>
|
||||
<!--除非无法使用注解,否则不建议使用广播来接受任务状态,true:使用广播接收任务状态,false:不适用广播接收状态 -->
|
||||
<!-- http://aria.laoyuyu.me/aria_doc/api/use_broadcast.html -->
|
||||
<useBroadcast value="true"/>
|
||||
<!--断网的时候是否重试,true:断网也重试;false:断网不重试,直接走失败的回调-->
|
||||
<notNetRetry value="true"/>
|
||||
</app>
|
||||
|
||||
|
||||
<!--普通下载任务-->
|
||||
<download>
|
||||
|
||||
<!--设置任务最大下载速度,0表示不限速,单位为:kb-->
|
||||
<maxSpeed value="128"/>
|
||||
|
||||
<!--
|
||||
多线程下载是否使用块下载模式,{@code true}使用,{@code false}不使用
|
||||
注意:
|
||||
1、使用分块模式,在I/O性能底下的手机上,合并文件需要的时间会更加长;
|
||||
2、优点是使用多线程的块下载,初始化时,文件初始化时将不会预占用对应长度的空间;
|
||||
3、只对新的多线程下载任务有效
|
||||
4、只对多线程的任务有效
|
||||
-->
|
||||
<useBlock value="true"/>
|
||||
|
||||
<!--设置下载线程数,下载线程数不能小于1
|
||||
注意:
|
||||
1、线程下载数改变后,新的下载任务才会生效;
|
||||
2、如果任务大小小于1m,该设置不会生效;
|
||||
3、从3.4.1开始,如果线程数为1,文件初始化时将不再预占用对应长度的空间,下载多少byte,则占多大的空间;
|
||||
对于3.4.1之前版本的未完成的老任务,依然采用原来的文件空间占用方式;
|
||||
-->
|
||||
<threadNum value="1"/>
|
||||
|
||||
<!--设置下载队列最大任务数, 默认为2-->
|
||||
<maxTaskNum value="1"/>
|
||||
|
||||
<!--设置下载失败,重试次数,默认为10-->
|
||||
<reTryNum value="1"/>
|
||||
|
||||
<!--设置重试间隔,单位为毫秒,默认2000毫秒-->
|
||||
<reTryInterval value="5000"/>
|
||||
|
||||
<!--设置url连接超时时间,单位为毫秒,默认5000毫秒-->
|
||||
<connectTimeOut value="5000"/>
|
||||
|
||||
<!--设置IO流读取时间,单位为毫秒,默认20000毫秒,该时间不能少于10000毫秒-->
|
||||
<iOTimeOut value="10000"/>
|
||||
|
||||
<!--设置写文件buff大小,该数值大小不能小于2048,数值变小,下载速度会变慢-->
|
||||
<buffSize value="8192"/>
|
||||
|
||||
<!--设置https ca 证书信息;path 为assets目录下的CA证书完整路径,name 为CA证书名-->
|
||||
<ca name="" path=""/>
|
||||
|
||||
<!--是否需要转换速度单位,转换完成后为:1b/s、1kb/s、1mb/s、1gb/s、1tb/s,如果不需要将返回byte长度-->
|
||||
<convertSpeed value="true"/>
|
||||
|
||||
<!--执行队列类型,见com.arialyy.aria.core.QueueMod,默认类型为wait-->
|
||||
<queueMod value="wait"/>
|
||||
|
||||
<!--进度更新更新间隔,默认1000毫秒-->
|
||||
<updateInterval value="1000"/>
|
||||
|
||||
</download>
|
||||
|
||||
<!--普通上传任务-->
|
||||
<upload>
|
||||
<!--设置任务最大上传速度,0表示不限速,单位为:kb-->
|
||||
<maxSpeed value="0"/>
|
||||
|
||||
<!--设置IO流读取时间,单位为毫秒,默认20000毫秒,该时间不能少于10000毫秒-->
|
||||
<iOTimeOut value="10000"/>
|
||||
|
||||
<!--设置写文件buff大小,该数值大小不能小于2048,数值变小,速度会变慢-->
|
||||
<buffSize value="8192"/>
|
||||
|
||||
<!--是否需要转换速度单位,转换完成后为:1b/s、1kb/s、1mb/s、1gb/s、1tb/s,如果不需要将返回byte长度-->
|
||||
<convertSpeed value="true"/>
|
||||
|
||||
<!--设置上传队列最大任务数, 默认为2-->
|
||||
<maxTaskNum value="2"/>
|
||||
|
||||
<!--设置上传失败,重试次数,默认为10-->
|
||||
<reTryNum value="3"/>
|
||||
|
||||
<!--设置重试间隔,单位为毫秒-->
|
||||
<reTryInterval value="2000"/>
|
||||
|
||||
<!--设置url连接超时时间,单位为毫秒,默认5000毫秒-->
|
||||
<connectTimeOut value="5000"/>
|
||||
|
||||
<!--执行队列类型,见com.arialyy.aria.core.QueueMod,默认类型为wait-->
|
||||
<queueMod value="wait"/>
|
||||
|
||||
<!--进度更新更新间隔,默认1000毫秒-->
|
||||
<updateInterval value="1000"/>
|
||||
|
||||
</upload>
|
||||
|
||||
<!-- 下载类组合任务 -->
|
||||
<dGroup>
|
||||
|
||||
<!--组合任务下载队列最大任务数, 默认为2-->
|
||||
<maxTaskNum value="1"/>
|
||||
|
||||
<!--设置下载失败,重试次数,默认为10-->
|
||||
<reTryNum value="1"/>
|
||||
|
||||
<!--设置重试间隔,单位为毫秒,默认2000毫秒-->
|
||||
<reTryInterval value="5000"/>
|
||||
|
||||
<!--执行队列类型,见com.arialyy.aria.core.QueueMod,默认类型为wait-->
|
||||
<queueMod value="wait"/>
|
||||
|
||||
<!--进度更新更新间隔,默认1000毫秒-->
|
||||
<updateInterval value="1000"/>
|
||||
|
||||
|
||||
<!-- =============================以下为子任务的配置====================================-->
|
||||
|
||||
<!--能同时下载的子任务最大任务数,默认3-->
|
||||
<subMaxTaskNum value="1"/>
|
||||
|
||||
<!--子任务下载失败时的重试次数,默认为5-->
|
||||
<subReTryNum value="5"/>
|
||||
|
||||
<!--子任务下载失败时的重试间隔,单位为毫秒,默认2000毫秒-->
|
||||
<subReTryInterval value="5000"/>
|
||||
|
||||
<!--子任务url连接超时时间,单位为毫秒,默认5000毫秒-->
|
||||
<connectTimeOut value="5000"/>
|
||||
|
||||
<!--子任务IO流读取时间,单位为毫秒,默认20000毫秒,该时间不能少于10000毫秒-->
|
||||
<iOTimeOut value="10000"/>
|
||||
|
||||
<!--子任务写文件buff大小,该数值大小不能小于2048,数值变小,下载速度会变慢-->
|
||||
<buffSize value="8192"/>
|
||||
|
||||
<!--子任务 https ca 证书信息;path 为assets目录下的CA证书完整路径,name 为CA证书名-->
|
||||
<ca name="" path=""/>
|
||||
|
||||
<!--子任务是否需要转换速度单位,转换完成后为:1b/s、1kb/s、1mb/s、1gb/s、1tb/s,如果不需要将返回byte长度-->
|
||||
<convertSpeed value="true"/>
|
||||
|
||||
<!--子任务的最大下载速度,0表示不限速,单位为:kb; -->
|
||||
<maxSpeed value="0"/>
|
||||
|
||||
</dGroup>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<aria>
|
||||
<!--注意,修改该配置文件中的属性会覆盖代码中所设置的属性-->
|
||||
|
||||
<!--Aria框架配置-->
|
||||
<app>
|
||||
<!--是否使用AriaCrashHandler来捕获异常,异常日志保存在:/mnt/sdcard/Android/data/{package_name}/files/log/-->
|
||||
<useAriaCrashHandler value="true"/>
|
||||
<!--设置Aria的日志级别,{@link ALog#LOG_LEVEL_VERBOSE}-->
|
||||
<logLevel value="2"/>
|
||||
<!-- 是否检查网络 true: 检查网络,false: 不检查网络-->
|
||||
<netCheck value="false"/>
|
||||
<!--除非无法使用注解,否则不建议使用广播来接受任务状态,true:使用广播接收任务状态,false:不适用广播接收状态 -->
|
||||
<!-- http://aria.laoyuyu.me/aria_doc/api/use_broadcast.html -->
|
||||
<useBroadcast value="true"/>
|
||||
<!--断网的时候是否重试,true:断网也重试;false:断网不重试,直接走失败的回调-->
|
||||
<notNetRetry value="true"/>
|
||||
</app>
|
||||
|
||||
|
||||
<!--普通下载任务-->
|
||||
<download>
|
||||
|
||||
<!--设置任务最大下载速度,0表示不限速,单位为:kb-->
|
||||
<maxSpeed value="128"/>
|
||||
|
||||
<!--
|
||||
多线程下载是否使用块下载模式,{@code true}使用,{@code false}不使用
|
||||
注意:
|
||||
1、使用分块模式,在I/O性能底下的手机上,合并文件需要的时间会更加长;
|
||||
2、优点是使用多线程的块下载,初始化时,文件初始化时将不会预占用对应长度的空间;
|
||||
3、只对新的多线程下载任务有效
|
||||
4、只对多线程的任务有效
|
||||
-->
|
||||
<useBlock value="true"/>
|
||||
|
||||
<!--设置下载线程数,下载线程数不能小于1
|
||||
注意:
|
||||
1、线程下载数改变后,新的下载任务才会生效;
|
||||
2、如果任务大小小于1m,该设置不会生效;
|
||||
3、从3.4.1开始,如果线程数为1,文件初始化时将不再预占用对应长度的空间,下载多少byte,则占多大的空间;
|
||||
对于3.4.1之前版本的未完成的老任务,依然采用原来的文件空间占用方式;
|
||||
-->
|
||||
<threadNum value="3"/>
|
||||
|
||||
<!--设置下载队列最大任务数, 默认为2-->
|
||||
<maxTaskNum value="1"/>
|
||||
|
||||
<!--设置下载失败,重试次数,默认为10-->
|
||||
<reTryNum value="1"/>
|
||||
|
||||
<!--设置重试间隔,单位为毫秒,默认2000毫秒-->
|
||||
<reTryInterval value="5000"/>
|
||||
|
||||
<!--设置url连接超时时间,单位为毫秒,默认5000毫秒-->
|
||||
<connectTimeOut value="5000"/>
|
||||
|
||||
<!--设置IO流读取时间,单位为毫秒,默认20000毫秒,该时间不能少于10000毫秒-->
|
||||
<iOTimeOut value="10000"/>
|
||||
|
||||
<!--设置写文件buff大小,该数值大小不能小于2048,数值变小,下载速度会变慢-->
|
||||
<buffSize value="8192"/>
|
||||
|
||||
<!--设置https ca 证书信息;path 为assets目录下的CA证书完整路径,name 为CA证书名-->
|
||||
<ca name="" path=""/>
|
||||
|
||||
<!--是否需要转换速度单位,转换完成后为:1b/s、1kb/s、1mb/s、1gb/s、1tb/s,如果不需要将返回byte长度-->
|
||||
<convertSpeed value="true"/>
|
||||
|
||||
<!--执行队列类型,见com.arialyy.aria.core.QueueMod,默认类型为wait-->
|
||||
<queueMod value="wait"/>
|
||||
|
||||
<!--进度更新更新间隔,默认1000毫秒-->
|
||||
<updateInterval value="1000"/>
|
||||
|
||||
</download>
|
||||
|
||||
<!--普通上传任务-->
|
||||
<upload>
|
||||
<!--设置任务最大上传速度,0表示不限速,单位为:kb-->
|
||||
<maxSpeed value="0"/>
|
||||
|
||||
<!--设置IO流读取时间,单位为毫秒,默认20000毫秒,该时间不能少于10000毫秒-->
|
||||
<iOTimeOut value="10000"/>
|
||||
|
||||
<!--设置写文件buff大小,该数值大小不能小于2048,数值变小,速度会变慢-->
|
||||
<buffSize value="8192"/>
|
||||
|
||||
<!--是否需要转换速度单位,转换完成后为:1b/s、1kb/s、1mb/s、1gb/s、1tb/s,如果不需要将返回byte长度-->
|
||||
<convertSpeed value="true"/>
|
||||
|
||||
<!--设置上传队列最大任务数, 默认为2-->
|
||||
<maxTaskNum value="2"/>
|
||||
|
||||
<!--设置上传失败,重试次数,默认为10-->
|
||||
<reTryNum value="3"/>
|
||||
|
||||
<!--设置重试间隔,单位为毫秒-->
|
||||
<reTryInterval value="2000"/>
|
||||
|
||||
<!--设置url连接超时时间,单位为毫秒,默认5000毫秒-->
|
||||
<connectTimeOut value="5000"/>
|
||||
|
||||
<!--执行队列类型,见com.arialyy.aria.core.QueueMod,默认类型为wait-->
|
||||
<queueMod value="wait"/>
|
||||
|
||||
<!--进度更新更新间隔,默认1000毫秒-->
|
||||
<updateInterval value="1000"/>
|
||||
|
||||
</upload>
|
||||
|
||||
<!-- 下载类组合任务 -->
|
||||
<dGroup>
|
||||
|
||||
<!--组合任务下载队列最大任务数, 默认为2-->
|
||||
<maxTaskNum value="1"/>
|
||||
|
||||
<!--设置下载失败,重试次数,默认为10-->
|
||||
<reTryNum value="1"/>
|
||||
|
||||
<!--设置重试间隔,单位为毫秒,默认2000毫秒-->
|
||||
<reTryInterval value="5000"/>
|
||||
|
||||
<!--执行队列类型,见com.arialyy.aria.core.QueueMod,默认类型为wait-->
|
||||
<queueMod value="wait"/>
|
||||
|
||||
<!--进度更新更新间隔,默认1000毫秒-->
|
||||
<updateInterval value="1000"/>
|
||||
|
||||
|
||||
<!-- =============================以下为子任务的配置====================================-->
|
||||
|
||||
<!--能同时下载的子任务最大任务数,默认3-->
|
||||
<subMaxTaskNum value="1"/>
|
||||
|
||||
<!--子任务下载失败时的重试次数,默认为5-->
|
||||
<subReTryNum value="5"/>
|
||||
|
||||
<!--子任务下载失败时的重试间隔,单位为毫秒,默认2000毫秒-->
|
||||
<subReTryInterval value="5000"/>
|
||||
|
||||
<!--子任务url连接超时时间,单位为毫秒,默认5000毫秒-->
|
||||
<connectTimeOut value="5000"/>
|
||||
|
||||
<!--子任务IO流读取时间,单位为毫秒,默认20000毫秒,该时间不能少于10000毫秒-->
|
||||
<iOTimeOut value="10000"/>
|
||||
|
||||
<!--子任务写文件buff大小,该数值大小不能小于2048,数值变小,下载速度会变慢-->
|
||||
<buffSize value="8192"/>
|
||||
|
||||
<!--子任务 https ca 证书信息;path 为assets目录下的CA证书完整路径,name 为CA证书名-->
|
||||
<ca name="" path=""/>
|
||||
|
||||
<!--子任务是否需要转换速度单位,转换完成后为:1b/s、1kb/s、1mb/s、1gb/s、1tb/s,如果不需要将返回byte长度-->
|
||||
<convertSpeed value="true"/>
|
||||
|
||||
<!--子任务的最大下载速度,0表示不限速,单位为:kb; -->
|
||||
<maxSpeed value="0"/>
|
||||
|
||||
</dGroup>
|
||||
</aria>
|
||||
@@ -31,6 +31,7 @@ import android.widget.Toast;
|
||||
|
||||
import com.arialyy.annotations.Download;
|
||||
import com.arialyy.aria.core.Aria;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadTarget;
|
||||
import com.arialyy.aria.core.download.DownloadTask;
|
||||
@@ -57,14 +58,11 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
||||
//"http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apks";
|
||||
//"http://120.55.95.61:8811/ghcg/zg/武义总规纲要成果.zip";
|
||||
//"https://yizi-kejian.oss-cn-beijing.aliyuncs.com/qimeng/package1/qmtable11.zip";
|
||||
"http://rs.0.gaoshouyou.com/d/04/1e/400423a7551e1f3f0eb1812afa1f9b44.apk";
|
||||
//"http://rs.0.gaoshouyou.com/d/04/1e/400423a7551e1f3f0eb1812afa1f9b44.apk";
|
||||
//"http://chargepile2.techsum.net/car-manage/file/download?path=2019-04-26/c0242efd18be4ecbb23911b1c509dcad--掌通各系统汇总.xls"; // 无长度的chunked
|
||||
//"http://58.210.9.131/tpk/sipgt//TDLYZTGH.tpk"; //chunked 下载
|
||||
//"https://static.donguo.me/video/ip/course/pfys_1.mp4";
|
||||
//"https://www.baidu.com/link?url=_LFCuTPtnzFxVJByJ504QymRywIA1Z_T5xUxe9ZLuxcGM0C_RcdpWyB1eGjbJC-e5wv5wAKM4WmLMAS5KeF6EZJHB8Va3YqZUiaErqK_pxm&wd=&eqid=e8583fe70002d126000000065a99f864";
|
||||
//"https://d.pcs.baidu.com/file/a02c89a2d479d4fd2756f3313d42491d?fid=4232431903-250528-1114369760340736&dstime=1525491372&rt=sh&sign=FDtAERVY-DCb740ccc5511e5e8fedcff06b081203-3C13vkOkuk4TqXvVYW05zj1K0ao%3D&expires=8h&chkv=1&chkbd=0&chkpc=et&dp-logid=8651730921842106225&dp-callid=0&r=165533013";
|
||||
//"http://apk500.bce.baidu-mgame.com/game/67000/67734/20170622040827_oem_5502845.apk?r=1";
|
||||
"http://apk500.bce.baidu-mgame.com/game/67000/67734/20170622040827_oem_5502845.apk?r=1";
|
||||
//"https://dl.genymotion.com/releases/genymotion-2.12.1/genymotion-2.12.1-vbox.exe";
|
||||
//"http://9.9.9.50:5000/download1";
|
||||
//"http://9.9.9.50:5000/download/CentOS-7-x86_64-Minimal-1804.iso";
|
||||
//"http://v2.qingdian1.com/m_20180730_991/2/2B9FB34A4BCD8CE61481D1C8418EFE36_1080P.m3u8";
|
||||
//"https://firmwareapi.azurewebsites.net/firmware-overview?name=A19_Filament_W_IMG0038_00102411-encrypted.ota";
|
||||
@@ -236,18 +234,17 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param task
|
||||
* @param e
|
||||
*
|
||||
*/
|
||||
@Download.onTaskFail
|
||||
void taskFail(DownloadTask task, Exception e) {
|
||||
if (task.getKey().equals(DOWNLOAD_URL)) {
|
||||
Toast.makeText(SingleTaskActivity.this, "下载失败", Toast.LENGTH_SHORT).show();
|
||||
setBtState(true);
|
||||
Aria.download(this)
|
||||
.load(DOWNLOAD_URL)
|
||||
.updateUrl("http://120.55.95.61:8811/ghcg/zg/武义总规纲要成果.zip")
|
||||
.start();
|
||||
//Aria.download(this)
|
||||
// .load(DOWNLOAD_URL)
|
||||
// .updateUrl("http://120.55.95.61:8811/ghcg/zg/武义总规纲要成果.zip")
|
||||
// .start();
|
||||
//DOWNLOAD_URL = "http://120.55.95.61:8811/ghcg/zg/武义总规纲要成果.zip";
|
||||
//ALog.d(TAG, ALog.getExceptionString(e));
|
||||
}
|
||||
@@ -262,9 +259,11 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
||||
//mCancel.setEnabled(false);
|
||||
setBtState(true);
|
||||
getBinding().setSpeed("");
|
||||
L.d(TAG, "path ==> " + task.getDownloadEntity().getDownloadPath());
|
||||
L.d(TAG, "md5Code ==> " + CommonUtil.getFileMD5(new File(task.getDownloadPath())));
|
||||
L.d(TAG, "data ==> " + Aria.download(this).getDownloadEntity(DOWNLOAD_URL));
|
||||
L.d(TAG, "path = " + task.getDownloadEntity().getDownloadPath());
|
||||
L.d(TAG, "md5Code = " + CommonUtil.getFileMD5(new File(task.getDownloadPath())));
|
||||
L.d(TAG, "data = " + Aria.download(this).getDownloadEntity(DOWNLOAD_URL));
|
||||
DownloadEntity temp = Aria.download(this).getDownloadEntity(DOWNLOAD_URL);
|
||||
L.d(TAG, "status = " + temp.getState() + ", isComplete = " + temp.isComplete());
|
||||
//Intent install = new Intent(Intent.ACTION_VIEW);
|
||||
//install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
//File apkFile = new File(task.getDownloadPath());
|
||||
@@ -286,8 +285,6 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
||||
return R.layout.activity_single;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void onClick(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.start:
|
||||
@@ -318,9 +315,9 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
||||
//params.put("filename", "CentOS-7-x86_64-Minimal-1804.iso");
|
||||
Aria.download(SingleTaskActivity.this)
|
||||
.load(DOWNLOAD_URL)
|
||||
//.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
|
||||
//.addHeader("Accept-Encoding", "gzip, deflate")
|
||||
//.addHeader("DNT", "1")
|
||||
//.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3")
|
||||
.addHeader("Accept-Encoding", "gzip, deflate")
|
||||
.addHeader("DNT", "1")
|
||||
//.addHeader("Cookie", "BAIDUID=648E5FF020CC69E8DD6F492D1068AAA9:FG=1; BIDUPSID=648E5FF020CC69E8DD6F492D1068AAA9; PSTM=1519099573; BD_UPN=12314753; locale=zh; BDSVRTM=0")
|
||||
.useServerFileName(true)
|
||||
.setFilePath(path, true)
|
||||
|
||||
@@ -48,16 +48,15 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
|
||||
setTitle("任务组");
|
||||
mChildList = getBinding().childList;
|
||||
mUrls = getModule(GroupModule.class).getUrls();
|
||||
DGTaskWrapper entity = Aria.download(this).getGroupTask(mUrls);
|
||||
if (entity != null && entity.getEntity() != null) {
|
||||
DownloadGroupEntity groupEntity = entity.getEntity();
|
||||
mChildList.addData(groupEntity.getSubEntities());
|
||||
getBinding().setFileSize(groupEntity.getConvertFileSize());
|
||||
if (groupEntity.getFileSize() == 0) {
|
||||
DownloadGroupEntity entity = Aria.download(this).getDownloadGroupEntity(mUrls);
|
||||
if (entity != null) {
|
||||
mChildList.addData(entity.getSubEntities());
|
||||
getBinding().setFileSize(entity.getConvertFileSize());
|
||||
if (entity.getFileSize() == 0) {
|
||||
getBinding().setProgress(0);
|
||||
} else {
|
||||
getBinding().setProgress(groupEntity.isComplete() ? 100
|
||||
: (int) (groupEntity.getCurrentProgress() * 100 / groupEntity.getFileSize()));
|
||||
getBinding().setProgress(entity.isComplete() ? 100
|
||||
: (int) (entity.getCurrentProgress() * 100 / entity.getFileSize()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +81,8 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
|
||||
switch (view.getId()) {
|
||||
case R.id.start:
|
||||
List<String> temp = new ArrayList<>();
|
||||
temp.add("https://d.pcs.baidu.com/file/130335545f3f4d9cc38afe709c19af5a?fid=1411168371-250528-1010657263806840&dstime=1531134714&rt=sh&sign=FDtAERVY-DCb740ccc5511e5e8fedcff06b081203-h8KgJ6gl4oY9UR6NqvwJsT4nVSM%3D&expires=8h&chkv=1&chkbd=0&chkpc=et&dp-logid=4401996296756616039&dp-callid=0&r=279987343");
|
||||
temp.add(
|
||||
"https://d.pcs.baidu.com/file/130335545f3f4d9cc38afe709c19af5a?fid=1411168371-250528-1010657263806840&dstime=1531134714&rt=sh&sign=FDtAERVY-DCb740ccc5511e5e8fedcff06b081203-h8KgJ6gl4oY9UR6NqvwJsT4nVSM%3D&expires=8h&chkv=1&chkbd=0&chkpc=et&dp-logid=4401996296756616039&dp-callid=0&r=279987343");
|
||||
Aria.download(this)
|
||||
.loadGroup(mUrls)
|
||||
.setDirPath(
|
||||
|
||||
@@ -36,23 +36,22 @@ import com.arialyy.simple.widget.SubStateLinearLayout;
|
||||
public class FTPDirDownloadActivity extends BaseActivity<ActivityDownloadGroupBinding> {
|
||||
private static final String dir = "ftp://9.9.9.50:21/upload/测试";
|
||||
|
||||
SubStateLinearLayout mChildList;
|
||||
SubStateLinearLayout mChildList;
|
||||
|
||||
@Override protected void init(Bundle savedInstanceState) {
|
||||
super.init(savedInstanceState);
|
||||
Aria.download(this).register();
|
||||
setTitle("FTP文件夹下载");
|
||||
mChildList = findViewById(R.id.child_list);
|
||||
DGTaskWrapper entity = Aria.download(this).getFtpDirTask(dir);
|
||||
if (entity != null && entity.getEntity() != null) {
|
||||
DownloadGroupEntity groupEntity = entity.getEntity();
|
||||
mChildList.addData(groupEntity.getSubEntities());
|
||||
getBinding().setFileSize(groupEntity.getConvertFileSize());
|
||||
if (groupEntity.getFileSize() == 0) {
|
||||
DownloadGroupEntity entity = Aria.download(this).getFtpDirEntity(dir);
|
||||
if (entity != null) {
|
||||
mChildList.addData(entity.getSubEntities());
|
||||
getBinding().setFileSize(entity.getConvertFileSize());
|
||||
if (entity.getFileSize() == 0) {
|
||||
getBinding().setProgress(0);
|
||||
} else {
|
||||
getBinding().setProgress(groupEntity.isComplete() ? 100
|
||||
: (int) (groupEntity.getCurrentProgress() * 100 / groupEntity.getFileSize()));
|
||||
getBinding().setProgress(entity.isComplete() ? 100
|
||||
: (int) (entity.getCurrentProgress() * 100 / entity.getFileSize()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,6 @@ public class AnyRunActivity extends BaseActivity<ActivityTestBinding> {
|
||||
mBar.setVisibility(View.GONE);
|
||||
module = new AnyRunnModule(this);
|
||||
urls = getResources().getStringArray(R.array.group_urls);
|
||||
DTaskWrapper entity = Aria.download(this).getDownloadTask(URL);
|
||||
Log.d(TAG, entity + "");
|
||||
}
|
||||
|
||||
public void onClick(View view) {
|
||||
|
||||
116
build.gradle
116
build.gradle
@@ -1,58 +1,58 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.11'
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
google()
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
dependencies {
|
||||
// classpath 'com.android.tools.build:gradle:2.3.3'
|
||||
classpath 'com.android.tools.build:gradle:3.3.2'
|
||||
classpath 'com.novoda:bintray-release:0.9'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}"
|
||||
// classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7'
|
||||
// classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
google()
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
|
||||
tasks.withType(Javadoc) {
|
||||
options {
|
||||
encoding "UTF-8"
|
||||
charSet 'UTF-8'
|
||||
links "http://docs.oracle.com/javase/7/docs/api"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
ext {
|
||||
userOrg = 'arialyy'
|
||||
groupId = 'com.arialyy.aria'
|
||||
publishVersion = '3.6.3'
|
||||
// publishVersion = '1.0.4' //FTP插件
|
||||
repoName='maven'
|
||||
desc = 'android 下载框架'
|
||||
website = 'https://github.com/AriaLyy/Aria'
|
||||
licences = ['Apache-2.0']
|
||||
|
||||
compileSdkVersion = 28
|
||||
supportLibVersion = "28.0.0"
|
||||
buildToolsVersion = "28.0.3"
|
||||
targetSdkVersion = 28
|
||||
minSdkVersion = 15
|
||||
}
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.11'
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
google()
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
dependencies {
|
||||
// classpath 'com.android.tools.build:gradle:2.3.3'
|
||||
classpath 'com.android.tools.build:gradle:3.3.2'
|
||||
classpath 'com.novoda:bintray-release:0.9'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}"
|
||||
// classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7'
|
||||
// classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
google()
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
|
||||
tasks.withType(Javadoc) {
|
||||
options {
|
||||
encoding "UTF-8"
|
||||
charSet 'UTF-8'
|
||||
links "http://docs.oracle.com/javase/7/docs/api"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
ext {
|
||||
userOrg = 'arialyy'
|
||||
groupId = 'com.arialyy.aria'
|
||||
publishVersion = '3.6.4_dev_1'
|
||||
// publishVersion = '1.0.4' //FTP插件
|
||||
repoName='maven'
|
||||
desc = 'android 下载框架'
|
||||
website = 'https://github.com/AriaLyy/Aria'
|
||||
licences = ['Apache-2.0']
|
||||
|
||||
compileSdkVersion = 28
|
||||
supportLibVersion = "28.0.0"
|
||||
buildToolsVersion = "28.0.3"
|
||||
targetSdkVersion = 28
|
||||
minSdkVersion = 15
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user