From 9212aabd95dfd69e1a0dee78b0d3fa2995a720db Mon Sep 17 00:00:00 2001 From: laoyuyu <511455842@qq.com> Date: Tue, 14 May 2019 21:13:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=86=E5=9D=97=E5=8F=AF?= =?UTF-8?q?=E8=83=BD=E5=87=BA=E7=8E=B0=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/arialyy/aria/core/AriaManager.java | 15 +- .../arialyy/aria/core/common/AbsFileer.java | 82 +-- .../aria/core/common/AbsThreadTask.java | 70 ++- .../aria/core/common/ThreadRecord.java | 3 +- .../core/common/http/HttpHeaderDelegate.java | 29 +- .../core/common/http/HttpTaskDelegate.java | 1 + .../aria/core/download/AbsGroupDelegate.java | 2 +- .../aria/core/download/BaseDListener.java | 2 +- .../core/download/DownloadGroupTarget.java | 3 +- .../aria/core/download/DownloadReceiver.java | 2 +- .../aria/core/download/DownloadTarget.java | 4 +- .../aria/core/download/HttpGroupDelegate.java | 43 +- .../core/download/downloader/Downloader.java | 9 + .../download/downloader/FtpThreadTask.java | 3 +- .../downloader/HttpFileInfoThread.java | 6 +- .../download/downloader/HttpThreadTask.java | 15 +- .../downloader/SimpleDownloadUtil.java | 1 - .../core/download/group/AbsGroupUtil.java | 48 +- .../download/group/DownloadGroupUtil.java | 34 +- .../download/group/FtpDirDownloadUtil.java | 2 +- .../aria/core/download/group/ISubQueue.java | 8 +- .../core/download/group/SimpleSubQueue.java | 12 + .../download/group/SubDownloadLoader.java | 4 +- .../aria/core/inf/AbsHttpFileLenAdapter.java | 10 - .../aria/core/manager/ThreadTaskManager.java | 4 +- .../aria/core/upload/BaseUListener.java | 2 +- .../core/upload/uploader/FtpThreadTask.java | 3 +- .../core/upload/uploader/HttpThreadTask.java | 2 +- .../java/com/arialyy/aria/orm/DBConfig.java | 2 +- .../java/com/arialyy/aria/orm/DbEntity.java | 579 +++++++++--------- .../com/arialyy/aria/orm/DelegateUpdate.java | 2 +- .../com/arialyy/aria/orm/DelegateWrapper.java | 4 +- .../java/com/arialyy/aria/orm/SqlHelper.java | 2 + .../com/arialyy/aria/util/CommonUtil.java | 84 ++- .../com/arialyy/aria/util/DbDataHelper.java | 7 +- DEV_LOG.md | 10 + .../download/group/DownloadGroupActivity.java | 27 +- 37 files changed, 597 insertions(+), 539 deletions(-) delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/inf/AbsHttpFileLenAdapter.java diff --git a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java index f920f836..95419595 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java @@ -276,19 +276,20 @@ import org.xml.sax.SAXException; /** * 删除任务记录 * - * @param type 需要删除的任务类型,1、表示单任务下载。2、表示任务组下载。3、单任务上传 - * @param key 下载为保存路径、任务组为任务组名、上传为上传文件路径 + * @param type 需要删除的任务类型,1、普通下载任务;2、组合任务;3、普通上传任务。 + * @param key type为1时,key为保存路径;type为2时,key为组合任务hash;type为3时,key为文件上传路径。 + * @param removeFile {@code true} 不仅删除任务数据库记录,还会删除已经删除完成的文件;{@code false}如果任务已经完成,只删除任务数据库记录。 */ - public void delRecord(int type, String key) { + public void delRecord(int type, String key, boolean removeFile) { switch (type) { - case 1: - DbEntity.deleteData(DownloadEntity.class, "url=? and isGroupChild='false'", key); + case 1: // 删除普通任务记录 + CommonUtil.delTaskRecord(key, 1, removeFile, true); break; case 2: - DbEntity.deleteData(DownloadGroupEntity.class, "groupHash=?", key); + CommonUtil.delGroupTaskRecord(key, removeFile); break; case 3: - DbEntity.deleteData(UploadEntity.class, "filePath=?", key); + CommonUtil.delTaskRecord(key, 2); break; } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java b/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java index dbf1f6f0..5960d330 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java @@ -212,6 +212,9 @@ public abstract class AbsFileer= 0) { mListener.onProgress(mConstance.CURRENT_LOCATION); @@ -251,9 +254,7 @@ public abstract class AbsFileer threadRect) { + ALog.i(TAG, String.format("分块【%s】错误,分块长度【%s】 > 线程区间长度【%s】,将重新开始该分块", + tr.threadId, blockFileLen, threadRect)); + temp.delete(); + tr.startLocation = tr.threadId * threadRect; + continue; + } + + long realLocation = + tr.threadId * normalRectLen + blockFileLen; //正常情况下,该线程的startLocation的位置 + /* + * 检查记录文件 + */ + if (blockFileLen == threadRect) { ALog.i(TAG, String.format("分块【%s】已完成,更新记录", temp.getPath())); - tr.startLocation = realLocation; + tr.startLocation = blockFileLen; tr.isComplete = true; mCompleteThreadNum++; - } else { - tr.isComplete = false; - if (realLocation == tr.startLocation) { - i++; - continue; - } - if (realLocation > tr.startLocation) { - ALog.i(TAG, String.format("修正分块【%s】的进度记录为:%s", temp.getPath(), realLocation)); - tr.startLocation = realLocation; - } else { - ALog.i(TAG, String.format("分块【%s】错误,将重新开始该分块", temp.getPath())); - temp.delete(); - tr.startLocation = i * blockLen; - } + } else if (tr.startLocation != realLocation) { // 处理记录小于分块文件长度的情况 + ALog.i(TAG, String.format("修正分块【%s】的进度记录为:%s", temp.getPath(), realLocation)); + tr.startLocation = realLocation; } } } - i++; } mTotalThreadNum = mRecord.threadRecords.size(); mTaskWrapper.setNewTask(false); @@ -517,13 +524,8 @@ public abstract class AbsFileer threads = new HashSet<>(); - // 如果是新任务,检查下历史记录,如果有遗留的记录,删除并删除分块文件 - if (mTaskWrapper.isNewTask()) { - CommonUtil.delTaskRecord(getFilePath(), 1, true); - } + //// 如果是新任务,检查下历史记录,如果有遗留的记录,删除并删除分块文件 + //if (mTaskWrapper.isNewTask()) { + // CommonUtil.delTaskRecord(getFilePath(), 1, true); + //} mRecord.fileLength = fileLength; if (mTaskWrapper.isNewTask() && !handleNewTask()) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java index b5da8a85..43a013ce 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java @@ -22,6 +22,7 @@ import com.arialyy.aria.core.config.BaseTaskConfig; import com.arialyy.aria.core.config.DGroupConfig; import com.arialyy.aria.core.config.DownloadConfig; import com.arialyy.aria.core.config.UploadConfig; +import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.inf.AbsNormalEntity; import com.arialyy.aria.core.inf.AbsTaskWrapper; import com.arialyy.aria.core.inf.IEventListener; @@ -31,6 +32,7 @@ import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.FileException; import com.arialyy.aria.exception.TaskException; import com.arialyy.aria.util.ALog; +import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.ErrorHelp; import com.arialyy.aria.util.FileUtil; import com.arialyy.aria.util.NetUtils; @@ -272,8 +274,10 @@ public abstract class AbsThreadTask tr.blockLen) { - ALog.i(TAG, String.format("分块【%s】错误,将重新下载该分块", blockFile.getPath())); - blockFile.delete(); - tr.startLocation = block * tr.threadId; - tr.isComplete = false; - getConfig().START_LOCATION = tr.startLocation; - } else if (blockFile.length() < tr.blockLen) { - tr.startLocation = block * tr.threadId + blockFile.length(); + long blockFileLen = temp.length(); // 磁盘中的分块文件长度 + long threadRect = tr.blockLen; // 当前线程的区间 + + if (!temp.exists()) { + ALog.i(TAG, String.format("分块文件【%s】不存在,该分块将重新开始", temp.getName())); tr.isComplete = false; getConfig().START_LOCATION = tr.startLocation; - getState().CURRENT_LOCATION = getBlockRealTotalSize(); - ALog.i(TAG, String.format("修正分块【%s】,开始位置:%s,当前进度:%s", blockFile.getPath(), tr.startLocation, - getState().CURRENT_LOCATION)); } else { - getState().COMPLETE_THREAD_NUM++; - tr.isComplete = true; + /* + * 检查磁盘中的分块文件 + */ + if (blockFileLen > threadRect) { + ALog.i(TAG, String.format("分块【%s】错误,将重新下载该分块", temp.getName())); + temp.delete(); + tr.startLocation = normalRectLen * tr.threadId; + tr.isComplete = false; + getConfig().START_LOCATION = tr.startLocation; + } else if (blockFileLen < tr.blockLen) { + tr.startLocation = normalRectLen * tr.threadId + blockFileLen; + tr.isComplete = false; + getConfig().START_LOCATION = tr.startLocation; + getState().CURRENT_LOCATION = getBlockRealTotalSize(); + ALog.i(TAG, + String.format("修正分块【%s】,开始位置:%s,当前进度:%s", temp.getName(), tr.startLocation, + getState().CURRENT_LOCATION)); + } else { + ALog.i(TAG, String.format("分块【%s】已完成,更新记录", temp.getName())); + getState().COMPLETE_THREAD_NUM++; + tr.isComplete = true; + } } tr.update(); } else { @@ -454,6 +470,16 @@ public abstract class AbsThreadTask return mTarget; } - public TARGET setFileLenAdapter(AbsHttpFileLenAdapter adapter) { + public TARGET setFileLenAdapter(IHttpFileLenAdapter adapter) { if (adapter == null) { throw new IllegalArgumentException("adapter为空"); } - //try { - // adapter.clone(); - mTarget.getTaskWrapper().asHttp().setFileLenAdapter((IHttpFileLenAdapter) adapter); - //} catch (CloneNotSupportedException e) { - // e.printStackTrace(); - //} - //// 以下代码有问题,匿名内部类不能序列化 - //String objPath = String.format("%s/obj_temp/%s", AriaManager.APP.getFilesDir().getPath(), - // adapter.hashCode()); - //CommonUtil.writeObjToFile(objPath, adapter); - //IHttpFileLenAdapter newAdapter = (IHttpFileLenAdapter) CommonUtil.readObjFromFile(objPath); - //File temp = new File(objPath); - //if (temp.exists()) { - // temp.delete(); - //} - //mTarget.getTaskWrapper().asHttp().setFileLenAdapter(newAdapter); - + mTarget.getTaskWrapper().asHttp().setFileLenAdapter(adapter); return mTarget; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/common/http/HttpTaskDelegate.java b/Aria/src/main/java/com/arialyy/aria/core/common/http/HttpTaskDelegate.java index f5ee86e7..a1f7cf8f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/common/http/HttpTaskDelegate.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/http/HttpTaskDelegate.java @@ -19,6 +19,7 @@ package com.arialyy.aria.core.common.http; import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.inf.IHttpFileLenAdapter; import com.arialyy.aria.core.inf.ITargetHeadDelegate; +import java.lang.ref.WeakReference; import java.net.CookieManager; import java.net.Proxy; import java.util.HashMap; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/AbsGroupDelegate.java b/Aria/src/main/java/com/arialyy/aria/core/download/AbsGroupDelegate.java index 03a8aae5..152aa5a9 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/AbsGroupDelegate.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/AbsGroupDelegate.java @@ -76,6 +76,7 @@ abstract class AbsGroupDelegate implements IGroupTar * @param newDirPath 新的文件夹路径 */ void reChangeDirPath(String newDirPath) { + ALog.d(TAG, String.format("修改新路径为:%s", newDirPath)); List subTasks = mWrapper.getSubTaskWrapper(); if (subTasks != null && !subTasks.isEmpty()) { List des = new ArrayList<>(); @@ -90,7 +91,6 @@ abstract class AbsGroupDelegate implements IGroupTar de.setDownloadPath(newPath); des.add(de); } - AbsEntity.saveAll(des); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java b/Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java index fd4af866..b022245b 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java @@ -55,7 +55,7 @@ public class BaseDListener extends BaseListener implem /** * 如果你需要使用header中特定的key来设置文件长度,或有定制文件长度的需要,那么你可以通过该方法自行处理文件长度 */ - public DownloadGroupTarget setFileLenAdapter(AbsHttpFileLenAdapter adapter) { + public DownloadGroupTarget setFileLenAdapter(IHttpFileLenAdapter adapter) { return mHeaderDelegate.setFileLenAdapter(adapter); } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java index aa04eff8..8f5d377d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java @@ -187,7 +187,7 @@ public class DownloadReceiver extends AbsReceiver { * 取消注册,如果是Activity或fragment,Aria会界面销毁时自动调用该方法,不需要你手动调用。 * 注意事项: * 1、如果在activity中一定要调用该方法,那么请在{@code onDestroy()}中调用 - * 2、不要在activity的{@code onStop()}中调用改方法 + * 2、不要在activity的{@code onPreStop()}中调用改方法 * 3、如果是Dialog或popupwindow,需要你在撤销界面时调用该方法 * 4、如果你是在Module(非android组件类)中注册了Aria,那么你也需要在Module类中调用该方法,而不是在组件类中 * 调用销毁,详情见 diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java index ff654c20..c101c7c4 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java @@ -20,7 +20,6 @@ import android.support.annotation.NonNull; import com.arialyy.aria.core.common.http.GetDelegate; import com.arialyy.aria.core.common.http.HttpHeaderDelegate; import com.arialyy.aria.core.common.http.PostDelegate; -import com.arialyy.aria.core.inf.AbsHttpFileLenAdapter; import com.arialyy.aria.core.inf.IHttpFileLenAdapter; import com.arialyy.aria.core.inf.IHttpHeaderDelegate; import java.net.Proxy; @@ -103,9 +102,8 @@ public class DownloadTarget extends AbsDTarget /** * 如果你需要使用header中特定的key来设置文件长度,或有定制文件长度的需要,那么你可以通过该方法自行处理文件长度 */ - public DownloadTarget setFileLenAdapter(AbsHttpFileLenAdapter adapter) { + public DownloadTarget setFileLenAdapter(IHttpFileLenAdapter adapter) { return mHeaderDelegate.setFileLenAdapter(adapter); - //return this; } /** diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/HttpGroupDelegate.java b/Aria/src/main/java/com/arialyy/aria/core/download/HttpGroupDelegate.java index 3cfcc6e9..966f4543 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/HttpGroupDelegate.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/HttpGroupDelegate.java @@ -125,8 +125,6 @@ class HttpGroupDelegate extends AbsGroupDelegate { } } - saveEntity(); - if (isNeedModifyPath()) { reChangeDirPath(getDirPathTemp()); } @@ -134,10 +132,11 @@ class HttpGroupDelegate extends AbsGroupDelegate { if (!mSubNameTemp.isEmpty()) { updateSingleSubFileName(); } + saveEntity(); return true; } - private void saveEntity(){ + private void saveEntity() { getEntity().save(); DbEntity.saveAll(getEntity().getSubEntities()); } @@ -148,10 +147,23 @@ class HttpGroupDelegate extends AbsGroupDelegate { private void updateSingleSubFileName() { List entities = getTaskWrapper().getSubTaskWrapper(); int i = 0; - for (DTaskWrapper entity : entities) { + for (DTaskWrapper taskWrapper : entities) { if (i < mSubNameTemp.size()) { String newName = mSubNameTemp.get(i); - updateSingleSubFileName(entity, newName); + DownloadEntity entity = taskWrapper.getEntity(); + if (!newName.equals(entity.getFileName())) { + String oldPath = getEntity().getDirPath() + "/" + entity.getFileName(); + String newPath = getEntity().getDirPath() + "/" + newName; + if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=? or isComplete='true'", + newPath)) { + ALog.w(TAG, String.format("更新文件名失败,路径【%s】已存在或文件已下载", newPath)); + return; + } + + CommonUtil.modifyTaskRecord(oldPath, newPath); + entity.setDownloadPath(newPath); + entity.setFileName(newName); + } } i++; } @@ -203,27 +215,6 @@ class HttpGroupDelegate extends AbsGroupDelegate { return true; } - /** - * 更新单个子任务文件名 - */ - private void updateSingleSubFileName(DTaskWrapper taskEntity, String newName) { - DownloadEntity entity = taskEntity.getEntity(); - if (!newName.equals(entity.getFileName())) { - String oldPath = getEntity().getDirPath() + "/" + entity.getFileName(); - String newPath = getEntity().getDirPath() + "/" + newName; - if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=? or isComplete='true'", - newPath)) { - ALog.w(TAG, String.format("更新文件名失败,路径【%s】已存在或文件已下载", newPath)); - return; - } - - CommonUtil.modifyTaskRecord(oldPath, newPath); - entity.setDownloadPath(newPath); - entity.setFileName(newName); - entity.update(); - } - } - /** * 如果用户设置了子任务文件名,检查子任务文件名 * diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java index ce76f484..e26424c5 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java @@ -26,6 +26,7 @@ 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 com.arialyy.aria.util.CommonUtil; import java.io.File; import java.io.IOException; @@ -59,6 +60,14 @@ public class Downloader extends AbsFileer { mTempFile.delete(); } //CommonUtil.createFile(mTempFile.getPath()); + } else { + for (int i = 0; i < mTotalThreadNum; i++) { + File blockFile = new File(String.format(AbsFileer.SUB_PATH, mTempFile.getPath(), i)); + if (blockFile.exists()) { + ALog.d(TAG, String.format("分块【%s】已经存在,将删除该分块", i)); + blockFile.delete(); + } + } } BufferedRandomAccessFile file = null; try { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java index 3bc29121..d58abf6f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java @@ -147,8 +147,7 @@ class FtpThreadTask extends AbsFtpThreadTask { return; } } - getState().TASK_RECORD.deleteData(); - mListener.onComplete(); + sendCompleteMsg(); } if (getState().isFail()) { mListener.onFail(false, diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java index 07cb4bc6..012395e3 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java @@ -89,6 +89,8 @@ public class HttpFileInfoThread implements Runnable { if (conn != null) { conn.disconnect(); } + // 销毁文件长度适配器 + mTaskWrapper.asHttp().setFileLenAdapter(null); } } @@ -113,6 +115,8 @@ public class HttpFileInfoThread implements Runnable { IHttpFileLenAdapter lenAdapter = mTaskWrapper.asHttp().getFileLenAdapter(); if (lenAdapter == null) { lenAdapter = new FileLenAdapter(); + } else { + ALog.d(TAG, "使用自定义adapter"); } long len = lenAdapter.handleFileLen(conn.getHeaderFields()); @@ -214,8 +218,6 @@ public class HttpFileInfoThread implements Runnable { onFileInfoCallback.onComplete(mEntity.getUrl(), info); } mEntity.update(); - // 销毁文件长度适配器 - mTaskWrapper.asHttp().setFileLenAdapter(null); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java index f2ef96bc..bfca0922 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java @@ -176,7 +176,8 @@ final class HttpThreadTask extends AbsThreadTask { handleComplete(); } catch (IOException e) { fail(mChildCurrentLocation, new AriaIOException(TAG, - String.format("文件下载失败,savePath: %s, url: %s", getEntity().getDownloadPath(), getConfig().URL), + String.format("文件下载失败,savePath: %s, url: %s", getEntity().getDownloadPath(), + getConfig().URL), e)); } finally { if (fos != null) { @@ -228,7 +229,8 @@ final class HttpThreadTask extends AbsThreadTask { handleComplete(); } catch (IOException e) { fail(mChildCurrentLocation, new AriaIOException(TAG, - String.format("文件下载失败,savePath: %s, url: %s", getEntity().getDownloadPath(), getConfig().URL), + String.format("文件下载失败,savePath: %s, url: %s", getEntity().getDownloadPath(), + getConfig().URL), e)); } finally { try { @@ -278,8 +280,7 @@ final class HttpThreadTask extends AbsThreadTask { return; } if (getTaskWrapper().asHttp().isChunked()) { - ALog.i(TAG, "任务下载完成"); - mListener.onComplete(); + sendCompleteMsg(); return; } @@ -300,8 +301,7 @@ final class HttpThreadTask extends AbsThreadTask { return; } } - getState().TASK_RECORD.deleteData(); - mListener.onComplete(); + sendCompleteMsg(); } if (getState().isFail()) { mListener.onFail(false, @@ -310,8 +310,7 @@ final class HttpThreadTask extends AbsThreadTask { getEntity().getDownloadPath(), getEntity().getUrl()))); } } else { - ALog.i(TAG, "任务下载完成"); - mListener.onComplete(); + sendCompleteMsg(); } } else { getState().FAIL_NUM++; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java index e04f9f3b..eb5e05f2 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java @@ -23,7 +23,6 @@ import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsTaskWrapper; import com.arialyy.aria.core.inf.IDownloadListener; -import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.exception.BaseException; /** diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/group/AbsGroupUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/group/AbsGroupUtil.java index cf5af42b..f960c882 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/group/AbsGroupUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/group/AbsGroupUtil.java @@ -152,7 +152,7 @@ public abstract class AbsGroupUtil implements IUtil, Runnable { private SubDownloadLoader getDownloader(String url) { SubDownloadLoader d = mExeLoader.get(url); if (d == null) { - return createSubLoader(mCache.get(url)); + return createAndStartSubLoader(mCache.get(url)); } return d; } @@ -172,38 +172,34 @@ public abstract class AbsGroupUtil implements IUtil, Runnable { @Override public void cancel() { isCancel = true; closeTimer(); - onCancel(); - Set keys = mExeLoader.keySet(); - mSubQueue.clear(); + onPreCancel(); - for (String key : keys) { - SubDownloadLoader loader = mExeLoader.get(key); - if (loader != null && loader.isRunning()) { - loader.cancel(); - } - } + mSubQueue.removeAllTask(); mListener.onCancel(); } - public void onCancel() { + /** + * onCancel前的操作 + */ + public void onPreCancel() { } @Override public void stop() { isStop = true; closeTimer(); - if (onStop()) { + if (onPreStop()) { return; } mSubQueue.stopAllTask(); } /** - * 子类的钩子 + * onStop前的操作 * * @return 返回{@code true},直接回调{@link IDownloadGroupListener#onStop(long)} */ - protected boolean onStop() { + protected boolean onPreStop() { return false; } @@ -286,8 +282,8 @@ public abstract class AbsGroupUtil implements IUtil, Runnable { /** * 创建并启动子任务下载器 */ - SubDownloadLoader createSubLoader(DTaskWrapper taskWrapper) { - return createSubLoader(taskWrapper, true); + SubDownloadLoader createAndStartSubLoader(DTaskWrapper taskWrapper) { + return createAndStartSubLoader(taskWrapper, true); } /** @@ -295,28 +291,10 @@ public abstract class AbsGroupUtil implements IUtil, Runnable { * * @param needGetFileInfo {@code true} 需要获取文件信息。{@code false} 不需要获取文件信息 */ - SubDownloadLoader createSubLoader(DTaskWrapper taskWrapper, boolean needGetFileInfo) { - if (getTaskType() == HTTP_GROUP) { - cloneHeader(taskWrapper); - } + SubDownloadLoader createAndStartSubLoader(DTaskWrapper taskWrapper, boolean needGetFileInfo) { SubDownloadLoader loader = new SubDownloadLoader(mScheduler, taskWrapper, needGetFileInfo); mExeLoader.put(loader.getKey(), loader); mSubQueue.startTask(loader); return loader; } - - /** - * 子任务使用父包裹器的属性 - */ - private void cloneHeader(DTaskWrapper taskWrapper) { - HttpTaskDelegate groupDelegate = mGTWrapper.asHttp(); - HttpTaskDelegate subDelegate = taskWrapper.asHttp(); - - // 设置属性 - subDelegate.setFileLenAdapter(groupDelegate.getFileLenAdapter()); - subDelegate.setRequestEnum(groupDelegate.getRequestEnum()); - subDelegate.setHeaders(groupDelegate.getHeaders()); - subDelegate.setProxy(groupDelegate.getProxy()); - subDelegate.setParams(groupDelegate.getParams()); - } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/group/DownloadGroupUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/group/DownloadGroupUtil.java index ba11443f..78c9a6b2 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/group/DownloadGroupUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/group/DownloadGroupUtil.java @@ -18,6 +18,7 @@ package com.arialyy.aria.core.download.group; import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.OnFileInfoCallback; +import com.arialyy.aria.core.common.http.HttpTaskDelegate; import com.arialyy.aria.core.download.DGTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DownloadEntity; @@ -49,11 +50,11 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil { return HTTP_GROUP; } - @Override public void onCancel() { - super.onCancel(); + @Override public void onPreCancel() { + super.onPreCancel(); } - @Override protected boolean onStop() { + @Override protected boolean onPreStop() { // 如果是isUnknownSize()标志,并且获取大小没有完成,则直接回调onStop if (mPool != null && !getLenComplete) { ALog.d(TAG, "获取长度未完成的情况下,停止组合任务"); @@ -83,7 +84,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil { } else { for (DTaskWrapper wrapper : mGTWrapper.getSubTaskWrapper()) { if (wrapper.getState() != IEntity.STATE_COMPLETE) { - createSubLoader(wrapper); + createAndStartSubLoader(wrapper); } } } @@ -99,10 +100,16 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil { int failCount; @Override public void run() { + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } for (DTaskWrapper dTaskWrapper : mGTWrapper.getSubTaskWrapper()) { + cloneHeader(dTaskWrapper); mPool.submit(new HttpFileInfoThread(dTaskWrapper, new OnFileInfoCallback() { @Override public void onComplete(String url, CompleteInfo info) { - createSubLoader((DTaskWrapper) info.wrapper, false); + createAndStartSubLoader((DTaskWrapper) info.wrapper, false); count++; checkGetSizeComplete(count, failCount); } @@ -133,15 +140,30 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil { mGTWrapper.getEntity().setConvertFileSize(CommonUtil.formatFileSize(size)); mGTWrapper.getEntity().setFileSize(size); mGTWrapper.getEntity().update(); - mGTWrapper.asHttp().setFileLenAdapter(null); getLenComplete = true; ALog.d(TAG, String.format("获取组合任务长度完成,len:%s", size)); } else if (failCount == mGTWrapper.getSubTaskWrapper().size()) { mListener.onFail(true, new AriaIOException(TAG, "获取子任务长度失败")); } + mGTWrapper.asHttp().setFileLenAdapter(null); synchronized (LOCK) { LOCK.notify(); } } + + /** + * 子任务使用父包裹器的属性 + */ + private void cloneHeader(DTaskWrapper taskWrapper) { + HttpTaskDelegate groupDelegate = mGTWrapper.asHttp(); + HttpTaskDelegate subDelegate = taskWrapper.asHttp(); + + // 设置属性 + subDelegate.setFileLenAdapter(groupDelegate.getFileLenAdapter()); + subDelegate.setRequestEnum(groupDelegate.getRequestEnum()); + subDelegate.setHeaders(groupDelegate.getHeaders()); + subDelegate.setProxy(groupDelegate.getProxy()); + subDelegate.setParams(groupDelegate.getParams()); + } } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/group/FtpDirDownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/group/FtpDirDownloadUtil.java index bb800a35..76e057b6 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/group/FtpDirDownloadUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/group/FtpDirDownloadUtil.java @@ -60,7 +60,7 @@ public class FtpDirDownloadUtil extends AbsGroupUtil { private void startDownload() { for (DTaskWrapper wrapper : mGTWrapper.getSubTaskWrapper()) { if (wrapper.getState() != IEntity.STATE_COMPLETE) { - createSubLoader(wrapper); + createAndStartSubLoader(wrapper); } } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/group/ISubQueue.java b/Aria/src/main/java/com/arialyy/aria/core/download/group/ISubQueue.java index e4f234e3..fab093dd 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/group/ISubQueue.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/group/ISubQueue.java @@ -63,10 +63,16 @@ interface ISubQueue { void removeTaskFromExecQ(Fileer fileer); /** - * 删除任务 + * 删除任务,如果缓存队列中有等待中的任务,则启动等待中的任务 */ void removeTask(Fileer fileer); + /** + * 停止全部任务,停止所有正在执行的任务,并清空所有等待中的端服务 + */ + void removeAllTask(); + + /** * 获取下一个任务 */ diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/group/SimpleSubQueue.java b/Aria/src/main/java/com/arialyy/aria/core/download/group/SimpleSubQueue.java index 5c24e9a9..493e408d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/group/SimpleSubQueue.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/group/SimpleSubQueue.java @@ -168,6 +168,18 @@ class SimpleSubQueue implements ISubQueue { mCache.remove(fileer.getKey()); } + @Override public void removeAllTask() { + ALog.d(TAG, "删除组合任务"); + Set keys = mExec.keySet(); + for (String key : keys) { + SubDownloadLoader loader = mExec.get(key); + if (loader != null) { + ALog.d(TAG, String.format("停止子任务:%s", loader.getEntity().getFileName())); + loader.cancel(); + } + } + } + @Override public SubDownloadLoader getNextTask() { Iterator keys = mCache.keySet().iterator(); if (keys.hasNext()) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/group/SubDownloadLoader.java b/Aria/src/main/java/com/arialyy/aria/core/download/group/SubDownloadLoader.java index 12254b48..0ac17ef0 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/group/SubDownloadLoader.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/group/SubDownloadLoader.java @@ -87,8 +87,10 @@ class SubDownloadLoader implements IUtil { } @Override public void cancel() { - if (mDownloader != null) { + if (mDownloader != null && isRunning()) { mDownloader.cancel(); + } else { + mSchedulers.obtainMessage(ISchedulers.CANCEL, this).sendToTarget(); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsHttpFileLenAdapter.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsHttpFileLenAdapter.java deleted file mode 100644 index 035cd5a3..00000000 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsHttpFileLenAdapter.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.arialyy.aria.core.inf; - -public abstract class AbsHttpFileLenAdapter implements IHttpFileLenAdapter { - - @Override public Object clone() throws CloneNotSupportedException { - //AbsHttpFileLenAdapter newAdapter = super.clone(); - - return super.clone(); - } -} diff --git a/Aria/src/main/java/com/arialyy/aria/core/manager/ThreadTaskManager.java b/Aria/src/main/java/com/arialyy/aria/core/manager/ThreadTaskManager.java index cc9d401d..30b9cb9f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/manager/ThreadTaskManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/manager/ThreadTaskManager.java @@ -29,7 +29,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; /** - * 线程管理器 + * 线程任务管理器 */ public class ThreadTaskManager { private static volatile ThreadTaskManager INSTANCE = null; @@ -80,7 +80,7 @@ public class ThreadTaskManager { * * @param key 任务对应的key{@link AbsTaskWrapper#getKey()} */ - public synchronized void stopTaskThread(String key) { + public synchronized void removeTaskThread(String key) { if (mExePool.isShutdown()) { ALog.e(TAG, "线程池已经关闭"); return; diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java index 6564baec..575aa3cc 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java @@ -36,7 +36,7 @@ class BaseUListener extends BaseListener mTaskWrapper.setState(state); mEntity.setState(state); if (state == IEntity.STATE_CANCEL) { - CommonUtil.delTaskRecord(mEntity.getFilePath(), 2, mTaskWrapper.isRemoveFile()); + CommonUtil.delTaskRecord(mEntity.getFilePath(), 2, mTaskWrapper.isRemoveFile(), true); } else if (state == IEntity.STATE_STOP) { mEntity.setStopTime(System.currentTimeMillis()); } else if (state == IEntity.STATE_COMPLETE) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java index 6b23d940..b1e86c53 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java @@ -96,8 +96,7 @@ class FtpThreadTask extends AbsFtpThreadTask { writeConfig(true, getConfig().END_LOCATION); getState().COMPLETE_THREAD_NUM++; if (getState().isComplete()) { - getState().TASK_RECORD.deleteData(); - mListener.onComplete(); + sendCompleteMsg(); } if (getState().isFail()) { mListener.onFail(false, new TaskException(TAG, diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java index 3fb76e55..48f2712d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java @@ -101,7 +101,7 @@ class HttpThreadTask extends AbsThreadTask { } uploadFile(writer, taskDelegate.getAttachment(), uploadFile); getEntity().setResponseStr(finish(writer)); - mListener.onComplete(); + sendCompleteMsg(); } catch (Exception e) { e.printStackTrace(); fail(new TaskException(TAG, diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java b/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java index d742aaf5..b83ca020 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java @@ -36,7 +36,7 @@ class DBConfig { static boolean DEBUG = false; static Map mapping = new HashMap<>(); static String DB_NAME; - static int VERSION = 45; + static int VERSION = 46; /** * 是否将数据库保存在Sd卡,{@code true} 是 diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java b/Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java index 63f8e975..07e374d5 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java @@ -1,290 +1,291 @@ -/* - * 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 java.util.ArrayList; -import java.util.List; - -/** - * Created by lyy on 2015/11/2. 所有数据库实体父类 - */ -public abstract class DbEntity { - private static final Object LOCK = new Object(); - protected long rowID = -1; - - protected DbEntity() { - - } - - /** - * 查询关联数据 - * - * DbEntity.findRelationData(DGEntityWrapper.class, "downloadUrl=?", downloadUrl); - * - * - * @param expression 查询条件 - */ - public static List findRelationData(Class clazz, - String... expression) { - return DelegateWrapper.getInstance().findRelationData(clazz, expression); - } - - /** - * 分页查询关联数据 - * - * - * DbEntity.findRelationData(DGEntityWrapper.class, 0, 10, "downloadUrl=?", downloadUrl); - * - * - * @param expression 查询条件 - * @param page 需要查询的页数,从1开始,如果page小于1 或 num 小于1,返回null - * @param num 每页返回的数量 - * @return 没有数据返回null,如果页数大于总页数,返回null - */ - public static List findRelationData(Class clazz, int page, int num, - String... expression) { - if (page < 1 || num < 1) { - return null; - } - return DelegateWrapper.getInstance().findRelationData(clazz, page, num, expression); - } - - /** - * 检查某个字段的值是否存在 - * - * @param expression 字段和值"downloadPath=?" - * @return {@code true}该字段的对应的value已存在 - */ - public static boolean checkDataExist(Class clazz, String... expression) { - return DelegateWrapper.getInstance().checkDataExist(clazz, expression); - } - - /** - * 清空表数据 - */ - public static void clean(Class clazz) { - DelegateWrapper.getInstance().clean(clazz); - } - - /** - * 直接执行sql语句 - */ - public static void exeSql(String sql) { - DelegateWrapper.getInstance().exeSql(sql); - } - - /** - * 查询所有数据 - * - * @return 没有数据返回null - */ - public static List findAllData(Class clazz) { - return DelegateWrapper.getInstance().findAllData(clazz); - } - - /** - * 查询第一条数据 - */ - public static T findFirst(Class clazz) { - List list = findAllData(clazz); - return (list == null || list.size() == 0) ? null : list.get(0); - } - - /** - * 查询一组数据 - * - * DbEntity.findFirst(DownloadEntity.class, "downloadUrl=?", downloadUrl); - * - * - * @return 没有数据返回null - */ - public static List findDatas(Class clazz, String... expression) { - return DelegateWrapper.getInstance().findData(clazz, expression); - } - - /** - * 分页查询数据 - * - * DbEntity.findFirst(DownloadEntity.class, 0, 10, "downloadUrl=?", downloadUrl); - * - * - * @param page 需要查询的页数,从1开始,如果page小于1 或 num 小于1,返回null - * @param num 每页返回的数量 - * @return 没有数据返回null,如果页数大于总页数,返回null - */ - public static List findDatas(Class clazz, int page, int num, - String... expression) { - if (page < 1 || num < 1) { - return null; - } - return DelegateWrapper.getInstance().findData(clazz, page, num, expression); - } - - /** - * 模糊查询一组数据 - * - * DbEntity.findDataByFuzzy(DownloadEntity.class, "downloadUrl like http://"); - * - * - * @return 没有数据返回null - */ - public static List findDataByFuzzy(Class clazz, String conditions) { - return DelegateWrapper.getInstance().findDataByFuzzy(clazz, conditions); - } - - /** - * 模糊查询一组数据 - * - * DbEntity.findDataByFuzzy(DownloadEntity.class, 0, 10, "downloadUrl like http://"); - * - * - * @param page 需要查询的页数,从1开始,如果page小于1 或 num 小于1,返回null - * @param num 每页返回的数量 - * @return 没有数据返回null,如果页数大于总页数,返回null - */ - public static List findDataByFuzzy(Class clazz, int page, int num, - String conditions) { - return DelegateWrapper.getInstance().findDataByFuzzy(clazz, page, num, conditions); - } - - /** - * 查询一行数据 - * - * DbEntity.findFirst(DownloadEntity.class, "downloadUrl=?", downloadUrl); - * - * - * @return 没有数据返回null - */ - public static T findFirst(Class clazz, String... expression) { - DelegateWrapper util = DelegateWrapper.getInstance(); - List datas = util.findData(clazz, expression); - return datas == null ? null : datas.size() > 0 ? datas.get(0) : null; - } - - /** - * 插入多条数据 - */ - public static void insertManyData(List entities) { - checkListData(entities); - DelegateWrapper.getInstance().insertManyData(entities); - } - - /** - * 修改多条数据 - */ - public static void updateManyData(List entities) { - checkListData(entities); - DelegateWrapper.getInstance().updateManyData(entities); - } - - /** - * 保存多条数据,通过rowID来判断记录存在以否,如果数据库已有记录,则更新该记录;如果数据库中没有记录,则保存该记录 - */ - public static void saveAll(List entities) { - checkListData(entities); - List insertD = new ArrayList<>(); - List updateD = new ArrayList<>(); - DelegateWrapper wrapper = DelegateWrapper.getInstance(); - for (DbEntity entity : entities) { - if (entity.rowID == -1) { - insertD.add(entity); - continue; - } - if (wrapper.isExist(entity.getClass(), entity.rowID)) { - updateD.add(entity); - } else { - insertD.add(entity); - } - } - if (!insertD.isEmpty()) { - wrapper.insertManyData(insertD); - } else { - wrapper.updateManyData(updateD); - } - } - - /** - * 检查批量操作的列表数据,如果数据为空,抛出{@link NullPointerException} - */ - private static void checkListData(List entities) { - if (entities == null || entities.isEmpty()) { - throw new NullPointerException("列表数据为空"); - } - } - - /** - * 删除当前数据 - */ - public void deleteData() { - deleteData(getClass(), "rowid=?", rowID + ""); - } - - /** - * 根据条件删除数据 - * - * DbEntity.deleteData(DownloadEntity.class, "downloadUrl=?", downloadUrl); - * - */ - public static void deleteData(Class clazz, String... expression) { - DelegateWrapper util = DelegateWrapper.getInstance(); - util.delData(clazz, expression); - } - - /** - * 修改数据 - */ - public void update() { - DelegateWrapper.getInstance().updateData(this); - } - - /** - * 保存自身,如果表中已经有数据,则更新数据,否则插入数据 只有 target中checkEntity成功后才能保存,创建实体部分也不允许保存 - */ - public void save() { - synchronized (LOCK) { - if (thisIsExist()) { - update(); - } else { - insert(); - } - } - } - - /** - * 查找数据在表中是否存在 - */ - private boolean thisIsExist() { - DelegateWrapper util = DelegateWrapper.getInstance(); - return rowID != -1 && util.isExist(getClass(), rowID); - } - - /** - * 表是否存在 - * - * @return {@code true} 存在 - */ - public static boolean tableExists(Class clazz) { - return DelegateWrapper.getInstance().tableExists(clazz); - } - - /** - * 插入数据,只有 target中checkEntity成功后才能插入,创建实体部分也不允许操作 - */ - public void insert() { - DelegateWrapper.getInstance().insertData(this); - } +/* + * 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 java.util.ArrayList; +import java.util.List; + +/** + * Created by lyy on 2015/11/2. 所有数据库实体父类 + */ +public abstract class DbEntity { + private static final Object LOCK = new Object(); + protected long rowID = -1; + + protected DbEntity() { + + } + + /** + * 查询关联数据 + * + * DbEntity.findRelationData(DGEntityWrapper.class, "downloadUrl=?", downloadUrl); + * + * + * @param expression 查询条件 + */ + public static List findRelationData(Class clazz, + String... expression) { + return DelegateWrapper.getInstance().findRelationData(clazz, expression); + } + + /** + * 分页查询关联数据 + * + * + * DbEntity.findRelationData(DGEntityWrapper.class, 0, 10, "downloadUrl=?", downloadUrl); + * + * + * @param expression 查询条件 + * @param page 需要查询的页数,从1开始,如果page小于1 或 num 小于1,返回null + * @param num 每页返回的数量 + * @return 没有数据返回null,如果页数大于总页数,返回null + */ + public static List findRelationData(Class clazz, int page, int num, + String... expression) { + if (page < 1 || num < 1) { + return null; + } + return DelegateWrapper.getInstance().findRelationData(clazz, page, num, expression); + } + + /** + * 检查某个字段的值是否存在 + * + * @param expression 字段和值"downloadPath=?" + * @return {@code true}该字段的对应的value已存在 + */ + public static boolean checkDataExist(Class clazz, String... expression) { + return DelegateWrapper.getInstance().checkDataExist(clazz, expression); + } + + /** + * 清空表数据 + */ + public static void clean(Class clazz) { + DelegateWrapper.getInstance().clean(clazz); + } + + /** + * 直接执行sql语句 + */ + public static void exeSql(String sql) { + DelegateWrapper.getInstance().exeSql(sql); + } + + /** + * 查询所有数据 + * + * @return 没有数据返回null + */ + public static List findAllData(Class clazz) { + return DelegateWrapper.getInstance().findAllData(clazz); + } + + /** + * 查询第一条数据 + */ + public static T findFirst(Class clazz) { + List list = findAllData(clazz); + return (list == null || list.size() == 0) ? null : list.get(0); + } + + /** + * 查询一组数据 + * + * DbEntity.findFirst(DownloadEntity.class, "downloadUrl=?", downloadUrl); + * + * + * @return 没有数据返回null + */ + public static List findDatas(Class clazz, String... expression) { + return DelegateWrapper.getInstance().findData(clazz, expression); + } + + /** + * 分页查询数据 + * + * DbEntity.findFirst(DownloadEntity.class, 0, 10, "downloadUrl=?", downloadUrl); + * + * + * @param page 需要查询的页数,从1开始,如果page小于1 或 num 小于1,返回null + * @param num 每页返回的数量 + * @return 没有数据返回null,如果页数大于总页数,返回null + */ + public static List findDatas(Class clazz, int page, int num, + String... expression) { + if (page < 1 || num < 1) { + return null; + } + return DelegateWrapper.getInstance().findData(clazz, page, num, expression); + } + + /** + * 模糊查询一组数据 + * + * DbEntity.findDataByFuzzy(DownloadEntity.class, "downloadUrl like http://"); + * + * + * @return 没有数据返回null + */ + public static List findDataByFuzzy(Class clazz, String conditions) { + return DelegateWrapper.getInstance().findDataByFuzzy(clazz, conditions); + } + + /** + * 模糊查询一组数据 + * + * DbEntity.findDataByFuzzy(DownloadEntity.class, 0, 10, "downloadUrl like http://"); + * + * + * @param page 需要查询的页数,从1开始,如果page小于1 或 num 小于1,返回null + * @param num 每页返回的数量 + * @return 没有数据返回null,如果页数大于总页数,返回null + */ + public static List findDataByFuzzy(Class clazz, int page, int num, + String conditions) { + return DelegateWrapper.getInstance().findDataByFuzzy(clazz, page, num, conditions); + } + + /** + * 查询一行数据 + * + * DbEntity.findFirst(DownloadEntity.class, "downloadUrl=?", downloadUrl); + * + * + * @return 没有数据返回null + */ + public static T findFirst(Class clazz, String... expression) { + DelegateWrapper util = DelegateWrapper.getInstance(); + List datas = util.findData(clazz, expression); + return datas == null ? null : datas.size() > 0 ? datas.get(0) : null; + } + + /** + * 插入多条数据 + */ + public static void insertManyData(List entities) { + checkListData(entities); + DelegateWrapper.getInstance().insertManyData(entities); + } + + /** + * 修改多条数据 + */ + public static void updateManyData(List entities) { + checkListData(entities); + DelegateWrapper.getInstance().updateManyData(entities); + } + + /** + * 保存多条数据,通过rowID来判断记录存在以否,如果数据库已有记录,则更新该记录;如果数据库中没有记录,则保存该记录 + */ + public static void saveAll(List entities) { + checkListData(entities); + List insertD = new ArrayList<>(); + List updateD = new ArrayList<>(); + DelegateWrapper wrapper = DelegateWrapper.getInstance(); + for (T entity : entities) { + if (entity.rowID == -1) { + insertD.add(entity); + continue; + } + if (wrapper.isExist(entity.getClass(), entity.rowID)) { + updateD.add(entity); + } else { + insertD.add(entity); + } + } + if (!insertD.isEmpty()) { + wrapper.insertManyData(insertD); + } + if (!updateD.isEmpty()) { + wrapper.updateManyData(updateD); + } + } + + /** + * 检查批量操作的列表数据,如果数据为空,抛出{@link NullPointerException} + */ + private static void checkListData(List entities) { + if (entities == null || entities.isEmpty()) { + throw new NullPointerException("列表数据为空"); + } + } + + /** + * 删除当前数据 + */ + public void deleteData() { + deleteData(getClass(), "rowid=?", rowID + ""); + } + + /** + * 根据条件删除数据 + * + * DbEntity.deleteData(DownloadEntity.class, "downloadUrl=?", downloadUrl); + * + */ + public static void deleteData(Class clazz, String... expression) { + DelegateWrapper util = DelegateWrapper.getInstance(); + util.delData(clazz, expression); + } + + /** + * 修改数据 + */ + public void update() { + DelegateWrapper.getInstance().updateData(this); + } + + /** + * 保存自身,如果表中已经有数据,则更新数据,否则插入数据 只有 target中checkEntity成功后才能保存,创建实体部分也不允许保存 + */ + public void save() { + synchronized (LOCK) { + if (thisIsExist()) { + update(); + } else { + insert(); + } + } + } + + /** + * 查找数据在表中是否存在 + */ + private boolean thisIsExist() { + DelegateWrapper util = DelegateWrapper.getInstance(); + return rowID != -1 && util.isExist(getClass(), rowID); + } + + /** + * 表是否存在 + * + * @return {@code true} 存在 + */ + public static boolean tableExists(Class clazz) { + return DelegateWrapper.getInstance().tableExists(clazz); + } + + /** + * 插入数据,只有 target中checkEntity成功后才能插入,创建实体部分也不允许操作 + */ + public void insert() { + DelegateWrapper.getInstance().insertData(this); + } } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java b/Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java index 1af103a2..ba1085a6 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java @@ -69,7 +69,7 @@ class DelegateUpdate extends AbsDelegate { /** * 更新多条记录 */ - synchronized void updateManyData(SQLiteDatabase db, List dbEntities) { + synchronized void updateManyData(SQLiteDatabase db, List dbEntities) { db = checkDb(db); db.beginTransaction(); try { diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java b/Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java index 86a36406..16b8466f 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java @@ -117,7 +117,7 @@ public class DelegateWrapper { /** * 更新多条数据 */ - void updateManyData(List dbEntitys) { + void updateManyData(List dbEntitys) { mDManager.getDelegate(DelegateUpdate.class).updateManyData(mDb, dbEntitys); } @@ -182,7 +182,7 @@ public class DelegateWrapper { /** * 插入多条数据 */ - void insertManyData(List dbEntitys) { + void insertManyData(List dbEntitys) { mDManager.getDelegate(DelegateUpdate.class).insertManyData(mDb, dbEntitys); } diff --git a/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java b/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java index 3bbc34fa..897cb3a3 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java @@ -98,6 +98,8 @@ final class SqlHelper extends SQLiteOpenHelper { handle314AriaUpdate(db); } else if (oldVersion < 45) { handle360AriaUpdate(db); + } else if (oldVersion < 46) { + db.execSQL("UPDATE ThreadRecord SET threadId=0 WHERE threadId=-1"); } else { handleDbUpdate(db, null, null); } diff --git a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java index c2f5cd33..bc08a76a 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java @@ -32,6 +32,7 @@ import com.arialyy.aria.core.command.group.GroupCmdFactory; import com.arialyy.aria.core.command.normal.AbsNormalCmd; import com.arialyy.aria.core.command.normal.NormalCmdFactory; import com.arialyy.aria.core.common.AbsFileer; +import com.arialyy.aria.core.common.RecordWrapper; import com.arialyy.aria.core.common.TaskRecord; import com.arialyy.aria.core.common.ThreadRecord; import com.arialyy.aria.core.download.DownloadEntity; @@ -587,6 +588,21 @@ public class CommonUtil { return ""; } + /** + * 删除任务组记录 + * + * @param removeFile {@code true} 不仅删除任务数据库记录,还会删除已经删除完成的文件 {@code false}如果任务已经完成,只删除任务数据库记录 + */ + public static void delGroupTaskRecord(String groupHash, boolean removeFile) { + if (TextUtils.isEmpty(groupHash)) { + ALog.e(TAG, "删除下载任务组记录失败,groupHash为null"); + return; + } + DownloadGroupEntity groupEntity = DbDataHelper.getDGEntity(groupHash); + + delGroupTaskRecord(groupEntity, removeFile); + } + /** * 删除任务组记录 * @@ -597,23 +613,28 @@ public class CommonUtil { ALog.e(TAG, "删除下载任务组记录失败,任务组实体为null"); return; } - List records = - DbEntity.findDatas(TaskRecord.class, "dGroupHash=?", groupEntity.getGroupHash()); + List records = + DbEntity.findRelationData(RecordWrapper.class, "dGroupHash=?", groupEntity.getGroupHash()); if (records == null || records.isEmpty()) { ALog.w(TAG, "组任务记录删除失败,记录为null"); } else { - for (TaskRecord record : records) { + for (RecordWrapper record : records) { + if (record == null || record.taskRecord == null) { + continue; + } // 删除分块文件 - if (record.isBlock) { - for (int i = 0, len = record.threadNum; i < len; i++) { - File partFile = new File(String.format(AbsFileer.SUB_PATH, record.filePath, i)); + if (record.taskRecord.isBlock) { + for (int i = 0, len = record.taskRecord.threadNum; i < len; i++) { + File partFile = + new File(String.format(AbsFileer.SUB_PATH, record.taskRecord.filePath, i)); if (partFile.exists()) { partFile.delete(); } } } - record.deleteData(); + DbEntity.deleteData(ThreadRecord.class, "key=?", record.taskRecord.filePath); + record.taskRecord.deleteData(); } } @@ -632,12 +653,13 @@ public class CommonUtil { if (dir.exists() && (removeFile || !groupEntity.isComplete())) { dir.delete(); } - groupEntity.deleteData(); } + DbEntity.deleteData(DownloadEntity.class, "groupHash=?", groupEntity.getGroupHash()); + DbEntity.deleteData(DownloadGroupEntity.class, "groupHash=?", groupEntity.getGroupHash()); } /** - * 删除任务记录 + * 删除任务记录,默认删除任务实体 * * @param removeFile {@code true} 不仅删除任务数据库记录,还会删除已经完成的文件 {@code false}如果任务已经完成,只删除任务数据库记录 */ @@ -655,7 +677,7 @@ public class CommonUtil { ALog.w(TAG, "删除记录失败,未知类型"); return; } - delTaskRecord(filePath, type, removeFile); + delTaskRecord(filePath, type, removeFile, true); } /** @@ -664,21 +686,28 @@ public class CommonUtil { * @param filePath 文件路径 * @param removeFile {@code true} 不仅删除任务数据库记录,还会删除已经删除完成的文件 {@code false}如果任务已经完成,只删除任务数据库记录 * @param type {@code 1}下载任务的记录,{@code 2} 上传任务的记录 {@code false}如果任务已经完成,只删除任务数据库记录 + * @param removeEntity {@code true} 删除任务实体, */ - public static void delTaskRecord(String filePath, int type, boolean removeFile) { + public static void delTaskRecord(String filePath, int type, boolean removeFile, + boolean removeEntity) { if (TextUtils.isEmpty(filePath)) { throw new NullPointerException("删除记录失败,文件路径为空"); } if (type != 1 && type != 2) { throw new IllegalArgumentException("任务记录类型错误"); } - TaskRecord record = DbEntity.findFirst(TaskRecord.class, "filePath=?", filePath); - DbEntity.deleteData(ThreadRecord.class, "key=?", filePath); + List recordWrapper = + DbEntity.findRelationData(RecordWrapper.class, "filePath=?", filePath); + DbEntity.deleteData(ThreadRecord.class, "key=?", filePath); // 必须先获取完成数据再删除线程记录 File file = new File(filePath); - if (record == null) { + if (recordWrapper == null + || recordWrapper.isEmpty() + || recordWrapper.get(0) == null + || recordWrapper.get(0).taskRecord == null) { ALog.w(TAG, "记录为空"); } else { + TaskRecord record = recordWrapper.get(0).taskRecord; // 删除分块文件 if (record.isBlock) { for (int i = 0, len = record.threadNum; i < len; i++) { @@ -688,28 +717,31 @@ public class CommonUtil { } } } + // 删除任务记录 record.deleteData(); } if (file.exists() && removeFile) { file.delete(); } - //下载任务实体和下载实体为一对一关系,下载实体删除,任务实体自动删除 - if (type == 1) { - DbEntity.deleteData(DownloadEntity.class, "downloadPath=?", filePath); - } else { - DbEntity.deleteData(UploadEntity.class, "filePath=?", filePath); + + if (removeEntity) { + if (type == 1) { + DbEntity.deleteData(DownloadEntity.class, "downloadPath=?", filePath); + } else { + DbEntity.deleteData(UploadEntity.class, "filePath=?", filePath); + } } } /** - * 删除任务记录,默认删除文件 + * 删除任务记录,默认删除文件,删除任务实体 * * @param filePath 文件路径 * @param type {@code 1}下载任务的记录,{@code 2} 上传任务的记录 {@code false}如果任务已经完成,只删除任务数据库记录 */ public static void delTaskRecord(String filePath, int type) { - delTaskRecord(filePath, type, false); + delTaskRecord(filePath, type, false, true); } /** @@ -925,9 +957,9 @@ public class CommonUtil { * 获取当前类里面的所在字段 */ public static Field[] getFields(Class clazz) { - Field[] fields = null; + Field[] fields; fields = clazz.getDeclaredFields(); - if (fields == null || fields.length == 0) { + if (fields.length == 0) { Class superClazz = clazz.getSuperclass(); if (superClazz != null) { fields = getFields(superClazz); @@ -1016,7 +1048,7 @@ public class CommonUtil { * @return 对象名 */ public static String getClassName(Object obj) { - String arrays[] = obj.getClass().getName().split("\\."); + String[] arrays = obj.getClass().getName().split("\\."); return arrays[arrays.length - 1]; } @@ -1027,7 +1059,7 @@ public class CommonUtil { * @return 对象名 */ public static String getClassName(Class clazz) { - String arrays[] = clazz.getName().split("\\."); + String[] arrays = clazz.getName().split("\\."); return arrays[arrays.length - 1]; } @@ -1165,7 +1197,7 @@ public class CommonUtil { blockFile.renameTo(new File(String.format(AbsFileer.SUB_PATH, newPath, tr.threadId))); } } - DbEntity.saveAll(record.threadRecords); + DbEntity.updateManyData(record.threadRecords); } } diff --git a/Aria/src/main/java/com/arialyy/aria/util/DbDataHelper.java b/Aria/src/main/java/com/arialyy/aria/util/DbDataHelper.java index 78da9ae2..a21f8a8f 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/DbDataHelper.java +++ b/Aria/src/main/java/com/arialyy/aria/util/DbDataHelper.java @@ -17,6 +17,7 @@ package com.arialyy.aria.util; import com.arialyy.aria.core.common.RecordWrapper; import com.arialyy.aria.core.common.TaskRecord; +import com.arialyy.aria.core.common.ThreadRecord; import com.arialyy.aria.core.download.DGEntityWrapper; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadGroupEntity; @@ -37,12 +38,12 @@ public class DbDataHelper { * @return 没有记录返回null,有记录则返回任务记录 */ public static TaskRecord getTaskRecord(String filePath) { - List records = + List record = DbEntity.findRelationData(RecordWrapper.class, "TaskRecord.filePath=?", filePath); - if (records == null || records.size() == 0) { + if (record == null || record.size() == 0) { return null; } - return records.get(0).taskRecord; + return record.get(0).taskRecord; } /** diff --git a/DEV_LOG.md b/DEV_LOG.md index 33b1bc55..82924c79 100644 --- a/DEV_LOG.md +++ b/DEV_LOG.md @@ -13,6 +13,16 @@ - 组合任务新增`unknownSize()`,用于处理组合任务大小未知的情况,https://github.com/AriaLyy/Aria/issues/380 - 优化`AbsThreadTask`代码 - 新增文件长度处理功能 https://github.com/AriaLyy/Aria/issues/393 + ```java + .setFileLenAdapter(new IHttpFileLenAdapter() { + @Override public long handleFileLen(Map> headers) { + ... + // 处理header中的文件长度 + + return fileLen; + } + }) + ``` - 修复组合任务多次回调`onStop`注解的问题 - 优化`isRunning()`的逻辑,任务是否在执行的判断将更加准确 - 修复多次重复快速点击`暂停、开始`时,任务有可能重复下载的问题 diff --git a/app/src/main/java/com/arialyy/simple/core/download/group/DownloadGroupActivity.java b/app/src/main/java/com/arialyy/simple/core/download/group/DownloadGroupActivity.java index 549bb020..579fd083 100644 --- a/app/src/main/java/com/arialyy/simple/core/download/group/DownloadGroupActivity.java +++ b/app/src/main/java/com/arialyy/simple/core/download/group/DownloadGroupActivity.java @@ -24,8 +24,8 @@ import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadGroupEntity; import com.arialyy.aria.core.download.DownloadGroupTask; -import com.arialyy.aria.core.inf.AbsHttpFileLenAdapter; import com.arialyy.aria.core.inf.IHttpFileLenAdapter; +import com.arialyy.aria.util.ALog; import com.arialyy.frame.util.show.L; import com.arialyy.frame.util.show.T; import com.arialyy.simple.R; @@ -59,6 +59,7 @@ public class DownloadGroupActivity extends BaseActivity> headers) { + + List sLength = headers.get("Content-Length"); + if (sLength == null || sLength.isEmpty()) { + return -1; + } + String temp = sLength.get(0); + + return Long.parseLong(temp); + } + }) //.setFileSize(114981416) //.updateUrls(temp) .start();