修复resumeall 导致的进度错乱问题,修复ftp文件上传不完整问题 https://github.com/AriaLyy/Aria/issues/127

pull/330/head
AriaLyy 7 years ago
parent afb47c8446
commit 2d64c50ed0
  1. 4
      Aria/build.gradle
  2. 2
      Aria/src/main/java/com/arialyy/aria/core/TaskManager.java
  3. 21
      Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
  4. 1
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java
  5. 13
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
  6. 12
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpInfoThread.java
  7. 2
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpThreadTask.java
  8. 1
      Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java
  9. 2
      Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java
  10. 7
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java
  11. 75
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java
  12. 4
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
  13. 6
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java
  14. 2
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java
  15. 5
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java
  16. 9
      Aria/src/main/java/com/arialyy/aria/core/queue/pool/BaseExecutePool.java
  17. 2
      Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java
  18. 2
      Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java
  19. 8
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpFISAdapter.java
  20. 37
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpFileInfoThread.java
  21. 66
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java
  22. 2
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/SimpleUploadUtil.java
  23. 6
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/Uploader.java
  24. 12
      Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
  25. 2
      DEV_LOG.md
  26. 7
      README.md
  27. 4
      app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
  28. 2
      app/src/main/java/com/arialyy/simple/download/group/FTPDirDownloadActivity.java
  29. 11
      app/src/main/java/com/arialyy/simple/download/multi_download/DownloadAdapter.java
  30. 4
      app/src/main/java/com/arialyy/simple/download/multi_download/MultiTaskActivity.java
  31. 5
      app/src/main/java/com/arialyy/simple/upload/FtpUploadActivity.java
  32. 3
      build.gradle
  33. 10
      gradle.properties

@ -23,8 +23,8 @@ dependencies {
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile project(':AriaAnnotations')
// compile 'com.arialyy.aria:aria-ftp-plug:1.0.0'
compile project(':AriaFtpPlug')
compile 'com.arialyy.aria:aria-ftp-plug:1.0.1'
// compile project(':AriaFtpPlug')
}
apply from: 'bintray-release.gradle'

