From 4f40341ee9fe79c9202024c737e676f81aee7a64 Mon Sep 17 00:00:00 2001 From: AriaLyy <511455842@qq.com> Date: Fri, 28 Jul 2017 18:57:14 +0800 Subject: [PATCH] =?UTF-8?q?ftp=E6=96=AD=E7=82=B9=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/arialyy/aria/core/Aria.java | 2 +- .../com/arialyy/aria/core/AriaManager.java | 5 +- .../core/command/group/GroupStartCmd.java | 2 +- .../aria/core/command/normal/StartCmd.java | 2 +- .../arialyy/aria/core/common/AbsFileer.java | 395 ++++++++++++++++++ .../downloader => common}/AbsThreadTask.java | 78 ++-- .../IDownloadUtil.java => common/IUtil.java} | 14 +- .../aria/core/{ => common}/ProxyHelper.java | 3 +- .../aria/core/{ => common}/QueueMod.java | 4 +- .../aria/core/{ => common}/RequestEnum.java | 2 +- .../downloader => common}/StateConstance.java | 40 +- .../aria/core/common/SubThreadConfig.java | 25 ++ .../aria/core/download/BaseGroupTarget.java | 4 +- .../aria/core/download/BaseListener.java | 7 +- .../aria/core/download/DownloadEntity.java | 87 ++-- .../aria/core/download/DownloadGroupTask.java | 16 +- .../aria/core/download/DownloadListener.java | 2 +- .../aria/core/download/DownloadReceiver.java | 6 +- .../aria/core/download/DownloadTarget.java | 8 +- .../aria/core/download/DownloadTask.java | 22 +- .../download/downloader/AbsFtpInfoThread.java | 3 +- .../download/downloader/AbsGroupUtil.java | 32 +- .../download/downloader/ConnectionHelp.java | 4 - .../downloader/DownloadGroupUtil.java | 3 +- .../core/download/downloader/Downloader.java | 363 +--------------- .../downloader/FtpDirDownloadUtil.java | 8 +- .../download/downloader/FtpDirInfoThread.java | 2 +- .../download/downloader/FtpThreadTask.java | 24 +- .../downloader/HttpFileInfoThread.java | 16 +- .../download/downloader/HttpThreadTask.java | 28 +- .../downloader/IDownloadGroupListener.java | 3 +- .../downloader/SimpleDownloadUtil.java | 38 +- .../download/downloader/SubThreadConfig.java | 25 -- .../aria/core/inf/AbsNormalEntity.java | 37 ++ .../com/arialyy/aria/core/inf/AbsTarget.java | 2 +- .../arialyy/aria/core/inf/AbsTaskEntity.java | 2 +- .../aria/core/inf/AbsUploadTarget.java | 4 +- .../downloader => inf}/IDownloadListener.java | 9 +- .../arialyy/aria/core/inf/IEventListener.java | 5 - .../com/arialyy/aria/core/inf/ITarget.java | 2 +- .../uploader => inf}/IUploadListener.java | 6 +- .../aria/core/queue/DownloadTaskQueue.java | 2 +- .../aria/core/upload/FtpUploadTarget.java | 6 + .../aria/core/upload/UploadEntity.java | 12 - .../aria/core/upload/UploadListener.java | 10 +- .../aria/core/upload/UploadReceiver.java | 16 +- .../aria/core/upload/UploadTarget.java | 5 + .../core/upload/uploader/FtpThreadTask.java | 186 +++++++++ .../HttpThreadTask.java} | 67 +-- .../core/upload/uploader/IUploadUtil.java | 66 --- .../upload/uploader/SimpleHttpUploadUtil.java | 82 ++++ .../aria/core/upload/uploader/Uploader.java | 112 +++-- .../java/com/arialyy/aria/util/CheckUtil.java | 7 +- app/src/main/AndroidManifest.xml | 1 + .../java/com/arialyy/simple/MainActivity.java | 15 +- .../simple/download/DownloadModule.java | 2 +- .../download/HighestPriorityActivity.java | 6 +- .../simple/download/SingleTaskActivity.java | 6 +- .../multi_download/DownloadAdapter.java | 4 +- .../simple/test/TestMutilTaskSysDownload.java | 2 +- .../simple/upload/FtpUploadActivity.java | 93 +++++ .../arialyy/simple/upload/UploadActivity.java | 7 +- .../main/res/layout/activity_ftp_upload.xml | 36 ++ app/src/main/res/layout/activity_main.xml | 12 +- ...ty_upload_mean.xml => activity_upload.xml} | 0 .../com/arialyy/aria/core/Configuration.java | 1 + .../arialyy/aria/core/upload/UploadTask.java | 23 +- 67 files changed, 1264 insertions(+), 855 deletions(-) create mode 100644 Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java rename Aria/src/main/java/com/arialyy/aria/core/{download/downloader => common}/AbsThreadTask.java (75%) rename Aria/src/main/java/com/arialyy/aria/core/{download/downloader/IDownloadUtil.java => common/IUtil.java} (84%) rename Aria/src/main/java/com/arialyy/aria/core/{ => common}/ProxyHelper.java (96%) rename Aria/src/main/java/com/arialyy/aria/core/{ => common}/QueueMod.java (92%) rename Aria/src/main/java/com/arialyy/aria/core/{ => common}/RequestEnum.java (95%) rename Aria/src/main/java/com/arialyy/aria/core/{download/downloader => common}/StateConstance.java (65%) create mode 100644 Aria/src/main/java/com/arialyy/aria/core/common/SubThreadConfig.java delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/SubThreadConfig.java rename Aria/src/main/java/com/arialyy/aria/core/{download/downloader => inf}/IDownloadListener.java (86%) rename Aria/src/main/java/com/arialyy/aria/core/{upload/uploader => inf}/IUploadListener.java (86%) create mode 100644 Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java rename Aria/src/main/java/com/arialyy/aria/core/upload/{UploadUtil.java => uploader/HttpThreadTask.java} (80%) delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/upload/uploader/IUploadUtil.java create mode 100644 Aria/src/main/java/com/arialyy/aria/core/upload/uploader/SimpleHttpUploadUtil.java create mode 100644 app/src/main/java/com/arialyy/simple/upload/FtpUploadActivity.java create mode 100644 app/src/main/res/layout/activity_ftp_upload.xml rename app/src/main/res/layout/{activity_upload_mean.xml => activity_upload.xml} (100%) diff --git a/Aria/src/main/java/com/arialyy/aria/core/Aria.java b/Aria/src/main/java/com/arialyy/aria/core/Aria.java index 5dc70cfe..538f8504 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/Aria.java +++ b/Aria/src/main/java/com/arialyy/aria/core/Aria.java @@ -43,7 +43,7 @@ import com.arialyy.aria.core.upload.UploadTask; * * //下载 * Aria.download(this) - * .load(DOWNLOAD_URL) //下载地址,必填 + * .load(URL) //下载地址,必填 * //文件保存路径,必填 * .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk") * .start(); 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 33d347ed..f13e618d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java @@ -28,6 +28,7 @@ import android.support.v4.app.Fragment; import android.text.TextUtils; import android.util.Log; import android.widget.PopupWindow; +import com.arialyy.aria.core.common.QueueMod; import com.arialyy.aria.core.download.DownloadReceiver; import com.arialyy.aria.core.command.ICmd; import com.arialyy.aria.core.inf.IReceiver; @@ -88,7 +89,7 @@ import org.xml.sax.SAXException; /** * 设置上传任务的执行队列类型 * - * @param mod {@link com.arialyy.aria.core.QueueMod} + * @param mod {@link QueueMod} */ public AriaManager setUploadQueueMod(QueueMod mod) { mUConfig.setQueueMod(mod.tag); @@ -98,7 +99,7 @@ import org.xml.sax.SAXException; /** * 设置下载任务的执行队列类型 * - * @param mod {@link com.arialyy.aria.core.QueueMod} + * @param mod {@link QueueMod} */ public AriaManager setDownloadQueueMod(QueueMod mod) { mDConfig.setQueueMod(mod.tag); diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java index 4fde6115..8f890987 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java @@ -17,7 +17,7 @@ package com.arialyy.aria.core.command.group; import android.text.TextUtils; import com.arialyy.aria.core.AriaManager; -import com.arialyy.aria.core.QueueMod; +import com.arialyy.aria.core.common.QueueMod; import com.arialyy.aria.core.inf.AbsGroupTask; import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.IEntity; diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java index 25e9a8e7..c61b31da 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java @@ -18,7 +18,7 @@ package com.arialyy.aria.core.command.normal; import android.text.TextUtils; import com.arialyy.aria.core.AriaManager; -import com.arialyy.aria.core.QueueMod; +import com.arialyy.aria.core.common.QueueMod; import com.arialyy.aria.core.inf.AbsTask; import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.AbsTaskEntity; 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 new file mode 100644 index 00000000..a387a4d9 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java @@ -0,0 +1,395 @@ +/* + * 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 android.content.Context; +import android.util.Log; +import android.util.SparseArray; +import com.arialyy.aria.core.AriaManager; +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; +import com.arialyy.aria.core.inf.IEventListener; +import com.arialyy.aria.core.upload.UploadTaskEntity; +import com.arialyy.aria.util.CommonUtil; +import java.io.File; +import java.util.Properties; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Created by AriaL on 2017/7/1. + * 文件下载器 + */ +public abstract class AbsFileer> + implements Runnable, IUtil { + private final String TAG = "Downloader"; + protected IEventListener mListener; + protected TASK_ENTITY mTaskEntity; + protected ENTITY mEntity; + protected File mConfigFile;//信息配置文件 + protected Context mContext; + protected File mTempFile; //下载的文件 + protected boolean isNewTask = true; + protected StateConstance mConstance; + private ExecutorService mFixedThreadPool; + private int mThreadNum, mRealThreadNum; + private SparseArray mTask = new SparseArray<>(); + + /** + * 小于1m的文件不启用多线程 + */ + private static final long SUB_LEN = 1024 * 1024; + private Timer mTimer; + + protected AbsFileer(IEventListener listener, TASK_ENTITY taskEntity) { + mListener = listener; + mTaskEntity = taskEntity; + mEntity = mTaskEntity.getEntity(); + mContext = AriaManager.APP; + mConstance = new StateConstance(); + } + + @Override public void setMaxSpeed(double maxSpeed) { + for (int i = 0; i < mThreadNum; i++) { + AbsThreadTask task = mTask.get(i); + if (task != null) { + task.setMaxSpeed(maxSpeed); + } + } + } + + public StateConstance getConstance() { + return mConstance; + } + + @Override public void run() { + startFlow(); + } + + /** + * 开始下载流程 + */ + private void startFlow() { + checkTask(); + if (mListener instanceof IDownloadListener) { + ((IDownloadListener) mListener).onPostPre(mEntity.getFileSize()); + } + mConstance.cleanState(); + mConstance.isRunning = true; + if (!mTaskEntity.isSupportBP) { + mThreadNum = 1; + mConstance.THREAD_NUM = mThreadNum; + handleNoSupportBP(); + } else { + mThreadNum = isNewTask ? (getThreadNum()) : mRealThreadNum; + mConstance.THREAD_NUM = mThreadNum; + mFixedThreadPool = Executors.newFixedThreadPool(mThreadNum); + handleBreakpoint(); + } + startTimer(); + } + + /** + * 获取线程数 + */ + protected int getThreadNum() { + return mEntity.getFileSize() <= SUB_LEN || mTaskEntity.requestType == AbsTaskEntity.FTP_DIR ? 1 + : AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum(); + } + + /** + * 启动进度获取定时器 + */ + private void startTimer() { + mTimer = new Timer(true); + mTimer.schedule(new TimerTask() { + @Override public void run() { + if (mConstance.isComplete() || !mConstance.isRunning) { + closeTimer(); + } else if (mConstance.CURRENT_LOCATION >= 0) { + mListener.onProgress(mConstance.CURRENT_LOCATION); + } + } + }, 0, 1000); + } + + private void closeTimer() { + if (mTimer != null) { + mTimer.purge(); + mTimer.cancel(); + } + } + + @Override public long getFileSize() { + return mEntity.getFileSize(); + } + + /** + * 获取当前下载位置 + */ + @Override public long getCurrentLocation() { + return mConstance.CURRENT_LOCATION; + } + + @Override public boolean isRunning() { + return mConstance.isRunning; + } + + @Override public void cancel() { + closeTimer(); + mConstance.isCancel = true; + mConstance.isRunning = false; + if (mFixedThreadPool != null) { + mFixedThreadPool.shutdown(); + } + for (int i = 0; i < mThreadNum; i++) { + AbsThreadTask task = mTask.get(i); + if (task != null) { + task.cancel(); + } + } + if (mTaskEntity instanceof DownloadTaskEntity) { + CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, (DownloadTaskEntity) mTaskEntity); + } else if (mTaskEntity instanceof UploadTaskEntity) { + CommonUtil.delUploadTaskConfig(mTaskEntity.removeFile, (UploadTaskEntity) mTaskEntity); + } + } + + @Override public void stop() { + closeTimer(); + if (mConstance.isComplete()) return; + mConstance.isStop = true; + mConstance.isRunning = false; + if (mFixedThreadPool != null) { + mFixedThreadPool.shutdown(); + } + for (int i = 0; i < mThreadNum; i++) { + AbsThreadTask task = mTask.get(i); + if (task != null) { + task.stop(); + } + } + } + + /** + * 直接调用的时候会自动启动线程执行 + */ + @Override public void start() { + new Thread(this).start(); + } + + @Override public void resume() { + start(); + } + + /** + * 返回该下载器的 + */ + public IEventListener getListener() { + return mListener; + } + + /** + * 检查任务是否是新任务,新任务条件: + * 1、文件不存在 + * 2、下载记录文件不存在 + * 3、下载记录文件缺失或不匹配 + * 4、数据库记录不存在 + * 5、不支持断点,则是新任务 + */ + protected abstract void checkTask(); + + /** + * 检查记录文件,如果是新任务返回{@code true},否则返回{@code false} + */ + protected boolean checkConfigFile() { + Properties pro = CommonUtil.loadConfig(mConfigFile); + if (pro.isEmpty()) { + return true; + } + Set keys = pro.keySet(); + int num = 0; + for (Object key : keys) { + if (String.valueOf(key).contains("_record_")) { + num++; + } + } + if (num == 0) { + return true; + } + mRealThreadNum = num; + for (int i = 0; i < mRealThreadNum; i++) { + if (pro.getProperty(mTempFile.getName() + "_record_" + i) == null) { + Object state = pro.getProperty(mTempFile.getName() + "_state_" + i); + if (state != null && Integer.parseInt(state + "") == 1) { + continue; + } + return true; + } + } + return false; + } + + /** + * 恢复记录地址 + * + * @return true 表示下载完成 + */ + private boolean resumeRecordLocation(int i, long startL, long endL) { + mConstance.CURRENT_LOCATION += endL - startL; + Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++"); + mConstance.COMPLETE_THREAD_NUM++; + mConstance.STOP_NUM++; + mConstance.CANCEL_NUM++; + if (mConstance.isComplete()) { + if (mConfigFile.exists()) { + mConfigFile.delete(); + } + mListener.onComplete(); + mConstance.isRunning = false; + return true; + } + return false; + } + + /** + * 启动断点任务时,创建单线程任务 + * + * @param i 线程id + * @param startL 该任务起始位置 + * @param endL 该任务结束位置 + * @param fileLength 该任务需要处理的文件长度 + */ + private AbsThreadTask createSingThreadTask(int i, long startL, long endL, long fileLength) { + SubThreadConfig config = new SubThreadConfig<>(); + config.FILE_SIZE = fileLength; + config.URL = mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getUrl(); + config.TEMP_FILE = mTempFile; + config.THREAD_ID = i; + config.START_LOCATION = startL; + config.END_LOCATION = endL; + config.CONFIG_FILE_PATH = mConfigFile.getPath(); + config.SUPPORT_BP = mTaskEntity.isSupportBP; + config.TASK_ENTITY = mTaskEntity; + return selectThreadTask(config); + } + + /** + * 启动单线程下载任务 + */ + private void startSingleTask(int[] recordL) { + if (mConstance.CURRENT_LOCATION > 0) { + mListener.onResume(mConstance.CURRENT_LOCATION); + } else { + mListener.onStart(mConstance.CURRENT_LOCATION); + } + mFixedThreadPool = Executors.newFixedThreadPool(recordL.length); + for (int l : recordL) { + if (l == -1) continue; + Runnable task = mTask.get(l); + if (task != null) { + mFixedThreadPool.execute(task); + } + } + } + + /** + * 处理断点 + */ + private void handleBreakpoint() { + long fileLength = mEntity.getFileSize(); + Properties pro = CommonUtil.loadConfig(mConfigFile); + int blockSize = (int) (fileLength / mThreadNum); + int[] recordL = new int[mThreadNum]; + for (int i = 0; i < mThreadNum; i++) { + recordL[i] = -1; + } + int rl = 0; + if (isNewTask) { + handleNewTask(); + } + for (int i = 0; i < mThreadNum; i++) { + long startL = i * blockSize, endL = (i + 1) * blockSize; + Object state = pro.getProperty(mTempFile.getName() + "_state_" + i); + if (state != null && Integer.parseInt(state + "") == 1) { //该线程已经完成 + if (resumeRecordLocation(i, startL, endL)) return; + continue; + } + //分配下载位置 + Object record = pro.getProperty(mTempFile.getName() + "_record_" + i); + //如果有记录,则恢复下载 + if (!isNewTask && record != null && Long.parseLong(record + "") >= 0) { + Long r = Long.parseLong(record + ""); + mConstance.CURRENT_LOCATION += r - startL; + Log.d(TAG, "任务【" + mEntity.getFileName() + "】线程__" + i + "__恢复下载"); + startL = r; + recordL[rl] = i; + rl++; + } else { + recordL[rl] = i; + rl++; + } + if (i == (mThreadNum - 1)) { + //最后一个线程的结束位置即为文件的总长度 + endL = fileLength; + } + AbsThreadTask task = createSingThreadTask(i, startL, endL, fileLength); + if (task == null) return; + mTask.put(i, task); + } + startSingleTask(recordL); + } + + protected abstract void handleNewTask(); + + /** + * 处理不支持断点的下载 + */ + private void handleNoSupportBP() { + SubThreadConfig config = new SubThreadConfig<>(); + config.FILE_SIZE = mEntity.getFileSize(); + config.URL = mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getUrl(); + config.TEMP_FILE = mTempFile; + config.THREAD_ID = 0; + config.START_LOCATION = 0; + config.END_LOCATION = config.FILE_SIZE; + config.CONFIG_FILE_PATH = mConfigFile.getPath(); + config.SUPPORT_BP = mTaskEntity.isSupportBP; + config.TASK_ENTITY = mTaskEntity; + AbsThreadTask task = selectThreadTask(config); + if (task == null) return; + mTask.put(0, task); + mFixedThreadPool.execute(task); + mListener.onStart(0); + } + + /** + * 选择单任务线程的类型 + */ + protected abstract AbsThreadTask selectThreadTask(SubThreadConfig config); + + protected void failDownload(String errorMsg) { + closeTimer(); + Log.e(TAG, errorMsg); + mConstance.isRunning = false; + mListener.onFail(); + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java similarity index 75% rename from Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsThreadTask.java rename to Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java index e748b58c..3f525881 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsThreadTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java @@ -13,14 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.core.download.downloader; +package com.arialyy.aria.core.common; import android.os.Build; import android.text.TextUtils; import android.util.Log; 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.AbsEntity; +import com.arialyy.aria.core.inf.AbsTaskEntity; +import com.arialyy.aria.core.inf.IEventListener; import com.arialyy.aria.util.CommonUtil; import java.io.File; import java.io.IOException; @@ -31,35 +32,40 @@ import java.util.Properties; * Created by lyy on 2017/1/18. * 下载线程 */ -abstract class AbsThreadTask implements Runnable { +public abstract class AbsThreadTask> + implements Runnable { private final String TAG = "AbsThreadTask"; - long mChildCurrentLocation = 0, mSleepTime = 0; - int mBufSize; - String mConfigFPath; - SubThreadConfig mConfig; - IDownloadListener mListener; - StateConstance STATE; - DownloadEntity mEntity; - DownloadTaskEntity mTaskEntity; + protected long mChildCurrentLocation = 0, mSleepTime = 0; + protected int mBufSize; + protected String mConfigFPath; + protected IEventListener mListener; + protected StateConstance STATE; + protected SubThreadConfig mConfig; + protected ENTITY mEntity; + protected TASK_ENTITY mTaskEntity; + /** + * FTP 服务器编码 + */ + public static String SERVER_CHARSET = "ISO-8859-1"; - AbsThreadTask(StateConstance constance, IDownloadListener listener, - SubThreadConfig downloadInfo) { + protected AbsThreadTask(StateConstance constance, IEventListener listener, + SubThreadConfig info) { AriaManager manager = AriaManager.getInstance(AriaManager.APP); STATE = constance; STATE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut(); STATE.READ_TIME_OUT = manager.getDownloadConfig().getIOTimeOut(); mListener = listener; - mConfig = downloadInfo; - mTaskEntity = mConfig.DOWNLOAD_TASK_ENTITY; + mConfig = info; + mTaskEntity = mConfig.TASK_ENTITY; mEntity = mTaskEntity.getEntity(); - if (mConfig.IS_SUPPORT_BREAK_POINT) { - mConfigFPath = downloadInfo.CONFIG_FILE_PATH; + if (mConfig.SUPPORT_BP) { + mConfigFPath = info.CONFIG_FILE_PATH; } mBufSize = manager.getDownloadConfig().getBuffSize(); setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed()); } - void setMaxSpeed(double maxSpeed) { + public void setMaxSpeed(double maxSpeed) { if (-0.9999 < maxSpeed && maxSpeed < 0.00001) { mSleepTime = 0; } else { @@ -76,10 +82,10 @@ abstract class AbsThreadTask implements Runnable { /** * 停止下载 */ - void stop() { + public void stop() { synchronized (AriaManager.LOCK) { try { - if (mConfig.IS_SUPPORT_BREAK_POINT) { + if (mConfig.SUPPORT_BP) { STATE.STOP_NUM++; Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() @@ -90,12 +96,12 @@ abstract class AbsThreadTask implements Runnable { writeConfig(false, mChildCurrentLocation); if (STATE.isStop()) { Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止"); - STATE.isDownloading = false; + STATE.isRunning = false; mListener.onStop(STATE.CURRENT_LOCATION); } } else { Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止"); - STATE.isDownloading = false; + STATE.isRunning = false; mListener.onStop(STATE.CURRENT_LOCATION); } } catch (IOException e) { @@ -107,7 +113,7 @@ abstract class AbsThreadTask implements Runnable { /** * 下载中 */ - void progress(long len) { + protected void progress(long len) { synchronized (AriaManager.LOCK) { mChildCurrentLocation += len; STATE.CURRENT_LOCATION += len; @@ -117,9 +123,9 @@ abstract class AbsThreadTask implements Runnable { /** * 取消下载 */ - void cancel() { + public void cancel() { synchronized (AriaManager.LOCK) { - if (mConfig.IS_SUPPORT_BREAK_POINT) { + if (mConfig.SUPPORT_BP) { STATE.CANCEL_NUM++; Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__取消下载"); @@ -132,39 +138,39 @@ abstract class AbsThreadTask implements Runnable { mConfig.TEMP_FILE.delete(); } Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已取消"); - STATE.isDownloading = false; + STATE.isRunning = false; mListener.onCancel(); } } else { Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已取消"); - STATE.isDownloading = false; + STATE.isRunning = false; mListener.onCancel(); } } } /** - * 下载失败 + * 任务失败 */ - void failDownload(long currentLocation, String msg, Exception ex) { + protected void fail(long currentLocation, String msg, Exception ex) { synchronized (AriaManager.LOCK) { try { STATE.FAIL_NUM++; - STATE.isDownloading = false; + STATE.isRunning = false; STATE.isStop = true; if (ex != null) { Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex)); - }else { + } else { Log.e(TAG, msg); } - if (mConfig.IS_SUPPORT_BREAK_POINT) { + if (mConfig.SUPPORT_BP) { writeConfig(false, currentLocation); if (STATE.isFail()) { - Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】下载失败"); + Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败"); mListener.onFail(); } } else { - Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】下载失败"); + Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败"); mListener.onFail(); } } catch (IOException e) { @@ -176,7 +182,7 @@ abstract class AbsThreadTask implements Runnable { /** * 将记录写入到配置文件 */ - void writeConfig(boolean isComplete, long record) throws IOException { + protected void writeConfig(boolean isComplete, long record) throws IOException { synchronized (AriaManager.LOCK) { String key = null, value = null; if (0 < record && record < mConfig.END_LOCATION) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/common/IUtil.java similarity index 84% rename from Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java rename to Aria/src/main/java/com/arialyy/aria/core/common/IUtil.java index bb92edde..ae60e058 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/IUtil.java @@ -14,13 +14,13 @@ * limitations under the License. */ -package com.arialyy.aria.core.download.downloader; +package com.arialyy.aria.core.common; /** * Created by lyy on 2016/10/31. * 抽象的下载接口 */ -public interface IDownloadUtil { +public interface IUtil { /** * 获取文件大小 @@ -37,27 +37,27 @@ public interface IDownloadUtil { * * @return true, 正在下载 */ - boolean isDownloading(); + boolean isRunning(); /** * 取消下载 */ - void cancelDownload(); + void cancel(); /** * 停止下载 */ - void stopDownload(); + void stop(); /** * 开始下载 */ - void startDownload(); + void start(); /** * 从上次断点恢复下载 */ - void resumeDownload(); + void resume(); /** * 设置最大下载速度 diff --git a/Aria/src/main/java/com/arialyy/aria/core/ProxyHelper.java b/Aria/src/main/java/com/arialyy/aria/core/common/ProxyHelper.java similarity index 96% rename from Aria/src/main/java/com/arialyy/aria/core/ProxyHelper.java rename to Aria/src/main/java/com/arialyy/aria/core/common/ProxyHelper.java index c1d1236f..c12ca3f2 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/ProxyHelper.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/ProxyHelper.java @@ -13,8 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.core; +package com.arialyy.aria.core.common; +import com.arialyy.aria.core.AriaManager; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Set; diff --git a/Aria/src/main/java/com/arialyy/aria/core/QueueMod.java b/Aria/src/main/java/com/arialyy/aria/core/common/QueueMod.java similarity index 92% rename from Aria/src/main/java/com/arialyy/aria/core/QueueMod.java rename to Aria/src/main/java/com/arialyy/aria/core/common/QueueMod.java index db9e7b6c..44088f3a 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/QueueMod.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/QueueMod.java @@ -1,4 +1,4 @@ -package com.arialyy.aria.core; +package com.arialyy.aria.core.common; /** * Created by Aria.Lao on 2017/6/21. @@ -19,7 +19,7 @@ public enum QueueMod { */ NOW("now"); - String tag; + public String tag; public String getTag() { return tag; diff --git a/Aria/src/main/java/com/arialyy/aria/core/RequestEnum.java b/Aria/src/main/java/com/arialyy/aria/core/common/RequestEnum.java similarity index 95% rename from Aria/src/main/java/com/arialyy/aria/core/RequestEnum.java rename to Aria/src/main/java/com/arialyy/aria/core/common/RequestEnum.java index 71b82ecd..5822bb70 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/RequestEnum.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/RequestEnum.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.core; +package com.arialyy.aria.core.common; /** * Created by lyy on 2017/1/23. diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java b/Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java similarity index 65% rename from Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java rename to Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java index 9505be5d..101d3dbd 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java @@ -13,32 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.core.download.downloader; +package com.arialyy.aria.core.common; /** * Created by lyy on 2017/1/18. * 下载状态常量 */ -class StateConstance { - int CANCEL_NUM = 0; - int STOP_NUM = 0; - int FAIL_NUM = 0; - int CONNECT_TIME_OUT; //连接超时时间 - int READ_TIME_OUT; //流读取的超时时间 - int COMPLETE_THREAD_NUM = 0; - int THREAD_NUM; - long CURRENT_LOCATION = 0; - boolean isDownloading = false; - boolean isCancel = false; - boolean isStop = false; +public class StateConstance { + public int CANCEL_NUM = 0; + public int STOP_NUM = 0; + public int FAIL_NUM = 0; + public int CONNECT_TIME_OUT; //连接超时时间 + public int READ_TIME_OUT; //流读取的超时时间 + public int COMPLETE_THREAD_NUM = 0; + public int THREAD_NUM; + public long CURRENT_LOCATION = 0; + public boolean isRunning = false; + public boolean isCancel = false; + public boolean isStop = false; - StateConstance() { + public StateConstance() { } - void cleanState() { + public void cleanState() { isCancel = false; isStop = false; - isDownloading = true; + isRunning = true; CURRENT_LOCATION = 0; CANCEL_NUM = 0; STOP_NUM = 0; @@ -48,28 +48,28 @@ class StateConstance { /** * 所有子线程是否都已经停止下载 */ - boolean isStop() { + public boolean isStop() { return STOP_NUM == THREAD_NUM; } /** * 所有子线程是否都已经下载失败 */ - boolean isFail() { + public boolean isFail() { return FAIL_NUM == THREAD_NUM; } /** * 所有子线程是否都已经完成下载 */ - boolean isComplete() { + public boolean isComplete() { return COMPLETE_THREAD_NUM == THREAD_NUM; } /** * 所有子线程是否都已经取消下载 */ - boolean isCancel() { + public boolean isCancel() { return CANCEL_NUM == THREAD_NUM; } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/common/SubThreadConfig.java b/Aria/src/main/java/com/arialyy/aria/core/common/SubThreadConfig.java new file mode 100644 index 00000000..d2992980 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/common/SubThreadConfig.java @@ -0,0 +1,25 @@ +package com.arialyy.aria.core.common; + +import com.arialyy.aria.core.inf.AbsTaskEntity; +import java.io.File; + +/** + * 子线程下载信息类 + */ +public class SubThreadConfig { + //线程Id + public int THREAD_ID; + //下载文件大小 + public long FILE_SIZE; + //子线程启动下载位置 + public long START_LOCATION; + //子线程结束下载位置 + public long END_LOCATION; + //下载文件或上传的文件路径 + public File TEMP_FILE; + //服务器地址 + public String URL; + public String CONFIG_FILE_PATH; + public TASK_ENTITY TASK_ENTITY; + public boolean SUPPORT_BP = true; +} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java index c6e1d129..e6e5c684 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java @@ -186,8 +186,8 @@ abstract class BaseGroupTarget list = new ArrayList<>(); for (int i = 0, len = mUrls.size(); i < len; i++) { DownloadEntity entity = new DownloadEntity(); - entity.setDownloadUrl(mUrls.get(i)); - String fileName = mSubTaskFileName.isEmpty() ? createFileName(entity.getDownloadUrl()) + entity.setUrl(mUrls.get(i)); + String fileName = mSubTaskFileName.isEmpty() ? createFileName(entity.getUrl()) : mSubTaskFileName.get(i); entity.setDownloadPath(mEntity.getDirPath() + "/" + fileName); entity.setGroupName(mGroupName); diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/BaseListener.java b/Aria/src/main/java/com/arialyy/aria/core/download/BaseListener.java index 211a705b..de30a6e5 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/BaseListener.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/BaseListener.java @@ -20,6 +20,7 @@ import android.util.Log; import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsTask; +import com.arialyy.aria.core.inf.IDownloadListener; import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEventListener; import com.arialyy.aria.core.scheduler.ISchedulers; @@ -30,7 +31,7 @@ import java.lang.ref.WeakReference; * 下载监听类 */ class BaseListener> - implements IEventListener { + implements IDownloadListener { private WeakReference outHandler; private long mLastLen = 0; //上一次发送长度 private boolean isFirst = true; @@ -60,6 +61,10 @@ class BaseListener> sendInState2Target(ISchedulers.POST_PRE); } + @Override public void supportBreakpoint(boolean support) { + + } + @Override public void onStart(long startLocation) { saveData(IEntity.STATE_RUNNING, startLocation); sendInState2Target(ISchedulers.START); diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java index f710c50f..1836393d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java @@ -27,10 +27,7 @@ import com.arialyy.aria.orm.Primary; * 下载实体 */ public class DownloadEntity extends AbsNormalEntity implements Parcelable { - private String downloadUrl = ""; //下载路径 @Primary private String downloadPath = ""; //保存路径 - private boolean isRedirect = false; //是否重定向 - private String redirectUrl = ""; //重定向链接 /** * 所属任务组 @@ -54,40 +51,12 @@ public class DownloadEntity extends AbsNormalEntity implements Parcelable { private String serverFileName = ""; @Override public String getKey() { - return downloadUrl; + return getUrl(); } public DownloadEntity() { } - @Override public String toString() { - return "DownloadEntity{" - + "downloadUrl='" - + downloadUrl - + '\'' - + ", downloadPath='" - + downloadPath - + '\'' - + ", isRedirect=" - + isRedirect - + ", redirectUrl='" - + redirectUrl - + '\'' - + ", groupName='" - + groupName - + '\'' - + ", md5Code='" - + md5Code - + '\'' - + ", disposition='" - + disposition - + '\'' - + ", serverFileName='" - + serverFileName - + '\'' - + '}'; - } - public String getMd5Code() { return md5Code; } @@ -120,13 +89,11 @@ public class DownloadEntity extends AbsNormalEntity implements Parcelable { this.groupName = groupName; } - public String getDownloadUrl() { - return downloadUrl; - } - - public DownloadEntity setDownloadUrl(String downloadUrl) { - this.downloadUrl = downloadUrl; - return this; + /** + * @see {@link #getUrl()} + */ + @Deprecated public String getDownloadUrl() { + return getUrl(); } public String getDownloadPath() { @@ -142,44 +109,42 @@ public class DownloadEntity extends AbsNormalEntity implements Parcelable { return (DownloadEntity) super.clone(); } - public boolean isRedirect() { - return isRedirect; - } - - public void setRedirect(boolean redirect) { - isRedirect = redirect; - } - - public String getRedirectUrl() { - return redirectUrl; - } - - public void setRedirectUrl(String redirectUrl) { - this.redirectUrl = redirectUrl; - } - @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); - dest.writeString(this.downloadUrl); dest.writeString(this.downloadPath); - dest.writeByte(this.isRedirect ? (byte) 1 : (byte) 0); - dest.writeString(this.redirectUrl); dest.writeString(this.groupName); dest.writeString(this.md5Code); dest.writeString(this.disposition); dest.writeString(this.serverFileName); } + @Override public String toString() { + return "DownloadEntity{" + + "downloadPath='" + + downloadPath + + '\'' + + ", groupName='" + + groupName + + '\'' + + ", md5Code='" + + md5Code + + '\'' + + ", disposition='" + + disposition + + '\'' + + ", serverFileName='" + + serverFileName + + '\'' + + '}'; + } + protected DownloadEntity(Parcel in) { super(in); - this.downloadUrl = in.readString(); this.downloadPath = in.readString(); - this.isRedirect = in.readByte() != 0; - this.redirectUrl = in.readString(); this.groupName = in.readString(); this.md5Code = in.readString(); this.disposition = in.readString(); diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java index a6bd0452..a165c564 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java @@ -19,7 +19,7 @@ import android.os.Handler; import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.download.downloader.DownloadGroupUtil; import com.arialyy.aria.core.download.downloader.FtpDirDownloadUtil; -import com.arialyy.aria.core.download.downloader.IDownloadUtil; +import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.inf.AbsGroupTask; import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.scheduler.ISchedulers; @@ -32,7 +32,7 @@ import com.arialyy.aria.util.CheckUtil; public class DownloadGroupTask extends AbsGroupTask { private final String TAG = "DownloadGroupTask"; private DownloadGroupListener mListener; - private IDownloadUtil mUtil; + private IUtil mUtil; private DownloadGroupTask(DownloadGroupTaskEntity taskEntity, Handler outHandler) { mTaskEntity = taskEntity; @@ -51,29 +51,29 @@ public class DownloadGroupTask extends AbsGroupTask { protected String url; DownloadTarget(DownloadEntity entity, String targetName) { - this(entity.getDownloadUrl(), targetName); + this(entity.getUrl(), targetName); } DownloadTarget(String url, String targetName) { @@ -60,11 +60,11 @@ public class DownloadTarget */ private DownloadEntity getEntity(String downloadUrl) { DownloadEntity entity = - DownloadEntity.findFirst(DownloadEntity.class, "downloadUrl=? and isGroupChild='false'", + DownloadEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl); if (entity == null) { entity = new DownloadEntity(); - entity.setDownloadUrl(downloadUrl); + entity.setUrl(downloadUrl); entity.setGroupChild(false); entity.save(); } @@ -93,7 +93,7 @@ public class DownloadTarget * 下载任务是否存在 */ @Override public boolean taskExists() { - return DownloadTaskQueue.getInstance().getTask(mEntity.getDownloadUrl()) != null; + return DownloadTaskQueue.getInstance().getTask(mEntity.getUrl()) != null; } /** diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java index e82864a0..1954f9c9 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java @@ -19,7 +19,7 @@ package com.arialyy.aria.core.download; import android.os.Handler; import android.util.Log; import com.arialyy.aria.core.AriaManager; -import com.arialyy.aria.core.download.downloader.IDownloadUtil; +import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.download.downloader.SimpleDownloadUtil; import com.arialyy.aria.core.inf.AbsNormalTask; import com.arialyy.aria.core.inf.IEntity; @@ -34,7 +34,7 @@ public class DownloadTask extends AbsNormalTask { public static final String TAG = "DownloadTask"; private DownloadListener mListener; - private IDownloadUtil mUtil; + private IUtil mUtil; private DownloadTask(DownloadTaskEntity taskEntity, Handler outHandler) { mEntity = taskEntity.getEntity(); @@ -63,11 +63,11 @@ public class DownloadTask extends AbsNormalTask { * @see DownloadTask#getKey() */ @Deprecated public String getDownloadUrl() { - return mEntity.getDownloadUrl(); + return mEntity.getUrl(); } @Override public String getKey() { - return getDownloadUrl(); + return mEntity.getUrl(); } /** @@ -76,7 +76,7 @@ public class DownloadTask extends AbsNormalTask { * @see DownloadTask#isRunning() */ @Deprecated public boolean isDownloading() { - return mUtil.isDownloading(); + return mUtil.isRunning(); } @Override public boolean isRunning() { @@ -108,10 +108,10 @@ public class DownloadTask extends AbsNormalTask { */ @Override public void start() { mListener.isWait = false; - if (mUtil.isDownloading()) { + if (mUtil.isRunning()) { Log.d(TAG, "任务正在下载"); } else { - mUtil.startDownload(); + mUtil.start(); } } @@ -124,8 +124,8 @@ public class DownloadTask extends AbsNormalTask { private void stop(boolean isWait) { mListener.isWait = isWait; - if (mUtil.isDownloading()) { - mUtil.stopDownload(); + if (mUtil.isRunning()) { + mUtil.stop(); } else { mEntity.setState(isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP); mEntity.update(); @@ -140,12 +140,12 @@ public class DownloadTask extends AbsNormalTask { */ @Override public void cancel() { if (!mEntity.isComplete()) { - if (!mUtil.isDownloading()) { + if (!mUtil.isRunning()) { if (mOutHandler != null) { mOutHandler.obtainMessage(ISchedulers.CANCEL, this).sendToTarget(); } } - mUtil.cancelDownload(); + mUtil.cancel(); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsFtpInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsFtpInfoThread.java index 7bcc4f05..b20909c7 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsFtpInfoThread.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsFtpInfoThread.java @@ -18,6 +18,7 @@ package com.arialyy.aria.core.download.downloader; import android.text.TextUtils; import android.util.Log; import com.arialyy.aria.core.AriaManager; +import com.arialyy.aria.core.common.AbsThreadTask; import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.util.CommonUtil; @@ -80,7 +81,7 @@ abstract class AbsFtpInfoThread mTask = new SparseArray<>(); - - /** - * 小于1m的文件不启用多线程 - */ - private static final long SUB_LEN = 1024 * 1024; - private Timer mTimer; +class Downloader extends AbsFileer { Downloader(IDownloadListener listener, DownloadTaskEntity taskEntity) { - mListener = listener; - mTaskEntity = taskEntity; - mEntity = mTaskEntity.getEntity(); - mContext = AriaManager.APP; - mConstance = new StateConstance(); - } - - @Override public void setMaxSpeed(double maxSpeed) { - for (int i = 0; i < mThreadNum; i++) { - AbsThreadTask task = mTask.get(i); - if (task != null) { - task.setMaxSpeed(maxSpeed); - } - } - } - - public StateConstance getConstance() { - return mConstance; - } - - @Override public void run() { - startFlow(); - } - - /** - * 开始下载流程 - */ - private void startFlow() { - checkTask(); - mListener.onPostPre(mEntity.getFileSize()); - mConstance.cleanState(); - mConstance.isDownloading = true; - if (!mTaskEntity.isSupportBP) { - mThreadNum = 1; - mConstance.THREAD_NUM = mThreadNum; - handleNoSupportBreakpointDownload(); - } else { - mThreadNum = isNewTask ? ( - mEntity.getFileSize() <= SUB_LEN || mTaskEntity.requestType == AbsTaskEntity.FTP_DIR ? 1 - : AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum()) - : mRealThreadNum; - mConstance.THREAD_NUM = mThreadNum; - mFixedThreadPool = Executors.newFixedThreadPool(mThreadNum); - handleBreakpoint(); - } - startTimer(); - } - - /** - * 启动进度获取定时器 - */ - private void startTimer() { - mTimer = new Timer(true); - mTimer.schedule(new TimerTask() { - @Override public void run() { - if (mConstance.isComplete() || !mConstance.isDownloading) { - closeTimer(); - } else if (mConstance.CURRENT_LOCATION >= 0) { - mListener.onProgress(mConstance.CURRENT_LOCATION); - } - } - }, 0, 1000); - } - - private void closeTimer() { - if (mTimer != null) { - mTimer.purge(); - mTimer.cancel(); - } - } - - @Override public long getFileSize() { - return mEntity.getFileSize(); - } - - /** - * 获取当前下载位置 - */ - @Override public long getCurrentLocation() { - return mConstance.CURRENT_LOCATION; - } - - @Override public boolean isDownloading() { - return mConstance.isDownloading; - } - - @Override public void cancelDownload() { - closeTimer(); - mConstance.isCancel = true; - mConstance.isDownloading = false; - if (mFixedThreadPool != null) { - mFixedThreadPool.shutdown(); - } - for (int i = 0; i < mThreadNum; i++) { - AbsThreadTask task = mTask.get(i); - if (task != null) { - task.cancel(); - } - } - CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, mTaskEntity); - } - - @Override public void stopDownload() { - closeTimer(); - if (mConstance.isComplete()) return; - mConstance.isStop = true; - mConstance.isDownloading = false; - if (mFixedThreadPool != null) { - mFixedThreadPool.shutdown(); - } - for (int i = 0; i < mThreadNum; i++) { - AbsThreadTask task = mTask.get(i); - if (task != null) { - task.stop(); - } - } - } - - /** - * 直接调用的时候会自动启动线程执行 - */ - @Override public void startDownload() { - new Thread(this).start(); - } - - @Override public void resumeDownload() { - startDownload(); - } - - /** - * 返回该下载器的 - */ - public IDownloadListener getListener() { - return mListener; + super(listener, taskEntity); } - /** - * 检查任务是否是新任务,新任务条件: - * 1、文件不存在 - * 2、下载记录文件不存在 - * 3、下载记录文件缺失或不匹配 - * 4、数据库记录不存在 - * 5、不支持断点,则是新任务 - */ - private void checkTask() { + @Override protected void checkTask() { if (!mTaskEntity.isSupportBP) { isNewTask = true; return; @@ -218,7 +54,7 @@ class Downloader implements Runnable, IDownloadUtil { CommonUtil.createFile(mConfigFile.getPath()); } else if (!mTempFile.exists()) { isNewTask = true; - } else if (DbEntity.findFirst(DownloadEntity.class, "downloadUrl=?", mEntity.getDownloadUrl()) + } else if (DbEntity.findFirst(DownloadEntity.class, "url=?", mEntity.getDownloadUrl()) == null) { isNewTask = true; } else { @@ -226,156 +62,16 @@ class Downloader implements Runnable, IDownloadUtil { } } - /** - * 检查记录文件,如果是新任务返回{@code true},否则返回{@code false} - */ - private boolean checkConfigFile() { - Properties pro = CommonUtil.loadConfig(mConfigFile); - if (pro.isEmpty()) { - return true; - } - Set keys = pro.keySet(); - int num = 0; - for (Object key : keys) { - if (String.valueOf(key).contains("_record_")) { - num++; - } - } - if (num == 0) { - return true; - } - mRealThreadNum = num; - for (int i = 0; i < mRealThreadNum; i++) { - if (pro.getProperty(mTempFile.getName() + "_record_" + i) == null) { - Object state = pro.getProperty(mTempFile.getName() + "_state_" + i); - if (state != null && Integer.parseInt(state + "") == 1) { - continue; - } - return true; - } - } - return false; - } - - /** - * 恢复记录地址 - * - * @return true 表示下载完成 - */ - private boolean resumeRecordLocation(int i, long startL, long endL) { - mConstance.CURRENT_LOCATION += endL - startL; - Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++"); - mConstance.COMPLETE_THREAD_NUM++; - mConstance.STOP_NUM++; - mConstance.CANCEL_NUM++; - if (mConstance.isComplete()) { - if (mConfigFile.exists()) { - mConfigFile.delete(); - } - mListener.onComplete(); - mConstance.isDownloading = false; - return true; - } - return false; - } - - /** - * 创建单线程任务 - */ - private void addSingleTask(int i, long startL, long endL, long fileLength) { - SubThreadConfig config = new SubThreadConfig(); - config.FILE_SIZE = fileLength; - config.DOWNLOAD_URL = - mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getDownloadUrl(); - config.TEMP_FILE = mTempFile; - config.THREAD_ID = i; - config.START_LOCATION = startL; - config.END_LOCATION = endL; - config.CONFIG_FILE_PATH = mConfigFile.getPath(); - config.IS_SUPPORT_BREAK_POINT = mTaskEntity.isSupportBP; - config.DOWNLOAD_TASK_ENTITY = mTaskEntity; - AbsThreadTask task = createThreadTask(config); - if (task == null) return; - mTask.put(i, task); - } - - /** - * 启动单线程下载任务 - */ - private void startSingleTask(int[] recordL) { - if (mConstance.CURRENT_LOCATION > 0) { - mListener.onResume(mConstance.CURRENT_LOCATION); - } else { - mListener.onStart(mConstance.CURRENT_LOCATION); - } - mFixedThreadPool = Executors.newFixedThreadPool(recordL.length); - for (int l : recordL) { - if (l == -1) continue; - Runnable task = mTask.get(l); - if (task != null) { - mFixedThreadPool.execute(task); - } - } - } - - /** - * 处理断点 - */ - private void handleBreakpoint() { - long fileLength = mEntity.getFileSize(); - Properties pro = CommonUtil.loadConfig(mConfigFile); - int blockSize = (int) (fileLength / mThreadNum); - int[] recordL = new int[mThreadNum]; - for (int i = 0; i < mThreadNum; i++) { - recordL[i] = -1; - } - int rl = 0; - if (isNewTask) { - createNewFile(fileLength); - } - for (int i = 0; i < mThreadNum; i++) { - long startL = i * blockSize, endL = (i + 1) * blockSize; - Object state = pro.getProperty(mTempFile.getName() + "_state_" + i); - if (state != null && Integer.parseInt(state + "") == 1) { //该线程已经完成 - if (resumeRecordLocation(i, startL, endL)) return; - continue; - } - //分配下载位置 - Object record = pro.getProperty(mTempFile.getName() + "_record_" + i); - //如果有记录,则恢复下载 - if (!isNewTask && record != null && Long.parseLong(record + "") >= 0) { - Long r = Long.parseLong(record + ""); - mConstance.CURRENT_LOCATION += r - startL; - Log.d(TAG, "任务【" + mEntity.getFileName() + "】线程__" + i + "__恢复下载"); - startL = r; - recordL[rl] = i; - rl++; - } else { - recordL[rl] = i; - rl++; - } - if (i == (mThreadNum - 1)) { - //最后一个线程的结束位置即为文件的总长度 - endL = fileLength; - } - addSingleTask(i, startL, endL, fileLength); - } - startSingleTask(recordL); - } - - /** - * 创建新的下载文件 - */ - private void createNewFile(long fileLength) { + @Override protected void handleNewTask() { CommonUtil.createFile(mTempFile.getPath()); BufferedRandomAccessFile file = null; try { file = new BufferedRandomAccessFile(new File(mTempFile.getPath()), "rwd", 8192); //设置文件长度 - file.setLength(fileLength); + file.setLength(mEntity.getFileSize()); } catch (IOException e) { failDownload("下载失败【downloadUrl:" - + mEntity.getDownloadUrl() + + mEntity.getUrl() + "】\n【filePath:" + mEntity.getDownloadPath() + "】\n" @@ -391,45 +87,14 @@ class Downloader implements Runnable, IDownloadUtil { } } - /** - * 处理不支持断点的下载 - */ - private void handleNoSupportBreakpointDownload() { - SubThreadConfig config = new SubThreadConfig(); - long len = mEntity.getFileSize(); - config.FILE_SIZE = len; - config.DOWNLOAD_URL = - mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getDownloadUrl(); - config.TEMP_FILE = mTempFile; - config.THREAD_ID = 0; - config.START_LOCATION = 0; - config.END_LOCATION = config.FILE_SIZE; - config.CONFIG_FILE_PATH = mConfigFile.getPath(); - config.IS_SUPPORT_BREAK_POINT = mTaskEntity.isSupportBP; - config.DOWNLOAD_TASK_ENTITY = mTaskEntity; - AbsThreadTask task = createThreadTask(config); - if (task == null) return; - mTask.put(0, task); - mFixedThreadPool.execute(task); - mListener.onPostPre(len); - mListener.onStart(0); - } - - private AbsThreadTask createThreadTask(SubThreadConfig config) { + @Override protected AbsThreadTask selectThreadTask(SubThreadConfig config) { switch (mTaskEntity.requestType) { case AbsTaskEntity.FTP: case AbsTaskEntity.FTP_DIR: - return new FtpThreadTask(mConstance, mListener, config); + return new FtpThreadTask(mConstance, (IDownloadListener) mListener, config); case AbsTaskEntity.HTTP: - return new HttpThreadTask(mConstance, mListener, config); + return new HttpThreadTask(mConstance, (IDownloadListener) mListener, config); } return null; } - - private void failDownload(String errorMsg) { - closeTimer(); - Log.e(TAG, errorMsg); - mConstance.isDownloading = false; - mListener.onFail(); - } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java index a81073f0..9c5c7ce8 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java @@ -32,17 +32,17 @@ public class FtpDirDownloadUtil extends AbsGroupUtil { @Override protected void onStart() { super.onStart(); if (mTaskEntity.getEntity().getFileSize() > 1) { - start(); + startDownload(); } else { new FtpDirInfoThread(mTaskEntity, new OnFileInfoCallback() { @Override public void onComplete(String url, int code) { if (code >= 200 && code < 300) { mTotalSize = mTaskEntity.getEntity().getFileSize(); for (DownloadEntity entity : mTaskEntity.entity.getSubTask()) { - mExeMap.put(entity.getDownloadUrl(), createChildDownloadTask(entity)); + mExeMap.put(entity.getUrl(), createChildDownloadTask(entity)); } mActualTaskNum = mTaskEntity.entity.getSubTask().size(); - start(); + startDownload(); } } @@ -53,7 +53,7 @@ public class FtpDirDownloadUtil extends AbsGroupUtil { } } - private void start() { + private void startDownload() { int i = 0; Set keys = mExeMap.keySet(); for (String key : keys) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java index 709e7d32..963639de 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java @@ -47,7 +47,7 @@ class FtpDirInfoThread extends AbsFtpInfoThread { private final String TAG = "FtpThreadTask"; FtpThreadTask(StateConstance constance, IDownloadListener listener, - SubThreadConfig downloadInfo) { + SubThreadConfig downloadInfo) { super(constance, listener, downloadInfo); } @@ -51,7 +57,7 @@ class FtpThreadTask extends AbsThreadTask { + ",结束位置:" + mConfig.END_LOCATION + "】"); - String url = mEntity.getDownloadUrl(); + String url = mEntity.getUrl(); String[] pp = url.split("/")[2].split(":"); String serverIp = pp[0]; int port = Integer.parseInt(pp[1]); @@ -66,7 +72,7 @@ class FtpThreadTask extends AbsThreadTask { int reply = client.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { client.disconnect(); - failDownload(STATE.CURRENT_LOCATION, "无法连接到ftp服务器,错误码为:" + reply, null); + fail(STATE.CURRENT_LOCATION, "无法连接到ftp服务器,错误码为:" + reply, null); return; } String charSet = "UTF-8"; @@ -82,12 +88,12 @@ class FtpThreadTask extends AbsThreadTask { client.setRestartOffset(mConfig.START_LOCATION); client.allocate(mBufSize); is = client.retrieveFileStream( - new String(remotePath.getBytes(charSet), ConnectionHelp.SERVER_CHARSET)); + new String(remotePath.getBytes(charSet), SERVER_CHARSET)); //发送第二次指令时,还需要再做一次判断 reply = client.getReplyCode(); if (!FTPReply.isPositivePreliminary(reply)) { client.disconnect(); - failDownload(mChildCurrentLocation, "获取文件信息错误,错误码为:" + reply, null); + fail(mChildCurrentLocation, "获取文件信息错误,错误码为:" + reply, null); return; } file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize); @@ -119,13 +125,13 @@ class FtpThreadTask extends AbsThreadTask { if (configFile.exists()) { configFile.delete(); } - STATE.isDownloading = false; + STATE.isRunning = false; mListener.onComplete(); } } catch (IOException e) { - failDownload(mChildCurrentLocation, "下载失败【" + mConfig.DOWNLOAD_URL + "】", e); + fail(mChildCurrentLocation, "下载失败【" + mConfig.URL + "】", e); } catch (Exception e) { - failDownload(mChildCurrentLocation, "获取流失败", e); + fail(mChildCurrentLocation, "获取流失败", e); } finally { try { if (file != null) { 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 8fe2c54a..a2387ae7 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 @@ -49,7 +49,7 @@ class HttpFileInfoThread implements Runnable { @Override public void run() { HttpURLConnection conn = null; try { - URL url = new URL(mEntity.getDownloadUrl()); + URL url = new URL(mEntity.getUrl()); conn = ConnectionHelp.handleConnection(url); conn = ConnectionHelp.setConnectParam(mTaskEntity, conn); conn.setRequestProperty("Range", "bytes=" + 0 + "-"); @@ -58,7 +58,7 @@ class HttpFileInfoThread implements Runnable { handleConnect(conn); } catch (IOException e) { failDownload("下载失败【downloadUrl:" - + mEntity.getDownloadUrl() + + mEntity.getUrl() + "】\n【filePath:" + mEntity.getDownloadPath() + "】\n" @@ -103,7 +103,7 @@ class HttpFileInfoThread implements Runnable { mTaskEntity.isSupportBP = false; isComplete = true; } else if (code == HttpURLConnection.HTTP_NOT_FOUND) { - failDownload("任务【" + mEntity.getDownloadUrl() + "】下载失败,错误码:404"); + failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:404"); } else if (code == HttpURLConnection.HTTP_MOVED_TEMP || code == HttpURLConnection.HTTP_MOVED_PERM || code == HttpURLConnection.HTTP_SEE_OTHER) { @@ -112,11 +112,11 @@ class HttpFileInfoThread implements Runnable { mEntity.setRedirectUrl(mTaskEntity.redirectUrl); handle302Turn(conn); } else { - failDownload("任务【" + mEntity.getDownloadUrl() + "】下载失败,错误码:" + code); + failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:" + code); } if (isComplete) { if (onFileInfoListener != null) { - onFileInfoListener.onComplete(mEntity.getDownloadUrl(), code); + onFileInfoListener.onComplete(mEntity.getUrl(), code); } mEntity.update(); mTaskEntity.update(); @@ -131,7 +131,7 @@ class HttpFileInfoThread implements Runnable { Log.d(TAG, "30x跳转,location【 " + mTaskEntity.redirectUrlKey + "】" + "新url为【" + newUrl + "】"); if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null")) { if (onFileInfoListener != null) { - onFileInfoListener.onFail(mEntity.getDownloadUrl(), "获取重定向链接失败"); + onFileInfoListener.onFail(mEntity.getUrl(), "获取重定向链接失败"); } return; } @@ -154,7 +154,7 @@ class HttpFileInfoThread implements Runnable { */ private boolean checkLen(long len) { if (len < 0) { - failDownload("任务【" + mEntity.getDownloadUrl() + "】下载失败,文件长度小于0"); + failDownload("任务【" + mEntity.getUrl() + "】下载失败,文件长度小于0"); return false; } return true; @@ -163,7 +163,7 @@ class HttpFileInfoThread implements Runnable { private void failDownload(String errorMsg) { Log.e(TAG, errorMsg); if (onFileInfoListener != null) { - onFileInfoListener.onFail(mEntity.getDownloadUrl(), errorMsg); + onFileInfoListener.onFail(mEntity.getUrl(), errorMsg); } } } \ No newline at end of file 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 953e2943..09d76523 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 @@ -16,6 +16,12 @@ package com.arialyy.aria.core.download.downloader; import android.util.Log; +import com.arialyy.aria.core.common.AbsThreadTask; +import com.arialyy.aria.core.common.StateConstance; +import com.arialyy.aria.core.common.SubThreadConfig; +import com.arialyy.aria.core.download.DownloadEntity; +import com.arialyy.aria.core.download.DownloadTaskEntity; +import com.arialyy.aria.core.inf.IDownloadListener; import com.arialyy.aria.util.BufferedRandomAccessFile; import java.io.File; import java.io.IOException; @@ -28,11 +34,11 @@ import java.net.URL; * Created by lyy on 2017/1/18. * 下载线程 */ -final class HttpThreadTask extends AbsThreadTask { +final class HttpThreadTask extends AbsThreadTask { private final String TAG = "HttpThreadTask"; HttpThreadTask(StateConstance constance, IDownloadListener listener, - SubThreadConfig downloadInfo) { + SubThreadConfig downloadInfo) { super(constance, listener, downloadInfo); } @@ -41,9 +47,9 @@ final class HttpThreadTask extends AbsThreadTask { InputStream is = null; BufferedRandomAccessFile file = null; try { - URL url = new URL(mConfig.DOWNLOAD_URL); + URL url = new URL(mConfig.URL); conn = ConnectionHelp.handleConnection(url); - if (mConfig.IS_SUPPORT_BREAK_POINT) { + if (mConfig.SUPPORT_BP) { Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" @@ -59,7 +65,7 @@ final class HttpThreadTask extends AbsThreadTask { } else { Log.w(TAG, "该下载不支持断点"); } - conn = ConnectionHelp.setConnectParam(mConfig.DOWNLOAD_TASK_ENTITY, conn); + conn = ConnectionHelp.setConnectParam(mConfig.TASK_ENTITY, conn); conn.setConnectTimeout(STATE.CONNECT_TIME_OUT); conn.setReadTimeout(STATE.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数 is = conn.getInputStream(); @@ -80,7 +86,7 @@ final class HttpThreadTask extends AbsThreadTask { } if (STATE.isCancel || STATE.isStop) return; //支持断点的处理 - if (mConfig.IS_SUPPORT_BREAK_POINT) { + if (mConfig.SUPPORT_BP) { Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕"); writeConfig(true, 1); STATE.COMPLETE_THREAD_NUM++; @@ -89,20 +95,20 @@ final class HttpThreadTask extends AbsThreadTask { if (configFile.exists()) { configFile.delete(); } - STATE.isDownloading = false; + STATE.isRunning = false; mListener.onComplete(); } } else { Log.i(TAG, "下载任务完成"); - STATE.isDownloading = false; + STATE.isRunning = false; mListener.onComplete(); } } catch (MalformedURLException e) { - failDownload(mChildCurrentLocation, "下载链接异常", e); + fail(mChildCurrentLocation, "下载链接异常", e); } catch (IOException e) { - failDownload(mChildCurrentLocation, "下载失败【" + mConfig.DOWNLOAD_URL + "】", e); + fail(mChildCurrentLocation, "下载失败【" + mConfig.URL + "】", e); } catch (Exception e) { - failDownload(mChildCurrentLocation, "获取流失败", e); + fail(mChildCurrentLocation, "获取流失败", e); } finally { try { if (file != null) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadGroupListener.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadGroupListener.java index 2b0f130f..e0b0695f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadGroupListener.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadGroupListener.java @@ -16,13 +16,14 @@ package com.arialyy.aria.core.download.downloader; import com.arialyy.aria.core.download.DownloadEntity; +import com.arialyy.aria.core.inf.IDownloadListener; import com.arialyy.aria.core.inf.IEventListener; /** * Created by Aria.Lao on 2017/7/20. * 下载任务组事件 */ -public interface IDownloadGroupListener extends IEventListener { +public interface IDownloadGroupListener extends IDownloadListener { /** * 子任务支持断点回调 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 cfe0b559..59776071 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 @@ -17,68 +17,70 @@ package com.arialyy.aria.core.download.downloader; import android.util.Log; +import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity; +import com.arialyy.aria.core.inf.IDownloadListener; /** * Created by lyy on 2015/8/25. * HTTP单任务下载工具 */ -public class SimpleDownloadUtil implements IDownloadUtil, Runnable { +public class SimpleDownloadUtil implements IUtil, Runnable { private static final String TAG = "SimpleDownloadUtil"; private IDownloadListener mListener; - private Downloader mDT; + private Downloader mDownloader; private DownloadTaskEntity mTaskEntity; public SimpleDownloadUtil(DownloadTaskEntity entity, IDownloadListener downloadListener) { mTaskEntity = entity; mListener = downloadListener; - mDT = new Downloader(downloadListener, entity); + mDownloader = new Downloader(downloadListener, entity); } @Override public long getFileSize() { - return mDT.getFileSize(); + return mDownloader.getFileSize(); } /** * 获取当前下载位置 */ @Override public long getCurrentLocation() { - return mDT.getCurrentLocation(); + return mDownloader.getCurrentLocation(); } - @Override public boolean isDownloading() { - return mDT.isDownloading(); + @Override public boolean isRunning() { + return mDownloader.isRunning(); } /** * 取消下载 */ - @Override public void cancelDownload() { - mDT.cancelDownload(); + @Override public void cancel() { + mDownloader.cancel(); } /** * 停止下载 */ - @Override public void stopDownload() { - mDT.stopDownload(); + @Override public void stop() { + mDownloader.stop(); } /** * 多线程断点续传下载文件,开始下载 */ - @Override public void startDownload() { + @Override public void start() { mListener.onPre(); new Thread(this).start(); } - @Override public void resumeDownload() { - startDownload(); + @Override public void resume() { + start(); } public void setMaxSpeed(double maxSpeed) { - mDT.setMaxSpeed(maxSpeed); + mDownloader.setMaxSpeed(maxSpeed); } private void failDownload(String msg) { @@ -90,7 +92,7 @@ public class SimpleDownloadUtil implements IDownloadUtil, Runnable { if (mTaskEntity.getEntity().getFileSize() <= 1) { new Thread(createInfoThread()).start(); } else { - mDT.startDownload(); + mDownloader.start(); } } @@ -102,7 +104,7 @@ public class SimpleDownloadUtil implements IDownloadUtil, Runnable { case AbsTaskEntity.FTP: return new FtpFileInfoThread(mTaskEntity, new OnFileInfoCallback() { @Override public void onComplete(String url, int code) { - mDT.startDownload(); + mDownloader.start(); } @Override public void onFail(String url, String errorMsg) { @@ -112,7 +114,7 @@ public class SimpleDownloadUtil implements IDownloadUtil, Runnable { case AbsTaskEntity.HTTP: return new HttpFileInfoThread(mTaskEntity, new OnFileInfoCallback() { @Override public void onComplete(String url, int code) { - mDT.startDownload(); + mDownloader.start(); } @Override public void onFail(String url, String errorMsg) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SubThreadConfig.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SubThreadConfig.java deleted file mode 100644 index f833474c..00000000 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SubThreadConfig.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.arialyy.aria.core.download.downloader; - -import com.arialyy.aria.core.download.DownloadTaskEntity; -import java.io.File; -import org.apache.commons.net.ftp.FTPClient; - -/** - * 子线程下载信息类 - */ -class SubThreadConfig { - //线程Id - int THREAD_ID; - //下载文件大小 - long FILE_SIZE; - //子线程启动下载位置 - long START_LOCATION; - //子线程结束下载位置 - long END_LOCATION; - //下载路径 - File TEMP_FILE; - String DOWNLOAD_URL; - String CONFIG_FILE_PATH; - DownloadTaskEntity DOWNLOAD_TASK_ENTITY; - boolean IS_SUPPORT_BREAK_POINT = true; -} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java index d1425f7f..5f03f29a 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java @@ -25,6 +25,11 @@ import com.arialyy.aria.orm.Ignore; */ public abstract class AbsNormalEntity extends AbsEntity implements Parcelable { + /** + * 服务器地址 + */ + private String url = ""; + /** * 文件名 */ @@ -35,6 +40,16 @@ public abstract class AbsNormalEntity extends AbsEntity implements Parcelable { */ private boolean isGroupChild = false; + private boolean isRedirect = false; //是否重定向 + private String redirectUrl = ""; //重定向链接 + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } public boolean isGroupChild() { return isGroupChild; @@ -52,6 +67,22 @@ public abstract class AbsNormalEntity extends AbsEntity implements Parcelable { this.fileName = fileName; } + public boolean isRedirect() { + return isRedirect; + } + + public void setRedirect(boolean redirect) { + isRedirect = redirect; + } + + public String getRedirectUrl() { + return redirectUrl; + } + + public void setRedirectUrl(String redirectUrl) { + this.redirectUrl = redirectUrl; + } + public AbsNormalEntity() { } @@ -61,13 +92,19 @@ public abstract class AbsNormalEntity extends AbsEntity implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); + dest.writeString(this.url); dest.writeString(this.fileName); dest.writeByte(this.isGroupChild ? (byte) 1 : (byte) 0); + dest.writeByte(this.isRedirect ? (byte) 1 : (byte) 0); + dest.writeString(this.redirectUrl); } protected AbsNormalEntity(Parcel in) { super(in); + this.url = in.readString(); this.fileName = in.readString(); this.isGroupChild = in.readByte() != 0; + this.isRedirect = in.readByte() != 0; + this.redirectUrl = in.readString(); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java index cc4be12c..c60d8be5 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java @@ -19,7 +19,7 @@ import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; import com.arialyy.aria.core.AriaManager; -import com.arialyy.aria.core.RequestEnum; +import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.command.normal.NormalCmdFactory; import com.arialyy.aria.util.CommonUtil; import java.util.Map; diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java index 29709aba..02048aa7 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java @@ -15,7 +15,7 @@ */ package com.arialyy.aria.core.inf; -import com.arialyy.aria.core.RequestEnum; +import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.Ignore; import com.arialyy.aria.orm.Primary; diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java index a5b6b141..ad4ddee3 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java @@ -37,8 +37,8 @@ public abstract class AbsUploadTarget CREATOR = new Creator() { diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadListener.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadListener.java index fa9cac78..3ef60eb3 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadListener.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadListener.java @@ -15,7 +15,7 @@ */ package com.arialyy.aria.core.upload; -import com.arialyy.aria.core.upload.uploader.IUploadListener; +import com.arialyy.aria.core.inf.IUploadListener; /** * Created by lyy on 2017/2/23. @@ -25,10 +25,6 @@ class UploadListener implements IUploadListener { } - @Override public void onPostPre(long fileSize) { - - } - @Override public void onStart(long startLocation) { } @@ -56,4 +52,8 @@ class UploadListener implements IUploadListener { @Override public void onFail() { } + + @Override public void onComplete(int state) { + + } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java index 9df0a8b9..8c7dfa16 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java @@ -17,7 +17,7 @@ package com.arialyy.aria.core.upload; import android.support.annotation.NonNull; import com.arialyy.aria.core.AriaManager; -import com.arialyy.aria.core.ProxyHelper; +import com.arialyy.aria.core.common.ProxyHelper; import com.arialyy.aria.core.command.normal.NormalCmdFactory; import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.inf.AbsReceiver; @@ -39,15 +39,25 @@ public class UploadReceiver extends AbsReceiver { public ISchedulerListener listener; /** - * 加载任务 + * 加载HTTP单文件上传任务 * - * @param filePath 文件地址 + * @param filePath 文件路径 */ public UploadTarget load(@NonNull String filePath) { CheckUtil.checkUploadPath(filePath); return new UploadTarget(filePath, targetName); } + /** + * 加载FTP单文件上传任务 + * + * @param filePath 文件路径 + */ + public FtpUploadTarget loadFtp(@NonNull String filePath) { + CheckUtil.checkUploadPath(filePath); + return new FtpUploadTarget(filePath, targetName); + } + /** * 通过上传路径获取上传实体 */ diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java index fb022b26..154226a4 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java @@ -20,6 +20,7 @@ import com.arialyy.aria.core.inf.AbsDownloadTarget; import com.arialyy.aria.core.inf.AbsUploadTarget; import com.arialyy.aria.core.queue.UploadTaskQueue; import com.arialyy.aria.orm.DbEntity; +import java.io.File; import java.util.regex.Pattern; /** @@ -38,7 +39,11 @@ public class UploadTarget extends AbsUploadTarget { + private final String TAG = "FtpThreadTask"; + private String remotePath, charSet; + + FtpThreadTask(StateConstance constance, IEventListener listener, + SubThreadConfig info) { + super(constance, listener, info); + } + + @Override public void run() { + FTPClient client = null; + OutputStream os = null; + BufferedRandomAccessFile file = null; + try { + Log.d(TAG, "任务【" + + mConfig.TEMP_FILE.getName() + + "】线程__" + + mConfig.THREAD_ID + + "__开始上传【开始位置 : " + + mConfig.START_LOCATION + + ",结束位置:" + + mConfig.END_LOCATION + + "】"); + //当前子线程的下载位置 + mChildCurrentLocation = mConfig.START_LOCATION; + client = createClient(); + if (client == null) return; + client.makeDirectory(remotePath); + client.changeWorkingDirectory(remotePath); + client.setRestartOffset(mConfig.START_LOCATION); + file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize); + file.seek(mConfig.START_LOCATION); + if (!isRemoteComplete(client)) { + os = client.storeFileStream(new String(remotePath.getBytes(charSet), SERVER_CHARSET)); + //发送第二次指令时,还需要再做一次判断 + int reply = client.getReplyCode(); + if (!FTPReply.isPositivePreliminary(reply)) { + client.disconnect(); + fail(mChildCurrentLocation, "上传文件错误,错误码为:" + reply, null); + return; + } + upload(file, os); + } + if (STATE.isCancel || STATE.isStop) return; + Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__上传完毕"); + writeConfig(true, 1); + STATE.COMPLETE_THREAD_NUM++; + if (STATE.isComplete()) { + File configFile = new File(mConfigFPath); + if (configFile.exists()) { + configFile.delete(); + } + STATE.isRunning = false; + mListener.onComplete(); + } + } catch (IOException e) { + fail(mChildCurrentLocation, "上传失败【" + mConfig.URL + "】", e); + } catch (Exception e) { + fail(mChildCurrentLocation, "获取流失败", e); + } finally { + try { + if (file != null) { + file.close(); + } + if (os != null) { + os.close(); + } + if (client != null && client.isConnected()) { + client.disconnect(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 远程文件是否已经玩飞车 + * + * @return true 任务已经完成 + */ + private boolean isRemoteComplete(FTPClient client) throws IOException { + FTPFile[] files = client.listFiles(new String(remotePath.getBytes(charSet), SERVER_CHARSET)); + return files.length != 0 && files[0].getSize() == mEntity.getFileSize(); + } + + /** + * 执行上传操作 + */ + private void upload(BufferedRandomAccessFile file, OutputStream os) + throws IOException, InterruptedException { + int len; + byte[] buffer = new byte[mBufSize]; + while ((len = file.read(buffer)) != -1) { + if (STATE.isCancel) break; + if (STATE.isStop) break; + if (mSleepTime > 0) Thread.sleep(mSleepTime); + if (mChildCurrentLocation + len >= mConfig.END_LOCATION) { + len = (int) (mConfig.END_LOCATION - mChildCurrentLocation); + os.write(buffer, 0, len); + progress(len); + break; + } else { + os.write(buffer, 0, len); + progress(len); + } + } + } + + /** + * 构建FTP客户端 + */ + private FTPClient createClient() throws IOException { + String url = mEntity.getUrl(); + String[] pp = url.split("/")[2].split(":"); + String serverIp = pp[0]; + int port = Integer.parseInt(pp[1]); + remotePath = url.substring(url.indexOf(pp[1]) + pp[1].length(), url.length()) + + "/" + + mEntity.getFileName(); + FTPClient client = new FTPClient(); + client.connect(serverIp, port); + if (!TextUtils.isEmpty(mTaskEntity.account)) { + client.login(mTaskEntity.userName, mTaskEntity.userPw); + } else { + client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account); + } + int reply = client.getReplyCode(); + if (!FTPReply.isPositiveCompletion(reply)) { + client.disconnect(); + fail(STATE.CURRENT_LOCATION, "无法连接到ftp服务器,错误码为:" + reply, null); + return null; + } + charSet = "UTF-8"; + // 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码 + if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion( + client.sendCommand("OPTS UTF8", "ON"))) { + charSet = mTaskEntity.charSet; + } + client.setControlEncoding(charSet); + client.setDataTimeout(STATE.READ_TIME_OUT); + client.enterLocalPassiveMode(); + client.setFileType(FTP.BINARY_FILE_TYPE); + client.allocate(mBufSize); + return client; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java similarity index 80% rename from Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java rename to Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java index 90bfc564..7a90b1da 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java @@ -13,11 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.core.upload; +package com.arialyy.aria.core.upload.uploader; import android.util.Log; -import com.arialyy.aria.core.upload.uploader.IUploadListener; -import com.arialyy.aria.util.CheckUtil; +import com.arialyy.aria.core.common.AbsThreadTask; +import com.arialyy.aria.core.common.StateConstance; +import com.arialyy.aria.core.common.SubThreadConfig; +import com.arialyy.aria.core.inf.IUploadListener; +import com.arialyy.aria.core.upload.UploadEntity; +import com.arialyy.aria.core.upload.UploadTaskEntity; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -33,55 +37,34 @@ import java.util.Set; import java.util.UUID; /** - * Created by lyy on 2017/2/9. - * 上传工具 + * Created by Aria.Lao on 2017/7/28. + * 不支持断点的HTTP上传任务 */ -final class UploadUtil implements Runnable { - private static final String TAG = "UploadUtil"; +class HttpThreadTask extends AbsThreadTask { + private final String TAG = "HttpThreadTask"; + private final String BOUNDARY = UUID.randomUUID().toString(); // 边界标识 随机生成 private final String PREFIX = "--", LINE_END = "\r\n"; - private UploadEntity mUploadEntity; - private UploadTaskEntity mTaskEntity; - private IUploadListener mListener; private HttpURLConnection mHttpConn; private long mCurrentLocation = 0; - private boolean isCancel = false; - private boolean isRunning = false; private OutputStream mOutputStream; - UploadUtil(UploadTaskEntity taskEntity, IUploadListener listener) { - mTaskEntity = taskEntity; - CheckUtil.checkTaskEntity(taskEntity); - mUploadEntity = taskEntity.getEntity(); - if (listener == null) { - throw new IllegalArgumentException("上传监听不能为空"); - } - mListener = listener; - } - - public void start() { - isCancel = false; - isRunning = false; - new Thread(this).start(); - } - - public void cancel() { - isCancel = true; - isRunning = false; + public HttpThreadTask(StateConstance constance, IUploadListener listener, + SubThreadConfig uploadInfo) { + super(constance, listener, uploadInfo); } @Override public void run() { - File uploadFile = new File(mUploadEntity.getFilePath()); + File uploadFile = new File(mEntity.getFilePath()); if (!uploadFile.exists()) { - Log.e(TAG, "【" + mUploadEntity.getFilePath() + "】,文件不存在。"); + Log.e(TAG, "【" + mEntity.getFilePath() + "】,文件不存在。"); fail(); return; } - mListener.onPre(); URL url; try { - url = new URL(mUploadEntity.getUploadUrl()); + url = new URL(mEntity.getUrl()); mHttpConn = (HttpURLConnection) url.openConnection(); mHttpConn.setUseCaches(false); mHttpConn.setDoOutput(true); @@ -98,13 +81,9 @@ final class UploadUtil implements Runnable { for (String key : keys) { mHttpConn.setRequestProperty(key, mTaskEntity.headers.get(key)); } - mOutputStream = mHttpConn.getOutputStream(); - mListener.onPostPre(uploadFile.length()); - PrintWriter writer = new PrintWriter(new OutputStreamWriter(mOutputStream, mTaskEntity.charSet), true); - //添加文件上传表单字段 keys = mTaskEntity.formFields.keySet(); for (String key : keys) { @@ -119,10 +98,6 @@ final class UploadUtil implements Runnable { } } - boolean isRunning() { - return isRunning; - } - private void fail() { try { mListener.onFail(); @@ -179,10 +154,9 @@ final class UploadUtil implements Runnable { while ((bytesRead = inputStream.read(buffer)) != -1) { mCurrentLocation += bytesRead; mOutputStream.write(buffer, 0, bytesRead); - if (isCancel) { + if (STATE.isCancel) { break; } - isRunning = true; mListener.onProgress(mCurrentLocation); } @@ -191,8 +165,7 @@ final class UploadUtil implements Runnable { inputStream.close(); writer.append(LINE_END); writer.flush(); - isRunning = false; - if (isCancel) { + if (STATE.isCancel) { mListener.onCancel(); return; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/IUploadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/IUploadUtil.java deleted file mode 100644 index 4e50862c..00000000 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/IUploadUtil.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.upload.uploader; - -/** - * Created by lyy on 2016/10/31. - * 抽象的下载接口 - */ -public interface IUploadUtil { - - /** - * 获取文件大小 - */ - long getFileSize(); - - /** - * 获取当前上传位置 - */ - long getCurrentLocation(); - - /** - * 是否正在下载 - * - * @return true, 正在下载 - */ - boolean isUploading(); - - /** - * 取消下载 - */ - void cancelUpload(); - - /** - * 停止下载 - */ - void stopUpload(); - - /** - * 开始下载 - */ - void startUpload(); - - /** - * 从上次断点恢复下载 - */ - void resumeUpload(); - - /** - * 设置最大下载速度 - */ - void setMaxSpeed(double maxSpeed); -} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/SimpleHttpUploadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/SimpleHttpUploadUtil.java new file mode 100644 index 00000000..00163397 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/SimpleHttpUploadUtil.java @@ -0,0 +1,82 @@ +/* + * 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.upload.uploader; + +import com.arialyy.aria.core.common.IUtil; +import com.arialyy.aria.core.inf.IUploadListener; +import com.arialyy.aria.core.upload.UploadEntity; +import com.arialyy.aria.core.upload.UploadTaskEntity; +import com.arialyy.aria.util.CheckUtil; + +/** + * Created by lyy on 2017/2/9. + * 简单的http文件上传工具 + */ +public class SimpleHttpUploadUtil implements IUtil, Runnable { + private static final String TAG = "SimpleHttpUploadUtil"; + + private UploadEntity mUploadEntity; + private UploadTaskEntity mTaskEntity; + private IUploadListener mListener; + private Uploader mUploader; + + public SimpleHttpUploadUtil(UploadTaskEntity taskEntity, IUploadListener listener) { + mTaskEntity = taskEntity; + CheckUtil.checkTaskEntity(taskEntity); + mUploadEntity = taskEntity.getEntity(); + if (listener == null) { + throw new IllegalArgumentException("上传监听不能为空"); + } + mListener = listener; + mUploader = new Uploader(mListener, taskEntity); + } + + @Override public void run() { + mUploader.start(); + } + + @Override public long getFileSize() { + return mUploader.getFileSize(); + } + + @Override public long getCurrentLocation() { + return mUploader.getCurrentLocation(); + } + + @Override public boolean isRunning() { + return mUploader.isRunning(); + } + + @Override public void cancel() { + mUploader.cancel(); + } + + @Override public void stop() { + mUploader.stop(); + } + + @Override public void start() { + mUploader.start(); + } + + @Override public void resume() { + mUploader.cancel(); + } + + @Override public void setMaxSpeed(double maxSpeed) { + mUploader.setMaxSpeed(maxSpeed); + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/Uploader.java b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/Uploader.java index aac8ab51..d09f5df4 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/Uploader.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/Uploader.java @@ -15,87 +15,73 @@ */ package com.arialyy.aria.core.upload.uploader; +import com.arialyy.aria.core.AriaManager; +import com.arialyy.aria.core.common.AbsFileer; +import com.arialyy.aria.core.common.AbsThreadTask; +import com.arialyy.aria.core.common.SubThreadConfig; +import com.arialyy.aria.core.inf.AbsTaskEntity; +import com.arialyy.aria.core.inf.IUploadListener; import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadTaskEntity; -import java.util.Timer; -import java.util.TimerTask; +import com.arialyy.aria.orm.DbEntity; +import com.arialyy.aria.util.CommonUtil; +import java.io.File; /** * Created by Aria.Lao on 2017/7/27. * 文件上传器 */ -public class Uploader implements Runnable, IUploadUtil { - - private IUploadListener mListener; - private UploadTaskEntity mTaskEntity; - private UploadEntity mEntity; - private long mCurrentLocation = 0; - - private Timer mTimer; - private boolean isRunning; +class Uploader extends AbsFileer { Uploader(IUploadListener listener, UploadTaskEntity taskEntity) { - mListener = listener; - mTaskEntity = taskEntity; - mEntity = mTaskEntity.getEntity(); - } - - @Override public long getFileSize() { - return mEntity.getFileSize(); - } - - @Override public long getCurrentLocation() { - return mCurrentLocation; - } - - @Override public boolean isUploading() { - return isRunning; - } - - @Override public void cancelUpload() { - isRunning = false; - } - - @Override public void stopUpload() { - isRunning = false; - } - - @Override public void startUpload() { - new Thread(this).start(); + super(listener, taskEntity); + mTempFile = new File(mEntity.getFilePath()); } - @Override public void resumeUpload() { - startUpload(); + /** + * 检查任务是否是新任务,新任务条件: + * 1、文件不存在 + * 2、记录文件不存在 + * 3、记录文件缺失或不匹配 + * 4、数据库记录不存在 + * 5、不支持断点,则是新任务 + */ + protected void checkTask() { + if (!mTaskEntity.isSupportBP) { + isNewTask = true; + return; + } + mConfigFile = new File(mContext.getFilesDir().getPath() + + AriaManager.UPLOAD_TEMP_DIR + + mEntity.getFileName() + + ".properties"); + if (!mConfigFile.exists()) { //记录文件被删除,则重新下载 + isNewTask = true; + CommonUtil.createFile(mConfigFile.getPath()); + } else if (DbEntity.findFirst(UploadEntity.class, "filePath=?", mEntity.getFilePath()) + == null) { + isNewTask = true; + } else { + isNewTask = checkConfigFile(); + } } - @Override public void setMaxSpeed(double maxSpeed) { - - } + @Override protected void handleNewTask() { - @Override public void run() { - isRunning = true; } - /** - * 启动进度获取定时器 - */ - private void startTimer() { - mTimer = new Timer(true); - mTimer.schedule(new TimerTask() { - @Override public void run() { - //if (mConstance.isComplete() || !mConstance.isDownloading) { - // closeTimer(); - //} else if (mConstance.CURRENT_LOCATION >= 0) { - // mListener.onProgress(mConstance.CURRENT_LOCATION); - //} - } - }, 0, 1000); + @Override protected int getThreadNum() { + return 1; } - private void closeTimer() { - if (mTimer != null) { - mTimer.purge(); - mTimer.cancel(); + @Override protected AbsThreadTask selectThreadTask(SubThreadConfig config) { + switch (mTaskEntity.requestType) { + case AbsTaskEntity.FTP: + case AbsTaskEntity.FTP_DIR: + return new FtpThreadTask(mConstance, mListener, config); + case AbsTaskEntity.HTTP: + return new HttpThreadTask(mConstance, (IUploadListener) mListener, config); } + return null; } } diff --git a/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java b/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java index ebb3aa33..745d2826 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java @@ -24,6 +24,7 @@ import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadTaskEntity; import com.arialyy.aria.exception.FileException; +import java.io.File; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -108,6 +109,8 @@ public class CheckUtil { */ 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("上传文件不存在"); } /** @@ -133,7 +136,7 @@ public class CheckUtil { DownloadEntity entity1 = ((DownloadTaskEntity) entity).getEntity(); if (entity1 == null) { Log.e(TAG, "下载实体不能为空"); - } else if (checkType && TextUtils.isEmpty(entity1.getDownloadUrl())) { + } else if (checkType && TextUtils.isEmpty(entity1.getUrl())) { Log.e(TAG, "下载链接不能为空"); } else if (checkType && TextUtils.isEmpty(entity1.getDownloadPath())) { Log.e(TAG, "保存路径不能为空"); @@ -175,7 +178,7 @@ public class CheckUtil { private static void checkDownloadTaskEntity(DownloadEntity entity) { if (entity == null) { throw new NullPointerException("下载实体不能为空"); - } else if (TextUtils.isEmpty(entity.getDownloadUrl())) { + } else if (TextUtils.isEmpty(entity.getUrl())) { throw new IllegalArgumentException("下载链接不能为空"); } else if (TextUtils.isEmpty(entity.getFileName())) { throw new FileException("文件名不能为null"); diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c00b5b85..e79b82bb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -34,6 +34,7 @@ + diff --git a/app/src/main/java/com/arialyy/simple/MainActivity.java b/app/src/main/java/com/arialyy/simple/MainActivity.java index 322ca334..50481142 100644 --- a/app/src/main/java/com/arialyy/simple/MainActivity.java +++ b/app/src/main/java/com/arialyy/simple/MainActivity.java @@ -26,7 +26,7 @@ import com.arialyy.simple.download.DownloadActivity; import com.arialyy.simple.download.FtpDownloadActivity; import com.arialyy.simple.download.group.DownloadGroupActivity; import com.arialyy.simple.download.group.FTPDirDownloadActivity; -import com.arialyy.simple.test.TestMutilTaskSysDownload; +import com.arialyy.simple.upload.FtpUploadActivity; import com.arialyy.simple.upload.UploadActivity; /** @@ -45,8 +45,10 @@ public class MainActivity extends BaseActivity { return R.layout.activity_main; } - @OnClick({ R.id.download, R.id.upload, R.id.download_task_group, R.id.ftp, R.id.ftp_dir }) - public void funcation(View view) { + @OnClick({ + R.id.download, R.id.upload, R.id.download_task_group, R.id.ftp_download, + R.id.ftp_dir_download, R.id.ftp_upload + }) public void funcation(View view) { switch (view.getId()) { case R.id.download: startActivity(new Intent(this, DownloadActivity.class)); @@ -57,12 +59,15 @@ public class MainActivity extends BaseActivity { case R.id.download_task_group: startActivity(new Intent(this, DownloadGroupActivity.class)); break; - case R.id.ftp: + case R.id.ftp_download: startActivity(new Intent(this, FtpDownloadActivity.class)); break; - case R.id.ftp_dir: + case R.id.ftp_dir_download: startActivity(new Intent(this, FTPDirDownloadActivity.class)); break; + case R.id.ftp_upload: + startActivity(new Intent(this, FtpUploadActivity.class)); + break; } } } diff --git a/app/src/main/java/com/arialyy/simple/download/DownloadModule.java b/app/src/main/java/com/arialyy/simple/download/DownloadModule.java index faef1cf3..c4e84c1a 100644 --- a/app/src/main/java/com/arialyy/simple/download/DownloadModule.java +++ b/app/src/main/java/com/arialyy/simple/download/DownloadModule.java @@ -76,7 +76,7 @@ public class DownloadModule extends BaseModule { String path = Environment.getExternalStorageDirectory() + "/download/" + name + ".apk"; DownloadEntity entity = new DownloadEntity(); entity.setFileName(name); - entity.setDownloadUrl(downloadUrl); + entity.setUrl(downloadUrl); entity.setDownloadPath(path); return entity; } diff --git a/app/src/main/java/com/arialyy/simple/download/HighestPriorityActivity.java b/app/src/main/java/com/arialyy/simple/download/HighestPriorityActivity.java index 611861dd..73cb28c4 100644 --- a/app/src/main/java/com/arialyy/simple/download/HighestPriorityActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/HighestPriorityActivity.java @@ -87,9 +87,9 @@ public class HighestPriorityActivity extends BaseActivity temp = Aria.download(this).getSimpleTaskList(); if (temp != null && !temp.isEmpty()) { for (DownloadEntity entity : temp) { - if (entity.getDownloadUrl().equals(DOWNLOAD_URL)) continue; + if (entity.getUrl().equals(DOWNLOAD_URL)) continue; mData.add(entity); - mRecord.add(entity.getDownloadUrl()); + mRecord.add(entity.getUrl()); } } mAdapter = new DownloadAdapter(this, mData); @@ -112,7 +112,7 @@ public class HighestPriorityActivity extends BaseActivity temp = getModule(DownloadModule.class).getHighestTestList(); for (DownloadEntity entity : temp) { - String url = entity.getDownloadUrl(); + String url = entity.getUrl(); if (mRecord.contains(url)) { continue; } diff --git a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java index 383d8ddc..710f3a79 100644 --- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java @@ -80,7 +80,7 @@ public class SingleTaskActivity extends BaseActivity { msg = "一些小知识点:\n" + "1、你可以在注解中增加链接,用于指定被注解的方法只能被特定的下载任务回调,以防止progress乱跳\n" + "2、当遇到网络慢的情况时,你可以先使用onPre()更新UI界面,待连接成功时,再在onTaskPre()获取完整的task数据,然后给UI界面设置正确的数据\n" - + "3、你可以在界面初始化时通过Aria.download(this).load(DOWNLOAD_URL).getPercent()等方法快速获取相关任务的一些数据"; + + "3、你可以在界面初始化时通过Aria.download(this).load(URL).getPercent()等方法快速获取相关任务的一些数据"; showMsgDialog("tip", msg); break; case R.id.speed_0: @@ -188,13 +188,13 @@ public class SingleTaskActivity extends BaseActivity { //String text = ((TextView) view).getText().toString(); //if (text.equals("重新开始?") || text.equals("开始")) { // Aria.download(this) - // .load(DOWNLOAD_URL) + // .load(URL) // .addHeader("groupName", "value") // .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk") // .setFileName("hehe.apk") // .start(); //} else if (text.equals("恢复")) { - // Aria.download(this).load(DOWNLOAD_URL).resume(); + // Aria.download(this).load(URL).resume(); //} Aria.download(this) .load(DOWNLOAD_URL) diff --git a/app/src/main/java/com/arialyy/simple/download/multi_download/DownloadAdapter.java b/app/src/main/java/com/arialyy/simple/download/multi_download/DownloadAdapter.java index 676d2bf8..06a2e572 100644 --- a/app/src/main/java/com/arialyy/simple/download/multi_download/DownloadAdapter.java +++ b/app/src/main/java/com/arialyy/simple/download/multi_download/DownloadAdapter.java @@ -58,7 +58,7 @@ public class DownloadAdapter extends AbsRVAdapter { + private final String FILE_PATH = "/mnt/sdcard/王者军团.apk"; + private final String URL = "ftp://172.18.104.129:21/upload/"; + + @Override protected void init(Bundle savedInstanceState) { + super.init(savedInstanceState); + Aria.upload(this).register(); + } + + @Override protected int setLayoutId() { + return R.layout.activity_ftp_upload; + } + + public void onClick(View view) { + switch (view.getId()) { + case R.id.start: + Aria.upload(this).loadFtp(FILE_PATH).setUploadUrl(URL).login("lao", "123456").start(); + break; + case R.id.stop: + Aria.upload(this).loadFtp(FILE_PATH).stop(); + break; + case R.id.cancel: + Aria.upload(this).load(FILE_PATH).cancel(); + break; + } + } + + @Upload.onPre public void onPre(UploadTask task) { + getBinding().setFileSize(task.getConvertFileSize()); + } + + @Upload.onTaskPre public void taskPre(UploadTask task) { + L.d(TAG, "fileSize = " + task.getConvertFileSize()); + } + + @Upload.onTaskStart public void taskStart(UploadTask task) { + + } + + @Upload.onTaskStop public void taskStop(UploadTask task) { + getBinding().setSpeed(""); + Log.d(TAG, "停止上传"); + } + + @Upload.onTaskCancel public void taskCancel(UploadTask task) { + getBinding().setSpeed(""); + Log.d(TAG, "取消上传"); + } + + @Upload.onTaskRunning public void taskRunning(UploadTask task) { + getBinding().setProgress(task.getPercent()); + getBinding().setSpeed(task.getConvertSpeed()); + } + + @Upload.onTaskComplete public void taskComplete(UploadTask task) { + getBinding().setProgress(100); + getBinding().setSpeed(""); + T.showShort(this, "上传完成"); + } +} diff --git a/app/src/main/java/com/arialyy/simple/upload/UploadActivity.java b/app/src/main/java/com/arialyy/simple/upload/UploadActivity.java index d3d0c42a..1d9eb32b 100644 --- a/app/src/main/java/com/arialyy/simple/upload/UploadActivity.java +++ b/app/src/main/java/com/arialyy/simple/upload/UploadActivity.java @@ -29,14 +29,13 @@ import com.arialyy.frame.util.show.L; import com.arialyy.frame.util.show.T; import com.arialyy.simple.R; import com.arialyy.simple.base.BaseActivity; -import com.arialyy.simple.databinding.ActivityUploadMeanBinding; +import com.arialyy.simple.databinding.ActivityUploadBinding; import com.arialyy.simple.widget.HorizontalProgressBarWithNumber; -import java.lang.ref.WeakReference; /** * Created by Aria.Lao on 2017/2/9. */ -public class UploadActivity extends BaseActivity { +public class UploadActivity extends BaseActivity { private static final String TAG = "UploadActivity"; @Bind(R.id.pb) HorizontalProgressBarWithNumber mPb; private static final int START = 0; @@ -74,7 +73,7 @@ public class UploadActivity extends BaseActivity { }; @Override protected int setLayoutId() { - return R.layout.activity_upload_mean; + return R.layout.activity_upload; } @Override protected void init(Bundle savedInstanceState) { diff --git a/app/src/main/res/layout/activity_ftp_upload.xml b/app/src/main/res/layout/activity_ftp_upload.xml new file mode 100644 index 00000000..46ac3b31 --- /dev/null +++ b/app/src/main/res/layout/activity_ftp_upload.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 5f78bbf9..de9a5c45 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -34,7 +34,7 @@ />