parent
3e2c3bc055
commit
7392eba667
@ -0,0 +1,275 @@ |
|||||||
|
/* |
||||||
|
* 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.loader; |
||||||
|
|
||||||
|
import android.os.Bundle; |
||||||
|
import android.os.Handler; |
||||||
|
import android.os.Looper; |
||||||
|
import android.os.Message; |
||||||
|
|
||||||
|
import com.arialyy.aria.core.TaskRecord; |
||||||
|
import com.arialyy.aria.core.inf.IThreadStateManager; |
||||||
|
import com.arialyy.aria.core.listener.IEventListener; |
||||||
|
import com.arialyy.aria.exception.AriaException; |
||||||
|
import com.arialyy.aria.util.ALog; |
||||||
|
import com.arialyy.aria.util.CommonUtil; |
||||||
|
import com.arialyy.aria.util.FileUtil; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
import java.util.concurrent.atomic.AtomicInteger; |
||||||
|
|
||||||
|
/** |
||||||
|
* 线程任务管理器,用于处理多线程下载时任务的状态回调 |
||||||
|
*/ |
||||||
|
public class UploadThreadStateManager implements IThreadStateManager { |
||||||
|
private final String TAG = CommonUtil.getClassName(this); |
||||||
|
|
||||||
|
/** |
||||||
|
* 任务状态回调 |
||||||
|
*/ |
||||||
|
private IEventListener mListener; |
||||||
|
private int mThreadNum; // 启动的线程总数
|
||||||
|
private AtomicInteger mCancelNum = new AtomicInteger(0); // 已经取消的线程的数
|
||||||
|
private AtomicInteger mStopNum = new AtomicInteger(0); // 已经停止的线程数
|
||||||
|
private AtomicInteger mFailNum = new AtomicInteger(0); // 失败的线程数
|
||||||
|
private AtomicInteger mCompleteNum = new AtomicInteger(0); // 完成的线程数
|
||||||
|
private long mProgress; //当前总进度
|
||||||
|
private TaskRecord mTaskRecord; // 任务记录
|
||||||
|
private Looper mLooper; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param listener 任务事件 |
||||||
|
*/ |
||||||
|
public UploadThreadStateManager(IEventListener listener) { |
||||||
|
mListener = listener; |
||||||
|
} |
||||||
|
|
||||||
|
@Override public void setLooper(TaskRecord taskRecord, Looper looper) { |
||||||
|
mTaskRecord = taskRecord; |
||||||
|
mThreadNum = mTaskRecord.threadNum; |
||||||
|
mLooper = looper; |
||||||
|
} |
||||||
|
|
||||||
|
private void checkLooper() { |
||||||
|
if (mTaskRecord == null) { |
||||||
|
throw new NullPointerException("任务记录为空"); |
||||||
|
} |
||||||
|
if (mLooper == null) { |
||||||
|
throw new NullPointerException("Looper为空"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private Handler.Callback callback = new Handler.Callback() { |
||||||
|
@Override public boolean handleMessage(Message msg) { |
||||||
|
checkLooper(); |
||||||
|
switch (msg.what) { |
||||||
|
case STATE_STOP: |
||||||
|
mStopNum.getAndIncrement(); |
||||||
|
if (isStop()) { |
||||||
|
quitLooper(); |
||||||
|
} |
||||||
|
break; |
||||||
|
case STATE_CANCEL: |
||||||
|
mCancelNum.getAndIncrement(); |
||||||
|
if (isCancel()) { |
||||||
|
quitLooper(); |
||||||
|
} |
||||||
|
break; |
||||||
|
case STATE_FAIL: |
||||||
|
mFailNum.getAndIncrement(); |
||||||
|
if (isFail()) { |
||||||
|
Bundle b = msg.getData(); |
||||||
|
mListener.onFail(b.getBoolean(DATA_RETRY, false), |
||||||
|
(AriaException) b.getSerializable(DATA_ERROR_INFO)); |
||||||
|
quitLooper(); |
||||||
|
} |
||||||
|
break; |
||||||
|
case STATE_COMPLETE: |
||||||
|
mCompleteNum.getAndIncrement(); |
||||||
|
if (isComplete()) { |
||||||
|
ALog.d(TAG, "isComplete, completeNum = " + mCompleteNum); |
||||||
|
//上传文件不需要合并文件
|
||||||
|
mListener.onComplete(); |
||||||
|
quitLooper(); |
||||||
|
} |
||||||
|
break; |
||||||
|
case STATE_RUNNING: |
||||||
|
Bundle b = msg.getData(); |
||||||
|
if (b != null) { |
||||||
|
long len = b.getLong(IThreadStateManager.DATA_ADD_LEN, 0); |
||||||
|
mProgress += len; |
||||||
|
} |
||||||
|
|
||||||
|
break; |
||||||
|
case STATE_UPDATE_PROGRESS: |
||||||
|
if (msg.obj == null) { |
||||||
|
mProgress = updateBlockProgress(); |
||||||
|
} else if (msg.obj instanceof Long) { |
||||||
|
mProgress = (long) msg.obj; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
@Override public void updateCurrentProgress(long currentProgress) { |
||||||
|
mProgress = currentProgress; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 退出looper循环 |
||||||
|
*/ |
||||||
|
private void quitLooper() { |
||||||
|
mLooper.quit(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取当前任务下载进度 |
||||||
|
* |
||||||
|
* @return 当前任务下载进度 |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public long getCurrentProgress() { |
||||||
|
return mProgress; |
||||||
|
} |
||||||
|
|
||||||
|
@Override public Handler.Callback getHandlerCallback() { |
||||||
|
return callback; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 所有子线程是否都已经停止 |
||||||
|
*/ |
||||||
|
public boolean isStop() { |
||||||
|
//ALog.d(TAG,
|
||||||
|
// String.format("isStop; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s", mStopNum,
|
||||||
|
// mCancelNum, mFailNum, mCompleteNum));
|
||||||
|
return mStopNum.get() == mThreadNum || mStopNum.get() + mCompleteNum.get() == mThreadNum; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 所有子线程是否都已经失败 |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public boolean isFail() { |
||||||
|
//ALog.d(TAG,
|
||||||
|
// String.format("isFail; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s", mStopNum,
|
||||||
|
// mCancelNum, mFailNum, mCompleteNum));
|
||||||
|
return mCompleteNum.get() != mThreadNum |
||||||
|
&& (mFailNum.get() == mThreadNum || mFailNum.get() + mCompleteNum.get() == mThreadNum); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 所有子线程是否都已经完成 |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public boolean isComplete() { |
||||||
|
//ALog.d(TAG,
|
||||||
|
// String.format("isComplete; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s",
|
||||||
|
// mStopNum,
|
||||||
|
// mCancelNum, mFailNum, mCompleteNum));
|
||||||
|
return mCompleteNum.get() == mThreadNum; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 所有子线程是否都已经取消 |
||||||
|
*/ |
||||||
|
public boolean isCancel() { |
||||||
|
//ALog.d(TAG, String.format("isCancel; stopNum: %s, cancelNum: %s, failNum: %s, completeNum: %s",
|
||||||
|
// mStopNum,
|
||||||
|
// mCancelNum, mFailNum, mCompleteNum));
|
||||||
|
return mCancelNum.get() == mThreadNum; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 更新分块任务s的真实进度 |
||||||
|
*/ |
||||||
|
private long updateBlockProgress() { |
||||||
|
long size = 0; |
||||||
|
for (int i = 0, len = mTaskRecord.threadRecords.size(); i < len; i++) { |
||||||
|
File temp = new File(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, i)); |
||||||
|
if (temp.exists()) { |
||||||
|
size += temp.length(); |
||||||
|
} |
||||||
|
} |
||||||
|
return size; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 合并sftp的分块 |
||||||
|
*/ |
||||||
|
private boolean mergerSFtp() { |
||||||
|
if (mTaskRecord.threadNum == 1) { |
||||||
|
File partFile = new File(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, 0)); |
||||||
|
return partFile.renameTo(new File(mTaskRecord.filePath)); |
||||||
|
} |
||||||
|
|
||||||
|
List<String> partPath = new ArrayList<>(); |
||||||
|
for (int i = 0, len = mTaskRecord.threadNum; i < len; i++) { |
||||||
|
partPath.add(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, i)); |
||||||
|
} |
||||||
|
FileUtil.mergeSFtpFile(mTaskRecord.filePath, partPath, mTaskRecord.fileLength); |
||||||
|
for (String pp : partPath) { |
||||||
|
FileUtil.deleteFile(pp); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 合并文件 |
||||||
|
* |
||||||
|
* @return {@code true} 合并成功,{@code false}合并失败 |
||||||
|
*/ |
||||||
|
private boolean mergeFile() { |
||||||
|
if (mTaskRecord.threadNum == 1) { |
||||||
|
File targetFile = new File(mTaskRecord.filePath); |
||||||
|
if (targetFile.exists() && targetFile.length() == mTaskRecord.fileLength){ |
||||||
|
return true; |
||||||
|
} |
||||||
|
FileUtil.deleteFile(targetFile); |
||||||
|
File partFile = new File(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, 0)); |
||||||
|
return partFile.renameTo(targetFile); |
||||||
|
} |
||||||
|
|
||||||
|
List<String> partPath = new ArrayList<>(); |
||||||
|
for (int i = 0, len = mTaskRecord.threadNum; i < len; i++) { |
||||||
|
partPath.add(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, i)); |
||||||
|
} |
||||||
|
boolean isSuccess = FileUtil.mergeFile(mTaskRecord.filePath, partPath); |
||||||
|
if (isSuccess) { |
||||||
|
for (String pp : partPath) { |
||||||
|
FileUtil.deleteFile(pp); |
||||||
|
} |
||||||
|
File targetFile = new File(mTaskRecord.filePath); |
||||||
|
if (targetFile.exists() && targetFile.length() > mTaskRecord.fileLength) { |
||||||
|
ALog.e(TAG, String.format("任务【%s】分块文件合并失败,下载长度超出文件真实长度,downloadLen: %s,fileSize: %s", |
||||||
|
targetFile.getName(), targetFile.length(), mTaskRecord.fileLength)); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} else { |
||||||
|
ALog.e(TAG, "合并失败"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override public void accept(ILoaderVisitor visitor) { |
||||||
|
visitor.addComponent(this); |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue