From 7bac19985690b68bfa4ed291fc061b731ab90e4f Mon Sep 17 00:00:00 2001 From: laoyuyu <511455842@qq.com> Date: Tue, 19 Jun 2018 20:58:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=86=E5=9D=97=E4=B8=8B=E8=BD=BD=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/arialyy/aria/core/ConfigHelper.java | 85 ++++++++++--------- .../com/arialyy/aria/core/ConfigType.java | 31 +++++++ .../arialyy/aria/core/common/AbsFileer.java | 55 ++++++++---- .../aria/core/common/AbsThreadTask.java | 32 ++++++- .../aria/core/common/StateConstance.java | 17 ++-- .../arialyy/aria/core/common/TaskRecord.java | 11 +++ .../aria/core/common/ThreadTaskManager.java | 78 +++++++++++++++++ .../core/download/downloader/Downloader.java | 14 ++- .../download/downloader/FtpThreadTask.java | 50 ++++++++--- .../download/downloader/HttpThreadTask.java | 17 +++- .../java/com/arialyy/aria/orm/DBConfig.java | 2 +- .../com/arialyy/aria/util/CommonUtil.java | 29 ++++++- .../java/com/arialyy/aria/util/FileUtil.java | 55 ++++++------ app/src/main/assets/aria_config.xml | 11 ++- .../arialyy/simple/test/AnyRunActivity.java | 4 +- .../arialyy/simple/test/AnyRunnModule.java | 10 +-- .../com/arialyy/aria/core/Configuration.java | 23 ++++- 17 files changed, 391 insertions(+), 133 deletions(-) create mode 100644 Aria/src/main/java/com/arialyy/aria/core/ConfigType.java create mode 100644 Aria/src/main/java/com/arialyy/aria/core/common/ThreadTaskManager.java diff --git a/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java b/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java index f9113622..0d26d978 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java +++ b/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java @@ -28,10 +28,10 @@ import org.xml.sax.helpers.DefaultHandler; class ConfigHelper extends DefaultHandler { private final String TAG = "ConfigHelper"; - private boolean isDownloadConfig = false, isUploadConfig = false, isAppConfig = false; private Configuration.DownloadConfig mDownloadConfig = Configuration.DownloadConfig.getInstance(); private Configuration.UploadConfig mUploadConfig = Configuration.UploadConfig.getInstance(); private Configuration.AppConfig mAppConfig = Configuration.AppConfig.getInstance(); + private @ConfigType int mType; @Override public void startDocument() throws SAXException { super.startDocument(); @@ -41,21 +41,19 @@ class ConfigHelper extends DefaultHandler { public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { super.startElement(uri, localName, qName, attributes); - if (qName.equals("download")) { - isDownloadConfig = true; - isUploadConfig = false; - isAppConfig = false; - } else if (qName.equals("upload")) { - isUploadConfig = true; - isDownloadConfig = false; - isAppConfig = false; - } else if (qName.equals("app")) { - isUploadConfig = false; - isDownloadConfig = false; - isAppConfig = true; - } - - if (isDownloadConfig || isUploadConfig) { + switch (qName) { + case "download": + mType = ConfigType.DOWNLOAD; + break; + case "upload": + mType = ConfigType.UPLOAD; + break; + case "app": + mType = ConfigType.APP; + break; + } + + if (mType == ConfigType.DOWNLOAD || mType == ConfigType.UPLOAD) { String value = attributes.getValue("value"); switch (qName) { @@ -100,8 +98,11 @@ class ConfigHelper extends DefaultHandler { case "notNetRetry": loadNotNetRetry(value); break; + case "useBlock": + loadUseBlock(value); + break; } - } else if (isAppConfig) { + } else if (mType == ConfigType.APP) { String value = attributes.getValue("value"); switch (qName) { case "useAriaCrashHandler": @@ -114,11 +115,17 @@ class ConfigHelper extends DefaultHandler { } } + private void loadUseBlock(String value) { + if (mType == ConfigType.DOWNLOAD) { + mDownloadConfig.useBlock = checkBoolean(value) ? Boolean.valueOf(value) : false; + } + } + private void loadNotNetRetry(String value) { - if (isDownloadConfig) { + if (mType == ConfigType.DOWNLOAD) { mDownloadConfig.notNetRetry = checkBoolean(value) ? Boolean.valueOf(value) : false; } - if (isUploadConfig) { + if (mType == ConfigType.UPLOAD) { mUploadConfig.notNetRetry = checkBoolean(value) ? Boolean.valueOf(value) : false; } } @@ -150,10 +157,10 @@ class ConfigHelper extends DefaultHandler { private void loadUpdateInterval(String value) { long temp = checkLong(value) ? Long.parseLong(value) : 1000; - if (isDownloadConfig) { + if (mType == ConfigType.DOWNLOAD) { mDownloadConfig.updateInterval = temp; } - if (isUploadConfig) { + if (mType == ConfigType.UPLOAD) { mUploadConfig.updateInterval = temp; } } @@ -164,17 +171,17 @@ class ConfigHelper extends DefaultHandler { "wait"))) { mod = value; } - if (isDownloadConfig) { + if (mType == ConfigType.DOWNLOAD) { mDownloadConfig.queueMod = mod; } - if (isUploadConfig) { + if (mType == ConfigType.UPLOAD) { mUploadConfig.queueMod = mod; } } private void loadMaxSpeed(String value) { int maxSpeed = checkInt(value) ? Integer.parseInt(value) : 0; - if (isDownloadConfig) { + if (mType == ConfigType.DOWNLOAD) { mDownloadConfig.maxSpeed = maxSpeed; } } @@ -185,10 +192,10 @@ class ConfigHelper extends DefaultHandler { open = Boolean.parseBoolean(value); } - if (isDownloadConfig) { + if (mType == ConfigType.DOWNLOAD) { mDownloadConfig.isConvertSpeed = open; } - if (isUploadConfig) { + if (mType == ConfigType.UPLOAD) { mUploadConfig.isConvertSpeed = open; } } @@ -200,13 +207,13 @@ class ConfigHelper extends DefaultHandler { time = 2 * 1000; } - if (isDownloadConfig) { + if (mType == ConfigType.DOWNLOAD) { mDownloadConfig.reTryInterval = time; } } private void loadCA(String name, String path) { - if (isDownloadConfig) { + if (mType == ConfigType.DOWNLOAD) { mDownloadConfig.caName = name; mDownloadConfig.caPath = path; } @@ -219,11 +226,11 @@ class ConfigHelper extends DefaultHandler { buffSize = 2048; } - if (isDownloadConfig) { + if (mType == ConfigType.DOWNLOAD) { mDownloadConfig.buffSize = buffSize; } - if (isUploadConfig) { + if (mType == ConfigType.UPLOAD) { mUploadConfig.buffSize = buffSize; } } @@ -235,11 +242,11 @@ class ConfigHelper extends DefaultHandler { time = 10 * 1000; } - if (isDownloadConfig) { + if (mType == ConfigType.DOWNLOAD) { mDownloadConfig.iOTimeOut = time; } - if (isUploadConfig) { + if (mType == ConfigType.UPLOAD) { mUploadConfig.iOTimeOut = time; } } @@ -247,10 +254,10 @@ class ConfigHelper extends DefaultHandler { private void loadConnectTime(String value) { int time = checkInt(value) ? Integer.parseInt(value) : 5 * 1000; - if (isDownloadConfig) { + if (mType == ConfigType.DOWNLOAD) { mDownloadConfig.connectTimeOut = time; } - if (isUploadConfig) { + if (mType == ConfigType.UPLOAD) { mUploadConfig.connectTimeOut = time; } } @@ -258,10 +265,10 @@ class ConfigHelper extends DefaultHandler { private void loadReTry(String value) { int num = checkInt(value) ? Integer.parseInt(value) : 0; - if (isDownloadConfig) { + if (mType == ConfigType.DOWNLOAD) { mDownloadConfig.reTryNum = num; } - if (isUploadConfig) { + if (mType == ConfigType.UPLOAD) { mUploadConfig.reTryNum = num; } } @@ -272,10 +279,10 @@ class ConfigHelper extends DefaultHandler { ALog.w(TAG, "任务队列数不能小于 1"); num = 2; } - if (isDownloadConfig) { + if (mType == ConfigType.DOWNLOAD) { mDownloadConfig.maxTaskNum = num; } - if (isUploadConfig) { + if (mType == ConfigType.UPLOAD) { mUploadConfig.maxTaskNum = num; } } @@ -286,7 +293,7 @@ class ConfigHelper extends DefaultHandler { ALog.e(TAG, "下载线程数不能小于 1"); num = 1; } - if (isDownloadConfig) { + if (mType == ConfigType.DOWNLOAD) { mDownloadConfig.threadNum = num; } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/ConfigType.java b/Aria/src/main/java/com/arialyy/aria/core/ConfigType.java new file mode 100644 index 00000000..3fc9ed35 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/ConfigType.java @@ -0,0 +1,31 @@ +/* + * 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; + +import android.support.annotation.IntDef; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@IntDef({ + ConfigType.DOWNLOAD, + ConfigType.UPLOAD, + ConfigType.APP +}) +@Retention(RetentionPolicy.SOURCE) @interface ConfigType { + int DOWNLOAD = 1; + int UPLOAD = 2; + int APP = 3; +} 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 98af3f94..7693bfd8 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 @@ -18,6 +18,7 @@ package com.arialyy.aria.core.common; import android.content.Context; import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.download.DownloadEntity; +import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.inf.AbsNormalEntity; import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.IDownloadListener; @@ -47,6 +48,10 @@ public abstract class AbsFileer 1 && manager.getDownloadConfig().isUseBlock(); + // 线程数不等1并且没有使用块下载,则认为没有使用动态文件 + mRecord.isOpenDynamicFile = mTotalThreadNum == 1 || mRecord.isBlock; + } + /* * mTaskEntity.getEntity().getFileSize() != mTempFile.length()为兼容以前老版本代码 * 动态长度条件: * 1、总线程数为1,并且是新任务 * 2、总线程数为1,不是新任务,但是长度不是文件全长度 */ - if (mTotalThreadNum == 1 && (mTaskEntity.isNewTask() - || mTaskEntity.getEntity().getFileSize() != mTempFile.length())) { - mConstance.isOpenDynamicFile = true; + if (mTotalThreadNum == 1 && (mTaskEntity.getEntity().getFileSize() != mTempFile.length())) { + mRecord.isOpenDynamicFile = true; + } + + if (!mTaskEntity.isSupportBP()) { + handleNoSupportBP(); + } else { + handleBreakpoint(); } + startTimer(); } @@ -254,17 +272,16 @@ public abstract class AbsFileer keys = pro.keySet(); // 老版本记录是5s存一次,但是5s中内,如果线程执行完成,record记录是没有的,只有state记录... // 第一步应该是record 和 state去重取正确的线程数 @@ -338,7 +355,7 @@ public abstract class AbsFileer config = new SubThreadConfig<>(); config.FILE_SIZE = fileLength; config.URL = mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getUrl(); - config.TEMP_FILE = mTempFile; + config.TEMP_FILE = + mRecord.isBlock ? new File(String.format(SUB_PATH, mTempFile.getPath(), i)) : mTempFile; config.THREAD_ID = i; config.START_LOCATION = startL; config.END_LOCATION = endL; 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 f4d411dd..0665575c 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 @@ -23,8 +23,12 @@ import com.arialyy.aria.core.inf.IEventListener; import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ErrorHelp; +import com.arialyy.aria.util.FileUtil; import com.arialyy.aria.util.NetUtils; +import java.io.File; import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ExecutorService; @@ -69,10 +73,10 @@ public abstract class AbsThreadTask info) { + SubThreadConfig config) { STATE = constance; mListener = listener; - mConfig = info; + mConfig = config; mTaskEntity = mConfig.TASK_ENTITY; mEntity = mTaskEntity.getEntity(); mLastSaveTime = System.currentTimeMillis(); @@ -134,6 +138,30 @@ public abstract class AbsThreadTask partPath = new ArrayList<>(); + for (int i = 0, len = STATE.TASK_RECORD.threadNum; i < len; i++) { + partPath.add(String.format(AbsFileer.SUB_PATH, STATE.TASK_RECORD.filePath, i)); + } + boolean isSuccess = FileUtil.mergeFile(STATE.TASK_RECORD.filePath, partPath); + if (isSuccess) { + for (String pp : partPath) { + File f = new File(pp); + if (f.exists()) { + f.delete(); + } + } + return true; + } else { + return false; + } + } + /** * 停止任务 */ diff --git a/Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java b/Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java index 8aca4910..c220d3c7 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java @@ -17,7 +17,7 @@ package com.arialyy.aria.core.common; /** * Created by lyy on 2017/1/18. - * 下载状态常量 + * 状态常量 */ public class StateConstance { public int CANCEL_NUM = 0; @@ -30,13 +30,8 @@ public class StateConstance { public boolean isCancel = false; public boolean isStop = false; public TaskRecord TASK_RECORD; - /** - * 是否是使用虚拟文件下载的 - * {@code true}是,{@code false}不是 - */ - public boolean isOpenDynamicFile = false; - public StateConstance() { + StateConstance() { } public void resetState() { @@ -50,14 +45,14 @@ public class StateConstance { } /** - * 所有子线程是否都已经停止下载 + * 所有子线程是否都已经停止 */ public boolean isStop() { return STOP_NUM == START_THREAD_NUM; } /** - * 所有子线程是否都已经下载失败 + * 所有子线程是否都已经失败 */ public boolean isFail() { return COMPLETE_THREAD_NUM != START_THREAD_NUM @@ -65,14 +60,14 @@ public class StateConstance { } /** - * 所有子线程是否都已经完成下载 + * 所有子线程是否都已经完成 */ public boolean isComplete() { return COMPLETE_THREAD_NUM >= START_THREAD_NUM; } /** - * 所有子线程是否都已经取消下载 + * 所有子线程是否都已经取消 */ public boolean isCancel() { return CANCEL_NUM == START_THREAD_NUM; diff --git a/Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java b/Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java index ea928de3..c8631486 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java @@ -73,4 +73,15 @@ public class TaskRecord extends DbEntity { @Ignore @Deprecated public String uGroupName; + + /** + * 是否是分块{@code true}是,{@code false} 不是 + */ + public boolean isBlock = false; + + /** + * 是否是使用虚拟文件下载的 + * {@code true}是,{@code false}不是 + */ + public boolean isOpenDynamicFile = false; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/common/ThreadTaskManager.java b/Aria/src/main/java/com/arialyy/aria/core/common/ThreadTaskManager.java new file mode 100644 index 00000000..8893d6df --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/common/ThreadTaskManager.java @@ -0,0 +1,78 @@ +/* + * 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.common; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 线程任务管理器 + */ +class ThreadTaskManager { + private static volatile ThreadTaskManager INSTANCE = null; + private Map> mThreadTasks = new ConcurrentHashMap<>(); + + private ThreadTaskManager() { + + } + + public static ThreadTaskManager getInstance() { + if (INSTANCE == null) { + synchronized (ThreadTaskManager.class) { + INSTANCE = new ThreadTaskManager(); + } + } + return INSTANCE; + } + + /** + * 添加单条线程记录 + * + * @param key 任务对应的key + * @param threadTask 线程任务 + */ + public void addTask(String key, AbsThreadTask threadTask) { + if (mThreadTasks.get(key) == null) { + mThreadTasks.put(key, new ArrayList()); + } + mThreadTasks.get(key).add(threadTask); + } + + /** + * 删除对应的任务的线程记录 + * + * @param key 任务对应的key + */ + public void removeTask(String key) { + for (Iterator>> iter = mThreadTasks.entrySet().iterator(); + iter.hasNext(); ) { + Map.Entry> entry = iter.next(); + if (key.equals(entry.getKey())) { + List list = mThreadTasks.get(key); + if (list != null && !list.isEmpty()) { + list.clear(); + } + iter.remove(); + } + } + } + + + +} 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 999eb37e..2335093d 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 @@ -57,22 +57,20 @@ class Downloader extends AbsFileer { } @Override protected boolean handleNewTask() { - CommonUtil.createFile(mTempFile.getPath()); + if (!mRecord.isBlock) { + CommonUtil.createFile(mTempFile.getPath()); + } BufferedRandomAccessFile file = null; try { - if (mTotalThreadNum > 1) { + if (mTotalThreadNum > 1 && !mRecord.isBlock) { file = new BufferedRandomAccessFile(new File(mTempFile.getPath()), "rwd", 8192); //设置文件长度 file.setLength(mEntity.getFileSize()); } return true; } catch (IOException e) { - failDownload("下载失败【downloadUrl:" - + mEntity.getUrl() - + "】\n【filePath:" - + mEntity.getDownloadPath() - + "】\n" - + ALog.getExceptionString(e)); + failDownload(String.format("下载失败【downloadUrl:%s】;【filePath:%s】\n %S", mEntity.getUrl(), + mEntity.getDownloadPath(), ALog.getExceptionString(e))); } finally { if (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 547e2aa4..40fdc2fb 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 @@ -41,6 +41,7 @@ import org.apache.commons.net.ftp.FTPReply; class FtpThreadTask extends AbsFtpThreadTask { private final String TAG = "FtpThreadTask"; private boolean isOpenDynamicFile; + private boolean isBlock; FtpThreadTask(StateConstance constance, IDownloadListener listener, SubThreadConfig downloadInfo) { @@ -50,11 +51,16 @@ class FtpThreadTask extends AbsFtpThreadTask mReadTimeOut = manager.getDownloadConfig().getIOTimeOut(); mBufSize = manager.getDownloadConfig().getBuffSize(); isNotNetRetry = manager.getDownloadConfig().isNotNetRetry(); - isOpenDynamicFile = STATE.isOpenDynamicFile; + isOpenDynamicFile = STATE.TASK_RECORD.isOpenDynamicFile; + isBlock = STATE.TASK_RECORD.isBlock; setMaxSpeed(manager.getDownloadConfig().getMaxSpeed()); } @Override public void run() { + if (mConfig.THREAD_RECORD.isComplete) { + handleComplete(); + return; + } //当前子线程的下载位置 mChildCurrentLocation = mConfig.START_LOCATION; FTPClient client = null; @@ -100,19 +106,7 @@ class FtpThreadTask extends AbsFtpThreadTask if (isBreak()) { return; } - ALog.i(TAG, - String.format("任务【%s】线程__%s__下载完毕", mConfig.TEMP_FILE.getName(), mConfig.THREAD_ID)); - writeConfig(true, mConfig.END_LOCATION); - STATE.COMPLETE_THREAD_NUM++; - if (STATE.isComplete()) { - STATE.TASK_RECORD.deleteData(); - STATE.isRunning = false; - mListener.onComplete(); - } - if (STATE.isFail()) { - STATE.isRunning = false; - mListener.onFail(false); - } + handleComplete(); } catch (IOException e) { fail(mChildCurrentLocation, String.format("下载失败【%s】", mConfig.URL), e); } catch (Exception e) { @@ -131,6 +125,34 @@ class FtpThreadTask extends AbsFtpThreadTask } } + /** + * 处理线程完成的情况 + */ + private void handleComplete() { + ALog.i(TAG, + String.format("任务【%s】线程__%s__下载完毕", mConfig.TEMP_FILE.getName(), mConfig.THREAD_ID)); + writeConfig(true, mConfig.END_LOCATION); + STATE.COMPLETE_THREAD_NUM++; + if (STATE.isComplete()) { + if (isBlock) { + boolean success = mergeFile(); + if (!success) { + ALog.e(TAG, String.format("任务【%s】分块文件合并失败", mConfig.TEMP_FILE.getName())); + STATE.isRunning = false; + mListener.onFail(false); + return; + } + } + STATE.TASK_RECORD.deleteData(); + STATE.isRunning = false; + mListener.onComplete(); + } + if (STATE.isFail()) { + STATE.isRunning = false; + mListener.onFail(false); + } + } + /** * 动态长度文件读取方式 */ 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 533aff00..314a0286 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 @@ -44,6 +44,7 @@ import java.nio.channels.ReadableByteChannel; final class HttpThreadTask extends AbsThreadTask { private final String TAG = "HttpThreadTask"; private boolean isOpenDynamicFile; + private boolean isBlock; HttpThreadTask(StateConstance constance, IDownloadListener listener, SubThreadConfig downloadInfo) { @@ -53,11 +54,16 @@ final class HttpThreadTask extends AbsThreadTask mapping = new HashMap<>(); static String DB_NAME; - static int VERSION = 34; + static int VERSION = 35; /** * 是否将数据库保存在Sd卡,{@code true} 是 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 692a5a02..98d5c51d 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java @@ -30,6 +30,7 @@ import com.arialyy.aria.core.command.group.AbsGroupCmd; 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.TaskRecord; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadGroupEntity; @@ -411,8 +412,17 @@ public class CommonUtil { if (records == null || records.isEmpty()) { ALog.w(TAG, "组任务记录删除失败,记录为null"); } else { - for (TaskRecord tr : records) { - tr.deleteData(); + for (TaskRecord record : records) { + // 删除分块文件 + 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 (partFile.exists()) { + partFile.delete(); + } + } + } + record.deleteData(); } } @@ -449,8 +459,19 @@ public class CommonUtil { ALog.w(TAG, "删除记录失败,未知类型"); return; } - if (file.exists() && (removeFile || !dEntity.isComplete())) { - file.delete(); + if (removeFile || !dEntity.isComplete()) { + // 删除分块文件 + 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 (partFile.exists()) { + partFile.delete(); + } + } + } + if (file.exists()) { + file.delete(); + } } if (record != null) { diff --git a/Aria/src/main/java/com/arialyy/aria/util/FileUtil.java b/Aria/src/main/java/com/arialyy/aria/util/FileUtil.java index b897633f..8732e99b 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/FileUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/FileUtil.java @@ -43,42 +43,44 @@ public class FileUtil { * * @param targetPath 目标文件 * @param subPaths 碎片文件路径 + * @return {@code true} 合并成功,{@code false}合并失败 */ - public static void mergeFile(String targetPath, List subPaths) { + public static boolean mergeFile(String targetPath, List subPaths) { File file = new File(targetPath); FileOutputStream fos = null; FileChannel foc = null; try { if (!file.exists()) { file.createNewFile(); - fos = new FileOutputStream(targetPath); - foc = fos.getChannel(); - List streams = new LinkedList<>(); - for (String subPath : subPaths) { - File f = new File(subPath); - if (!f.exists()) { - ALog.d(TAG, String.format("合并文件失败,文件【%s】不存在", subPath)); - for (FileInputStream fis : streams) { - fis.close(); - } - streams.clear(); - - return; + } + fos = new FileOutputStream(targetPath); + foc = fos.getChannel(); + List streams = new LinkedList<>(); + for (String subPath : subPaths) { + File f = new File(subPath); + if (!f.exists()) { + ALog.d(TAG, String.format("合并文件失败,文件【%s】不存在", subPath)); + for (FileInputStream fis : streams) { + fis.close(); } - streams.add(new FileInputStream(subPath)); - } - Enumeration en = Collections.enumeration(streams); - SequenceInputStream sis = new SequenceInputStream(en); - ReadableByteChannel fic = Channels.newChannel(sis); - ByteBuffer bf = ByteBuffer.allocate(8196); - while (fic.read(bf) != -1) { - bf.flip(); - foc.write(bf); - bf.compact(); + streams.clear(); + + return false; } - fic.close(); - sis.close(); + streams.add(new FileInputStream(subPath)); } + Enumeration en = Collections.enumeration(streams); + SequenceInputStream sis = new SequenceInputStream(en); + ReadableByteChannel fic = Channels.newChannel(sis); + ByteBuffer bf = ByteBuffer.allocate(8196); + while (fic.read(bf) != -1) { + bf.flip(); + foc.write(bf); + bf.compact(); + } + fic.close(); + sis.close(); + return true; } catch (IOException e) { e.printStackTrace(); } finally { @@ -93,6 +95,7 @@ public class FileUtil { e.printStackTrace(); } } + return false; } /** diff --git a/app/src/main/assets/aria_config.xml b/app/src/main/assets/aria_config.xml index 7c37a9b4..b9aa70df 100644 --- a/app/src/main/assets/aria_config.xml +++ b/app/src/main/assets/aria_config.xml @@ -11,6 +11,15 @@ + + @@ -22,7 +31,7 @@ 3、从3.4.1开始,如果线程数为1,文件初始化时将不再预占用对应长度的空间,下载多少byte,则占多大的空间; 对于采用多线程的任务或旧任务,依然采用原来的文件空间占用方式; --> - + diff --git a/app/src/main/java/com/arialyy/simple/test/AnyRunActivity.java b/app/src/main/java/com/arialyy/simple/test/AnyRunActivity.java index affaea6b..e988d22d 100644 --- a/app/src/main/java/com/arialyy/simple/test/AnyRunActivity.java +++ b/app/src/main/java/com/arialyy/simple/test/AnyRunActivity.java @@ -18,10 +18,10 @@ public class AnyRunActivity extends BaseActivity { AnyRunnModule module; String[] urls; int index = 0; - //String URL = "http://static.gaoshouyou.com/d/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk"; + String URL = "http://static.gaoshouyou.com/d/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk"; //String URL = "http://58.213.157.242:8081/sims_file/rest/v1/file/mshd_touchscreen_ms/guideFile/41c33556-dc4a-4d78-bb76-b9f627f94448.mp4/%E5%85%AB%E5%8D%A6%E6%B4%B2%E5%8D%97%E4%BA%AC%E5%86%9C%E4%B8%9A%E5%98%89%E5%B9%B4%E5%8D%8E0511.mp4"; //String URL = "http://d1.showself.com/download/showself_android-s236279_release.apk"; - String URL = "http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk"; + //String URL = "http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk"; //private final String URL = "ftp://192.168.29.140:21/download/AriaPrj.rar"; //String URL = "https://dl.genymotion.com/releases/genymotion-2.12.1/genymotion-2.12.1-vbox.exe"; //String URL = "ftp://192.168.29.140:21/download/SDK_Demo-release.apk"; diff --git a/app/src/main/java/com/arialyy/simple/test/AnyRunnModule.java b/app/src/main/java/com/arialyy/simple/test/AnyRunnModule.java index a7f630ee..b56727f8 100644 --- a/app/src/main/java/com/arialyy/simple/test/AnyRunnModule.java +++ b/app/src/main/java/com/arialyy/simple/test/AnyRunnModule.java @@ -65,11 +65,11 @@ public class AnyRunnModule { void start(String url) { mUrl = url; - String path = Environment.getExternalStorageDirectory().getPath() + "/abcds.exe"; - File file = new File(path); - if (file.exists()) { - file.delete(); - } + String path = Environment.getExternalStorageDirectory().getPath() + "/abcds.apk"; + //File file = new File(path); + //if (file.exists()) { + // file.delete(); + //} Aria.download(this) .load(url) //.addHeader("Accept-Encoding", "gzip") diff --git a/aria/src/main/java/com/arialyy/aria/core/Configuration.java b/aria/src/main/java/com/arialyy/aria/core/Configuration.java index 51539db5..99ffc7a3 100644 --- a/aria/src/main/java/com/arialyy/aria/core/Configuration.java +++ b/aria/src/main/java/com/arialyy/aria/core/Configuration.java @@ -379,6 +379,26 @@ class Configuration { */ int maxSpeed = 0; + /** + * 多线程下载是否使用块下载模式,{@code true}使用,{@code false}不使用 + * 注意: + * 1、使用分块模式,在读写性能底下的手机上,合并文件需要的时间会更加长; + * 2、优点是使用多线程的块下载,初始化时,文件初始化时将不会预占用对应长度的空间; + * 3、只对新的多线程下载任务有效 + * 4、只对多线程的任务有效 + */ + boolean useBlock = false; + + public boolean isUseBlock() { + return useBlock; + } + + public DownloadConfig setUseBlock(boolean useBlock) { + this.useBlock = useBlock; + saveKey("useBlock", String.valueOf(useBlock)); + return this; + } + public DownloadConfig setMaxTaskNum(int maxTaskNum) { oldMaxTaskNum = this.maxTaskNum; this.maxTaskNum = maxTaskNum; @@ -398,9 +418,10 @@ class Configuration { return this; } - public void setThreadNum(int threadNum) { + public DownloadConfig setThreadNum(int threadNum) { this.threadNum = threadNum; saveKey("threadNum", String.valueOf(threadNum)); + return this; } public String getCaPath() {