@ -31,7 +31,7 @@ public class TaskManager {
private static volatile TaskManager INSTANCE = null;
private Map<String, AbsTask> map = new ConcurrentHashMap<>();
public TaskManager getInstance() {
public static TaskManager getInstance() {
if (INSTANCE == null) {
synchronized (AriaManager.LOCK) {
INSTANCE = new TaskManager();

@ -1,7 +1,6 @@
package com.arialyy.aria.core.command.normal;
import android.util.Log;
import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
@ -30,7 +29,7 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
}
@Override public void executeCmd() {
if (!NetUtils.isConnected(AriaManager.APP)){
if (!NetUtils.isConnected(AriaManager.APP)) {
Log.w(TAG, "恢复任务失败,网络未连接");
return;
}
@ -49,18 +48,22 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
DbEntity.findDatas(DownloadTaskEntity.class, "isGroupTask=?", "false");
if (dTaskEntity != null && !dTaskEntity.isEmpty()) {
for (DownloadTaskEntity te : dTaskEntity) {
if (te == null || te.getEntity() == null) continue;
int state = te.getState();
if (state == IEntity.STATE_COMPLETE || state == IEntity.STATE_FAIL) continue;
resumeEntity(te);
if (state == IEntity.STATE_STOP || state == IEntity.STATE_OTHER) {
resumeEntity(te);
}
}
}
List<DownloadGroupTaskEntity> groupTask = DbEntity.findAllData(DownloadGroupTaskEntity.class);
if (groupTask != null && !groupTask.isEmpty()) {
for (DownloadGroupTaskEntity te : groupTask) {
if (te == null || te.getEntity() == null) continue;
int state = te.getState();
if (state == IEntity.STATE_COMPLETE || state == IEntity.STATE_FAIL) continue;
resumeEntity(te);
if (state == IEntity.STATE_STOP || state == IEntity.STATE_OTHER) {
resumeEntity(te);
}
}
}
}
@ -73,9 +76,11 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
DbEntity.findDatas(UploadTaskEntity.class, "isGroupTask=?", "false");
if (dTaskEntity != null && !dTaskEntity.isEmpty()) {
for (UploadTaskEntity te : dTaskEntity) {
if (te == null || te.getEntity() == null) continue;
int state = te.getState();
if (state == IEntity.STATE_COMPLETE || state == IEntity.STATE_FAIL) continue;
resumeEntity(te);
if (state == IEntity.STATE_STOP || state == IEntity.STATE_OTHER) {
resumeEntity(te);
}
}
}
}

@ -70,7 +70,6 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
}
}
} else {
// 任务不存在时,根据配置不同,对任务执行操作
if (!task.isRunning()) {
startTask();
}

@ -96,8 +96,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
if (mListener instanceof IDownloadListener) {
((IDownloadListener) mListener).onPostPre(mEntity.getFileSize());
}
mConstance.cleanState();
mConstance.isRunning = true;
mConstance.resetState();
if (!mTaskEntity.isSupportBP) {
mThreadNum = 1;
mConstance.THREAD_NUM = mThreadNum;
@ -125,7 +124,10 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
mTimer = new Timer(true);
mTimer.schedule(new TimerTask() {
@Override public void run() {
if (mConstance.isComplete() || !mConstance.isRunning) {
if (mConstance.isComplete()
|| mConstance.isStop()
|| mConstance.isCancel()
|| !mConstance.isRunning) {
closeTimer();
} else if (mConstance.CURRENT_LOCATION >= 0) {
mListener.onProgress(mConstance.CURRENT_LOCATION);
@ -179,9 +181,9 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
@Override public void stop() {
closeTimer();
if (mConstance.isComplete()) return;
mConstance.isStop = true;
mConstance.isRunning = false;
mConstance.isStop = true;
if (mConstance.isComplete()) return;
if (mFixedThreadPool != null) {
mFixedThreadPool.shutdown();
}
@ -393,5 +395,4 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
* 选择单任务线程的类型
*/
protected abstract AbsThreadTask selectThreadTask(SubThreadConfig<TASK_ENTITY> config);
}

@ -23,7 +23,6 @@ import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.util.CommonUtil;
import java.io.IOException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
@ -37,7 +36,7 @@ import org.apache.commons.net.ftp.FTPReply;
public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable {
private final String TAG = "HttpFileInfoThread";
private final String TAG = "AbsFtpInfoThread";
protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity;
private int mConnectTimeOut;
@ -86,6 +85,9 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
}
}
mTaskEntity.code = reply;
if (mSize != 0 && !isUpload) {
mEntity.setFileSize(mSize);
}
mEntity.update();
mTaskEntity.update();
onPreComplete(reply);
@ -170,9 +172,9 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
size += file.getSize();
handleFile(path + file.getName(), file);
} else {
size += getFileSize(client.listFiles(
CommonUtil.strCharSetConvert(path + file.getName(), mTaskEntity.charSet)), client,
path + file.getName());
String remotePath =
new String((path + file.getName()).getBytes(charSet), AbsFtpThreadTask.SERVER_CHARSET);
size += getFileSize(client.listFiles(remotePath), client, path + file.getName());
}
}
return size;

@ -74,7 +74,7 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
client.setBufferSize(mBufSize);
//client.setControlKeepAliveTimeout(5);
client.setControlKeepAliveTimeout(5);
//client.setCopyStreamListener();
return client;
}

@ -229,7 +229,6 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
*/
protected void writeConfig(boolean isComplete, final long record) throws IOException {
synchronized (AriaManager.LOCK) {
Log.d(TAG, "really record == " + record);
String key = null, value = null;
if (0 < record && record < mConfig.END_LOCATION) {
key = mConfig.TEMP_FILE.getName() + "_record_" + mConfig.THREAD_ID;

@ -35,7 +35,7 @@ public class StateConstance {
public StateConstance() {
}
public void cleanState() {
public void resetState() {
isCancel = false;
isStop = false;
isRunning = true;

@ -17,6 +17,7 @@ package com.arialyy.aria.core.download;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.download.downloader.AbsGroupUtil;
@ -56,7 +57,11 @@ public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity, Dow
}
@Override public void start() {
mUtil.start();
if (mUtil.isRunning()) {
Log.d(TAG, "任务正在下载");
} else {
mUtil.start();
}
}
@Override public void stop() {

@ -43,23 +43,15 @@ import java.util.concurrent.Executors;
public abstract class AbsGroupUtil implements IUtil {
private final String TAG = "AbsGroupUtil";
/**
* 任务组所有任务总大小
* 任务组所有任务总长度
*/
long mTotalSize = 0;
long mTotalLen = 0;
long mCurrentLocation = 0;
private ExecutorService mExePool;
protected IDownloadGroupListener mListener;
protected DownloadGroupTaskEntity mTaskEntity;
private boolean isRunning = false;
private Timer mTimer;
/**
* 初始化完成的任务书数
*/
int mInitNum = 0;
/**
* 初始化失败的任务数
*/
int mInitFailNum = 0;
/**
* 保存所有没有下载完成的任务key为下载地址
*/
@ -79,18 +71,26 @@ public abstract class AbsGroupUtil implements IUtil {
* 该任务组对应的所有任务
*/
private Map<String, DownloadTaskEntity> mTasksMap = new HashMap<>();
/**
* 是否需要读取文件长度{@code true}需要
*/
boolean isNeedLoadFileSize = true;
//已经完成的任务数
private int mCompleteNum = 0;
//失败的任务数
private int mFailNum = 0;
//停止的任务数
private int mStopNum = 0;
//实际的下载任务数
int mActualTaskNum = 0;
/**
* 是否需要读取文件长度{@code true}需要
*/
boolean isNeedLoadFileSize = true;
//初始化完成的任务数
int mInitNum = 0;
// 初始化失败的任务数
int mInitFailNum = 0;
//任务组大小
int mGroupSize = 0;
AbsGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) {
mListener = listener;
@ -105,14 +105,13 @@ public abstract class AbsGroupUtil implements IUtil {
mTasksMap.put(te.getEntity().getUrl(), te);
}
}
mTotalSize = taskEntity.getEntity().getFileSize();
isNeedLoadFileSize = mTotalSize <= 1;
mGroupSize = mTaskEntity.entity.getSubTask().size();
mTotalLen = taskEntity.getEntity().getFileSize();
isNeedLoadFileSize = mTotalLen <= 1;
for (DownloadEntity entity : mTaskEntity.entity.getSubTask()) {
File file = new File(entity.getDownloadPath());
if (entity.getState() == IEntity.STATE_COMPLETE && file.exists()) {
mCompleteNum++;
mInitNum++;
mStopNum++;
mCurrentLocation += entity.getFileSize();
} else {
mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
@ -120,7 +119,7 @@ public abstract class AbsGroupUtil implements IUtil {
mActualTaskNum++;
}
if (isNeedLoadFileSize) {
mTotalSize += entity.getFileSize();
mTotalLen += entity.getFileSize();
}
}
updateFileSize();
@ -128,7 +127,7 @@ public abstract class AbsGroupUtil implements IUtil {
void updateFileSize() {
if (isNeedLoadFileSize) {
mTaskEntity.getEntity().setFileSize(mTotalSize);
mTaskEntity.getEntity().setFileSize(mTotalLen);
mTaskEntity.getEntity().update();
}
}
@ -212,7 +211,7 @@ public abstract class AbsGroupUtil implements IUtil {
}
@Override public long getFileSize() {
return mTotalSize;
return mTotalLen;
}
@Override public long getCurrentLocation() {
@ -272,7 +271,6 @@ public abstract class AbsGroupUtil implements IUtil {
@Override public void stop() {
closeTimer(false);
mListener.onStop(mCurrentLocation);
onStop();
if (!mExePool.isShutdown()) {
mExePool.shutdown();
@ -325,7 +323,7 @@ public abstract class AbsGroupUtil implements IUtil {
*/
void startRunningFlow() {
closeTimer(true);
mListener.onPostPre(mTotalSize);
mListener.onPostPre(mTotalLen);
mListener.onStart(mCurrentLocation);
startTimer();
}
@ -413,8 +411,8 @@ public abstract class AbsGroupUtil implements IUtil {
ChildDownloadListener(DownloadTaskEntity entity) {
this.taskEntity = entity;
this.entity = taskEntity.getEntity();
lastLen = this.entity.getCurrentProgress();
this.entity.setFailNum(0);
lastLen = this.entity.getCurrentProgress();
mLastSaveTime = System.currentTimeMillis();
}
@ -458,10 +456,12 @@ public abstract class AbsGroupUtil implements IUtil {
saveData(IEntity.STATE_STOP, stopLocation);
handleSpeed(0);
mListener.onSubStop(entity);
mStopNum++;
if (mStopNum + mCompleteNum >= mInitNum) {
closeTimer(false);
mListener.onStop(mCurrentLocation);
synchronized (AbsGroupUtil.class) {
mStopNum++;
if (mStopNum + mCompleteNum + mInitFailNum + mFailNum >= mGroupSize) {
closeTimer(false);
mListener.onStop(mCurrentLocation);
}
}
}
@ -473,16 +473,19 @@ public abstract class AbsGroupUtil implements IUtil {
@Override public void onComplete() {
saveData(IEntity.STATE_COMPLETE, entity.getFileSize());
mCompleteNum++;
handleSpeed(0);
mListener.onSubComplete(entity);
//如果子任务完成的数量和总任务数一致,表示任务组任务已经完成
if (mCompleteNum >= mTaskEntity.getEntity().getSubTask().size()) {
closeTimer(false);
mListener.onComplete();
} else if (mCompleteNum + mFailNum >= mActualTaskNum) {
//如果子任务完成数量加上失败的数量和总任务数一致,则任务组停止下载
closeTimer(false);
synchronized (AbsGroupUtil.class) {
mCompleteNum++;
//如果子任务完成的数量和总任务数一致,表示任务组任务已经完成
if (mCompleteNum >= mGroupSize) {
closeTimer(false);
mListener.onComplete();
} else if (mStopNum + mCompleteNum + mInitFailNum + mFailNum >= mGroupSize) {
//如果子任务完成数量加上失败的数量和总任务数一致,则任务组停止下载
closeTimer(false);
mListener.onStop(mCurrentLocation);
}
}
}

@ -74,7 +74,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
}
}
if (i != 0 && i == mExeMap.size()) startRunningFlow();
if (mCurrentLocation == mTotalSize) {
if (mCurrentLocation == mTotalLen) {
mListener.onComplete();
}
}
@ -93,7 +93,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
DownloadTaskEntity te = mExeMap.get(url);
if (te != null) {
if (isNeedLoadFileSize) {
mTotalSize += te.getEntity().getFileSize();
mTotalLen += te.getEntity().getFileSize();
}
createChildDownload(te);
}

@ -16,7 +16,6 @@
package com.arialyy.aria.core.download.downloader;
import android.util.Log;
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;
@ -43,10 +42,7 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
}
@Override protected void checkTask() {
mConfigFile = new File(mContext.getFilesDir().getPath()
+ AriaManager.DOWNLOAD_TEMP_DIR
+ mEntity.getFileName()
+ ".properties");
mConfigFile = new File(CommonUtil.getFileConfigPath(true, mEntity.getFileName()));
mTempFile = new File(mEntity.getDownloadPath());
if (!mTaskEntity.isSupportBP) {
isNewTask = true;

@ -43,6 +43,8 @@ public class FtpDirDownloadUtil extends AbsGroupUtil {
mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
}
mActualTaskNum = mTaskEntity.entity.getSubTask().size();
mGroupSize = mActualTaskNum;
mTotalLen = mTaskEntity.entity.getFileSize();
startDownload();
}
}

@ -32,9 +32,7 @@ class FtpFileInfoThread extends AbsFtpInfoThread<DownloadEntity, DownloadTaskEnt
@Override protected String setRemotePath() {
String url = mEntity.getUrl();
return url.substring(url.indexOf(mPort) + mPort.length(), url.length())
+ "/"
+ mEntity.getFileName();
return url.substring(url.indexOf(mPort) + mPort.length(), url.length());
}
@Override protected void onPreComplete(int code) {
@ -43,5 +41,6 @@ class FtpFileInfoThread extends AbsFtpInfoThread<DownloadEntity, DownloadTaskEnt
mTaskEntity.isNewTask = true;
}
mEntity.setFileSize(mSize);
mCallback.onComplete(mEntity.getUrl(), code);
}
}

@ -20,9 +20,7 @@ import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.util.CommonUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
@ -185,8 +183,11 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
}
String convertKey = CommonUtil.keyToHashKey(key);
TASK task = mExecuteMap.get(convertKey);
mExecuteMap.remove(convertKey);
return mExecuteQueue.remove(task);
if (mExecuteQueue.remove(task)) {
mExecuteMap.remove(convertKey);
return true;
}
return false;
}
}

@ -19,7 +19,6 @@ import android.os.CountDownTimer;
import android.os.Message;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsNormalEntity;
@ -29,7 +28,6 @@ import com.arialyy.aria.core.inf.GroupSendParams;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.queue.ITaskQueue;
import com.arialyy.aria.core.upload.UploadTask;
import com.arialyy.aria.util.NetUtils;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

@ -47,7 +47,7 @@ public class FtpUploadTarget
mEntity.setFileSize(file.length());
//暂时不支持断点续传上传
mTaskEntity.isSupportBP = false;
//mTaskEntity.isSupportBP = false;
}
/**

@ -22,9 +22,9 @@ import java.io.InputStream;
/**
* Created by lyy on 2017/9/26.
* 具有进度的InputStream
* BufferedRandomAccessFile InputStream 适配器
*/
final class ProgressInputStream extends InputStream {
final class FtpFISAdapter extends InputStream {
private BufferedRandomAccessFile mIs;
private ProgressCallback mCallback;
@ -34,12 +34,12 @@ final class ProgressInputStream extends InputStream {
void onProgressCallback(byte[] buffer, int byteOffset, int byteCount) throws IOException;
}
ProgressInputStream(@NonNull BufferedRandomAccessFile is, @NonNull ProgressCallback callback) {
FtpFISAdapter(@NonNull BufferedRandomAccessFile is, @NonNull ProgressCallback callback) {
mIs = is;
mCallback = callback;
}
ProgressInputStream(@NonNull BufferedRandomAccessFile is) {
FtpFISAdapter(@NonNull BufferedRandomAccessFile is) {
mIs = is;
}

@ -19,15 +19,18 @@ import com.arialyy.aria.core.common.AbsFtpInfoThread;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.util.Properties;
import org.apache.commons.net.ftp.FTPFile;
/**
* Created by Aria.Lao on 2017/9/26.
* FTP远程服务器文件信息
* 单任务远程服务器文件信息
*/
class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity> {
static final int CODE_EXISTS = 0xab1;
private boolean exists = false;
static final int CODE_COMPLETE = 0xab1;
private boolean isComplete = false;
FtpFileInfoThread(UploadTaskEntity taskEntity, OnFileInfoCallback callback) {
super(taskEntity, callback);
@ -40,16 +43,36 @@ class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity>
+ mEntity.getFileName();
}
/**
* 如果服务器的文件长度和本地上传文件的文件长度一致则任务任务已完成
* 否则重新修改保存的停止位置这是因为outputStream是读不到服务器是否成功写入的
* 而threadTask的保存的停止位置是File的InputStream的所有就会导致两端停止位置不一致
*
* @param remotePath ftp服务器文件夹路径
* @param ftpFile ftp服务器上对应的文件
*/
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
super.handleFile(remotePath, ftpFile);
//远程文件已完成
if (ftpFile != null && ftpFile.getSize() == mEntity.getFileSize()) {
exists = true;
if (ftpFile != null) {
//远程文件已完成
if (ftpFile.getSize() == mEntity.getFileSize()) {
isComplete = true;
} else {
File configFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
Properties pro = CommonUtil.loadConfig(configFile);
String key = mEntity.getFileName() + "_record_" + 0;
long oldRecord = Long.parseLong(pro.getProperty(key, "0"));
if (oldRecord != 0) {
//修改本地保存的停止地址为服务器上的真实地址
pro.setProperty(key, ftpFile.getSize() + "");
CommonUtil.saveConfig(configFile, pro);
}
}
}
}
@Override protected void onPreComplete(int code) {
super.onPreComplete(code);
mCallback.onComplete(mEntity.getKey(), exists ? CODE_EXISTS : code);
mCallback.onComplete(mEntity.getKey(), isComplete ? CODE_COMPLETE : code);
}
}

@ -25,14 +25,10 @@ import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.OnFtpInputStreamListener;
import org.apache.commons.net.io.CopyStreamEvent;
import org.apache.commons.net.io.CopyStreamListener;
/**
* Created by Aria.Lao on 2017/7/28.
@ -70,8 +66,8 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
client.setRestartOffset(mConfig.START_LOCATION);
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize);
if (mConfig.START_LOCATION != 0) {
file.skipBytes((int) mConfig.START_LOCATION);
//file.seek(mConfig.START_LOCATION);
//file.skipBytes((int) mConfig.START_LOCATION);
file.seek(mConfig.START_LOCATION);
}
upload(client, file);
if (STATE.isCancel || STATE.isStop) return;
@ -113,27 +109,16 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
private void upload(final FTPClient client, final BufferedRandomAccessFile bis)
throws IOException {
//client.storeFile(remotePath,
// new ProgressInputStream(bis, new ProgressInputStream.ProgressCallback() {
// @Override public void onProgressCallback(byte[] buffer, int byteOffset, int byteCount)
// throws IOException {
// if (STATE.isCancel || STATE.isStop) {
// long s = client.abor();
// Log.d(TAG, "s = " + s);
// client.disconnect();
// }
// progress(byteCount);
// }
// }));
try {
client.storeFile(remotePath, new ProgressInputStream(bis), new OnFtpInputStreamListener() {
client.storeFile(remotePath, new FtpFISAdapter(bis), new OnFtpInputStreamListener() {
boolean isStoped = false;
@Override public void onFtpInputStream(FTPClient client, long totalBytesTransferred,
int bytesTransferred, long streamSize) {
if (STATE.isCancel || STATE.isStop) {
if ((STATE.isCancel || STATE.isStop) && !isStoped) {
try {
isStoped = true;
client.abor();
} catch (IOException e) {
e.printStackTrace();
@ -142,40 +127,21 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
progress(bytesTransferred);
}
});
} catch (IOException e) {
//e.printStackTrace();
if (e.getMessage().contains("IOException caught while copying")) {
e.printStackTrace();
} else {
fail(mChildCurrentLocation, "上传失败", e);
}
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
fail(mChildCurrentLocation, "上传文件错误,错误码为:" + reply, null);
}
}
/**
* 执行上传操作
*/
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);
if (client.isConnected()) {
client.disconnect();
}
Log.d(TAG, len + "");
if (reply == FTPReply.TRANSFER_ABORTED) return;
fail(mChildCurrentLocation, "上传文件错误,错误码为:" + reply, null);
}
}

@ -49,7 +49,7 @@ public class SimpleUploadUtil implements IUtil, Runnable {
mListener.onPre();
new FtpFileInfoThread(mTaskEntity, new OnFileInfoCallback() {
@Override public void onComplete(String url, int code) {
if (code == FtpFileInfoThread.CODE_EXISTS) {
if (code == FtpFileInfoThread.CODE_COMPLETE) {
mListener.onComplete();
} else {
mUploader.start();

@ -15,7 +15,6 @@
*/
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;
@ -47,10 +46,7 @@ class Uploader extends AbsFileer<UploadEntity, UploadTaskEntity> {
* 5不支持断点则是新任务
*/
protected void checkTask() {
mConfigFile = new File(mContext.getFilesDir().getPath()
+ AriaManager.UPLOAD_TEMP_DIR
+ mEntity.getFileName()
+ ".properties");
mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
if (!mTaskEntity.isSupportBP) {
isNewTask = true;
return;

@ -266,7 +266,7 @@ public class CommonUtil {
file.delete();
}
}
File config = new File(getFileConfig(false, uEntity.getFileName()));
File config = new File(getFileConfigPath(false, uEntity.getFileName()));
if (config.exists()) {
config.delete();
}
@ -296,7 +296,7 @@ public class CommonUtil {
}
}
File config = new File(getFileConfig(true, dEntity.getFileName()));
File config = new File(getFileConfigPath(true, dEntity.getFileName()));
if (config.exists()) {
config.delete();
}
@ -730,11 +730,11 @@ public class CommonUtil {
}
/**
* 通过文件名获取下载配置文件
* 通过文件名获取下载配置文件路径
*
* @param fileName 文件名
*/
public static String getFileConfig(boolean isDownload, String fileName) {
public static String getFileConfigPath(boolean isDownload, String fileName) {
return AriaManager.APP.getFilesDir().getPath() + (isDownload ? AriaManager.DOWNLOAD_TEMP_DIR
: AriaManager.UPLOAD_TEMP_DIR) + fileName + ".properties";
}
@ -765,8 +765,8 @@ public class CommonUtil {
private static void renameConfig(boolean isDownload, String oldName, String newName) {
if (oldName.equals(newName)) return;
File oldFile = new File(getFileConfig(isDownload, oldName));
File newFile = new File(getFileConfig(isDownload, oldName));
File oldFile = new File(getFileConfigPath(isDownload, oldName));
File newFile = new File(getFileConfigPath(isDownload, oldName));
if (!oldFile.exists()) {
createFile(newFile.getPath());
} else {

@ -1,5 +1,5 @@
## 开发日志
+ v_3.3.2 新加reTry(),修复上一个版本不会回调失败事件的问题;增加running状态下5秒钟保存一次数据库的功能
+ v_3.3.2 新加reTry(),修复上一个版本不会回调失败事件的问题;增加running状态下5秒钟保存一次数据库的功能;修复FTP断点上传文件不完整的问题
+ v_3.3.1 增加网络事件,网络未连接,将不会重试下载,修复删除未开始任务,状态回调错误
+ v_3.3.0 增加任务组子任务暂停和开始控制功能、修复5.0系统以上数据库多生成两个字段的bug、去掉addSchedulerListener事件
+ v_3.2.26 修复任务组有时注解不起作用的问题

@ -6,9 +6,10 @@ Aria项目源于工作中遇到的一个文件下载管理的需求,当时被
Aria有以下特点:
+ 简单、方便
- 可以在Activity、Service、Fragment、Dialog、popupWindow、Notification等组件中使用
- 一行代码实现HTTP\FTP断线续传、多任务自动调度
- 一行代码实现HTTP任务组\FTP文件夹下载
- 一行代码实现HTTP\FTP断点续传上传
- 支持HTTP\FTP断点续传、多任务自动调度
- 支持HTTP任务组\FTP文件夹,断点续传下载
- 支持HTTP表单上传
- 支持文件FTP断点续传上传
+ 支持https地址下载
- 在配置文件中很容易就可以设置CA证书的信息
+ 支持300、301、302重定向下载链接下载

@ -46,14 +46,14 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
private static final String DOWNLOAD_URL =
//"http://kotlinlang.org/docs/kotlin-docs.pdf";
//"https://atom-installer.github.com/v1.13.0/AtomSetup.exe?s=1484074138&ext=.exe";
"http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk";
//"http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk";
//"http://sitcac.daxincf.cn/wp-content/uploads/swift_vido/01/element.mp4_1";
//"http://120.25.196.56:8000/filereq?id=15692406294&ipncid=105635&client=android&filename=20170819185541.avi";
//"http://down2.xiaoshuofuwuqi.com/d/file/filetxt/20170608/14/%BA%DA%CE%D7%CA%A6%E1%C8%C6%F0.txt";
//"http://tinghuaapp.oss-cn-shanghai.aliyuncs.com/20170612201739607815";
//"http://static.gaoshouyou.com/d/36/69/2d3699acfa69e9632262442c46516ad8.apk";
//"http://oqcpqqvuf.bkt.clouddn.com/ceshi.txt";
//"http://down8.androidgame-store.com/201706122321/97967927DD4E53D9905ECAA7874C8128/new/game1/19/45319/com.neuralprisma-2.5.2.174-2000174_1494784835.apk?f=web_1";
"http://down8.androidgame-store.com/201706122321/97967927DD4E53D9905ECAA7874C8128/new/game1/19/45319/com.neuralprisma-2.5.2.174-2000174_1494784835.apk?f=web_1";
//不支持断点的链接
//"http://ox.konsung.net:5555/ksdc-web/download/downloadFile/?fileName=ksdc_1.0.2.apk&rRange=0-";
//"http://172.18.104.50:8080/download/_302turn";

@ -35,7 +35,7 @@ import com.arialyy.simple.widget.SubStateLinearLayout;
* Created by Aria.Lao on 2017/7/6.
*/
public class FTPDirDownloadActivity extends BaseActivity<ActivityDownloadGroupBinding> {
private static final String dir = "ftp://172.18.104.66:21/haha/";
private static final String dir = "ftp://172.18.104.49:21/haha/";
@Bind(R.id.child_list) SubStateLinearLayout mChildList;

@ -19,6 +19,7 @@ package com.arialyy.simple.download.multi_download;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
@ -182,7 +183,7 @@ public class DownloadAdapter extends AbsRVAdapter<AbsEntity, DownloadAdapter.Sim
color = android.R.color.holo_red_light;
break;
case IEntity.STATE_COMPLETE:
str = "重新开始?";
str = "完成";
holder.progress.setProgress(100);
break;
}
@ -206,9 +207,9 @@ public class DownloadAdapter extends AbsRVAdapter<AbsEntity, DownloadAdapter.Sim
mData.remove(entity);
notifyDataSetChanged();
if (isSimpleDownload(entity)) {
Aria.download(getContext()).load((DownloadEntity) entity).cancel();
Aria.download(getContext()).load((DownloadEntity) entity).cancel(true);
} else {
Aria.download(getContext()).load((DownloadGroupEntity) entity).cancel();
Aria.download(getContext()).load((DownloadGroupEntity) entity).cancel(true);
}
}
});
@ -254,7 +255,6 @@ public class DownloadAdapter extends AbsRVAdapter<AbsEntity, DownloadAdapter.Sim
case IEntity.STATE_OTHER:
case IEntity.STATE_FAIL:
case IEntity.STATE_STOP:
case IEntity.STATE_COMPLETE:
case IEntity.STATE_PRE:
case IEntity.STATE_POST_PRE:
start(entity);
@ -262,6 +262,9 @@ public class DownloadAdapter extends AbsRVAdapter<AbsEntity, DownloadAdapter.Sim
case IEntity.STATE_RUNNING:
stop(entity);
break;
case IEntity.STATE_COMPLETE:
Log.d(TAG, "任务已完成");
break;
}
}

@ -66,8 +66,8 @@ public class MultiTaskActivity extends BaseActivity<ActivityMultiBinding> {
dialog.show(getSupportFragmentManager(), "download_num");
break;
case R.id.stop_all:
//Aria.download(this).stopAllTask();
Aria.download(this).removeAllTask(true);
Aria.download(this).stopAllTask();
//Aria.download(this).removeAllTask(true);
break;
case R.id.turn:
startActivity(new Intent(this, MultiDownloadActivity.class));

@ -34,8 +34,8 @@ import com.arialyy.simple.databinding.ActivityFtpUploadBinding;
* Ftp 文件上传demo
*/
public class FtpUploadActivity extends BaseActivity<ActivityFtpUploadBinding> {
private final String FILE_PATH = "/mnt/sdcard/Download/jd.jpg";
private final String URL = "ftp://192.168.1.9:21/upload/测试";
private final String FILE_PATH = "/mnt/sdcard/Download/me.jpg";
private final String URL = "ftp://172.18.104.49:21/upload/测试";
@Override protected void init(Bundle savedInstanceState) {
setTile("FTP 文件上传");
@ -92,6 +92,7 @@ public class FtpUploadActivity extends BaseActivity<ActivityFtpUploadBinding> {
}
@Upload.onTaskRunning public void taskRunning(UploadTask task) {
Log.d(TAG, "PP = " + task.getPercent());
getBinding().setProgress(task.getPercent());
getBinding().setSpeed(task.getConvertSpeed());
}

@ -37,7 +37,8 @@ task clean(type: Delete) {
ext {
userOrg = 'arialyy'
groupId = 'com.arialyy.aria'
publishVersion = '3.3.0'
publishVersion = '3.3.3_dev'
// publishVersion = '1.0.1' //FTP插件
repoName='maven'
desc = 'android 下载框架'
website = 'https://github.com/AriaLyy/Aria'

@ -13,9 +13,9 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
#Wed Dec 07 20:19:22 CST 2016
org.gradle.daemon=true
org.gradle.jvmargs=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
#org.gradle.daemon=true
#org.gradle.jvmargs=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
# gradle proxy https://chaosleong.github.io/2017/02/10/Configuring-Gradle-Proxy/
#systemProp.socksProxyHost=127.0.0.1
#systemProp.socksProxyPort=51110
#systemprop.socksProxyVersion=5
systemProp.socksProxyHost=127.0.0.1
systemProp.socksProxyPort=51110
systemprop.socksProxyVersion=5
Loading…
Cancel
Save