修复线程重启的导致下载失败的一个问题,https://github.com/AriaLyy/Aria/issues/160

pull/330/head
AriaLyy 7 years ago
parent ec1b504309
commit a310df2281
  1. 53
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
  2. 24
      Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java
  3. 2
      Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java
  4. 4
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java
  5. 6
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
  6. 4
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java
  7. 8
      Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
  8. 2
      app/src/main/assets/aria_config.xml
  9. 2
      app/src/main/java/com/arialyy/simple/download/FtpDownloadActivity.java
  10. 4
      app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java

@ -40,7 +40,7 @@ import java.util.concurrent.Executors;
*/
public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable, IUtil {
private final String TAG = "Downloader";
private final String TAG = "AbsFileer";
protected IEventListener mListener;
protected TASK_ENTITY mTaskEntity;
protected ENTITY mEntity;
@ -50,7 +50,12 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
protected boolean isNewTask = true;
protected StateConstance mConstance;
private ExecutorService mFixedThreadPool;
private int mThreadNum, mRealThreadNum;
//总线程数
private int mTotalThreadNum;
//启动线程数
private int mStartThreadNum;
//已完成的线程数
private int mCompleteThreadNum;
private SparseArray<AbsThreadTask> mTask = new SparseArray<>();
/**
@ -72,7 +77,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
}
@Override public void setMaxSpeed(double maxSpeed) {
for (int i = 0; i < mThreadNum; i++) {
for (int i = 0; i < mTotalThreadNum; i++) {
AbsThreadTask task = mTask.get(i);
if (task != null) {
task.setMaxSpeed(maxSpeed);
@ -101,12 +106,13 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
((IDownloadListener) mListener).onPostPre(mEntity.getFileSize());
}
if (!mTaskEntity.isSupportBP) {
mThreadNum = 1;
mConstance.THREAD_NUM = mThreadNum;
mTotalThreadNum = 1;
mStartThreadNum = 1;
mConstance.THREAD_NUM = mTotalThreadNum;
handleNoSupportBP();
} else {
mThreadNum = isNewTask ? (getNewTaskThreadNum()) : mRealThreadNum;
mConstance.THREAD_NUM = mThreadNum;
mTotalThreadNum = isNewTask ? (getNewTaskThreadNum()) : mStartThreadNum + mCompleteThreadNum;
mConstance.THREAD_NUM = mTotalThreadNum;
handleBreakpoint();
}
startTimer();
@ -116,8 +122,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
* 设置新任务的最大线程数
*/
protected int getNewTaskThreadNum() {
return mEntity.getFileSize() <= SUB_LEN || mTaskEntity.requestType == AbsTaskEntity.D_FTP_DIR ? 1
: AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum();
return mEntity.getFileSize() <= SUB_LEN || mTaskEntity.requestType == AbsTaskEntity.D_FTP_DIR
? 1 : AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum();
}
/**
@ -169,7 +175,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
if (mFixedThreadPool != null) {
mFixedThreadPool.shutdown();
}
for (int i = 0; i < mThreadNum; i++) {
for (int i = 0; i < mStartThreadNum; i++) {
AbsThreadTask task = mTask.get(i);
if (task != null) {
task.cancel();
@ -190,7 +196,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
if (mFixedThreadPool != null) {
mFixedThreadPool.shutdown();
}
for (int i = 0; i < mThreadNum; i++) {
for (int i = 0; i < mStartThreadNum; i++) {
AbsThreadTask task = mTask.get(i);
if (task != null) {
task.stop();
@ -230,6 +236,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
* 检查记录文件如果是新任务返回{@code true}否则返回{@code false}
*/
protected boolean checkConfigFile() {
mStartThreadNum = 0;
mCompleteThreadNum = 0;
Properties pro = CommonUtil.loadConfig(mConfigFile);
if (pro.isEmpty()) {
return true;
@ -237,15 +245,18 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
Set<Object> keys = pro.keySet();
int num = 0;
for (Object key : keys) {
if (String.valueOf(key).contains("_record_")) {
String str = String.valueOf(key);
if (str.contains("_record_")) {
num++;
} else if (str.contains("_state_")) {
mCompleteThreadNum++;
}
}
if (num == 0) {
return true;
}
mRealThreadNum = num;
for (int i = 0; i < mRealThreadNum; i++) {
mStartThreadNum = num;
for (int i = 0; i < mStartThreadNum; i++) {
if (pro.getProperty(mTempFile.getName() + "_record_" + i) == null) {
Object state = pro.getProperty(mTempFile.getName() + "_state_" + i);
if (state != null && Integer.parseInt(state + "") == 1) {
@ -264,8 +275,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
*/
private boolean resumeRecordLocation(int i, long startL, long endL) {
mConstance.CURRENT_LOCATION += endL - startL;
ALog.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++");
mConstance.COMPLETE_THREAD_NUM++;
ALog.d(TAG, "任务【" + mTaskEntity.getEntity().getFileName() + "】线程__" + i + "__已完成");
mConstance.COMPLETE_THREAD_NUM = mCompleteThreadNum;
mConstance.STOP_NUM++;
mConstance.CANCEL_NUM++;
if (mConstance.isComplete()) {
@ -307,16 +318,16 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
private void handleBreakpoint() {
long fileLength = mEntity.getFileSize();
Properties pro = CommonUtil.loadConfig(mConfigFile);
long blockSize = fileLength / mThreadNum;
int[] recordL = new int[mThreadNum];
for (int i = 0; i < mThreadNum; i++) {
long blockSize = fileLength / mTotalThreadNum;
int[] recordL = new int[mTotalThreadNum];
for (int i = 0; i < mTotalThreadNum; i++) {
recordL[i] = -1;
}
int rl = 0;
if (isNewTask) {
handleNewTask();
}
for (int i = 0; i < mThreadNum; i++) {
for (int i = 0; i < mTotalThreadNum; i++) {
long startL = i * blockSize, endL = (i + 1) * blockSize;
Object state = pro.getProperty(mTempFile.getName() + "_state_" + i);
if (state != null && Integer.parseInt(state + "") == 1) { //该线程已经完成
@ -339,7 +350,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
recordL[rl] = i;
rl++;
}
if (i == (mThreadNum - 1)) {
if (i == (mTotalThreadNum - 1)) {
//最后一个线程的结束位置即为文件的总长度
endL = fileLength;
}

@ -42,7 +42,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
/**
* 线程重试次数
*/
private final int RETRY_NUM = 5;
private final int RETRY_NUM = 2;
/**
* 线程重试间隔
*/
@ -108,7 +108,8 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
+ "】thread__"
+ mConfig.THREAD_ID
+ "__停止【停止位置: "
+ currentTemp + "】");
+ currentTemp
+ "】");
writeConfig(false, currentTemp);
if (STATE.isStop()) {
ALog.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止");
@ -134,7 +135,8 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
mChildCurrentLocation += len;
STATE.CURRENT_LOCATION += len;
//mIncrement += len;
if (System.currentTimeMillis() - mLastSaveTime > 5000) {
if (System.currentTimeMillis() - mLastSaveTime > 5000
&& mChildCurrentLocation < mConfig.END_LOCATION) {
mLastSaveTime = System.currentTimeMillis();
new Thread(new Runnable() {
@Override public void run() {
@ -209,15 +211,15 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
* @param needRetry 是否可以重试
*/
private void retryThis(boolean needRetry) {
if (mFailTimer != null) {
mFailTimer.purge();
mFailTimer.cancel();
}
if (!NetUtils.isConnected(AriaManager.APP)) {
ALog.w(TAG,
"任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__重试失败,网络未连接");
}
if (mFailNum < RETRY_NUM && needRetry && NetUtils.isConnected(AriaManager.APP)) {
if (mFailTimer != null) {
mFailTimer.purge();
mFailTimer.cancel();
}
mFailTimer = new Timer(true);
mFailTimer.schedule(new TimerTask() {
@Override public void run() {
@ -247,12 +249,12 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
protected void writeConfig(boolean isComplete, final long record) throws IOException {
synchronized (AriaManager.LOCK) {
String key = null, value = null;
if (0 < record && record < mConfig.END_LOCATION) {
key = mConfig.TEMP_FILE.getName() + "_record_" + mConfig.THREAD_ID;
value = String.valueOf(record);
} else if (record >= mConfig.END_LOCATION || isComplete) {
if (record >= mConfig.END_LOCATION || isComplete) {
key = mConfig.TEMP_FILE.getName() + "_state_" + mConfig.THREAD_ID;
value = "1";
} else if (0 < record && record < mConfig.END_LOCATION) {
key = mConfig.TEMP_FILE.getName() + "_record_" + mConfig.THREAD_ID;
value = String.valueOf(record);
}
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
File configFile = new File(mConfigFPath);

@ -56,7 +56,7 @@ public class StateConstance {
* 所有子线程是否都已经下载失败
*/
public boolean isFail() {
return FAIL_NUM + COMPLETE_THREAD_NUM >= THREAD_NUM;
return COMPLETE_THREAD_NUM != THREAD_NUM && FAIL_NUM + COMPLETE_THREAD_NUM >= THREAD_NUM;
}
/**

@ -102,6 +102,10 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
STATE.isRunning = false;
mListener.onComplete();
}
if (STATE.isFail()) {
STATE.isRunning = false;
mListener.onFail(false);
}
} catch (IOException e) {
fail(mChildCurrentLocation, "下载失败【" + mConfig.URL + "】", e);
} catch (Exception e) {

@ -100,8 +100,12 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
STATE.isRunning = false;
mListener.onComplete();
}
if (STATE.isFail()){
STATE.isRunning = false;
mListener.onFail(false);
}
} else {
ALog.i(TAG, "下载任务完成");
ALog.i(TAG, "任务下载完成");
STATE.isRunning = false;
mListener.onComplete();
}

@ -82,6 +82,10 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
STATE.isRunning = false;
mListener.onComplete();
}
if (STATE.isFail()){
STATE.isRunning = false;
mListener.onFail(false);
}
} catch (IOException e) {
fail(mChildCurrentLocation, "上传失败【" + mConfig.URL + "】", e);
} catch (Exception e) {

@ -30,7 +30,6 @@ import com.arialyy.aria.core.command.group.GroupCmdFactory;
import com.arialyy.aria.core.command.normal.AbsNormalCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
@ -148,7 +147,6 @@ public class CommonUtil {
for (String str : strs) {
url = url.replaceAll(str, URLEncoder.encode(str, "UTF-8"));
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
@ -284,7 +282,6 @@ public class CommonUtil {
*/
public static void delDownloadGroupTaskConfig(boolean removeFile,
DownloadGroupTaskEntity tEntity) {
DownloadGroupEntity entity = tEntity.getEntity();
List<DownloadTaskEntity> tasks =
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", tEntity.key);
if (tasks != null && !tasks.isEmpty()) {
@ -293,6 +290,7 @@ public class CommonUtil {
}
}
if (tEntity.getEntity() != null) {
File dir = new File(tEntity.getEntity().getDirPath());
if (removeFile) {
if (dir.exists()) {
@ -305,6 +303,7 @@ public class CommonUtil {
}
tEntity.deleteData();
}
}
/**
* 删除上传任务的配置
@ -314,6 +313,9 @@ public class CommonUtil {
*/
public static void delUploadTaskConfig(boolean removeFile, UploadTaskEntity tEntity) {
UploadEntity uEntity = tEntity.getEntity();
if (uEntity == null) {
return;
}
File file = new File(uEntity.getFilePath());
if (removeFile) {
if (file.exists()) {

@ -5,7 +5,7 @@
<download>
<!--设置下载线程,线程下载数改变后,新的下载任务才会生效,如果任务大小小于1m,该设置也不会生效-->
<threadNum value="1"/>
<threadNum value="3"/>
<!--设置下载队列最大任务数, 默认为2-->
<maxTaskNum value="2"/>

@ -38,7 +38,7 @@ public class FtpDownloadActivity extends BaseActivity<ActivityFtpDownloadBinding
//private final String URL = "ftp://192.168.1.9:21/下载/AriaPrj.zip";
//private final String URL = "ftp://192.168.1.9:21/下载/[电影天堂www.dy2018.com]赛车总动员3BD中英双字.mp4";
//private final String URL = "ftp://h:h@tv.dl1234.com:2199/付岩洞复仇者们05.mkv";
private final String URL = "ftp://z:z@dygod18.com:21211/[电影天堂www.dy2018.com]英格丽向西行BD中英双字.mp4";
private final String URL = "ftp://z:z@dygod18.com:21211/[破晓电影www.poxiao.com]情遇曼哈顿HD国语中字.mkv";
//private final String URL = "ftp://172.18.104.71:21/upload/AS.zip";
@Override protected void init(Bundle savedInstanceState) {

@ -48,7 +48,7 @@ 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";
@ -59,7 +59,7 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
//不支持断点的链接
//"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";
//"http://gdown.baidu.com/data/wisegame/0904344dee4a2d92/QQ_718.apk";
"http://gdown.baidu.com/data/wisegame/0904344dee4a2d92/QQ_718.apk";
//"http://172.21.1.99:8080/download/test+ 中文123.zip";
@Bind(R.id.start) Button mStart;
@Bind(R.id.stop) Button mStop;

Loading…
Cancel
Save