parent
c9eb57132b
commit
1e237d795d
@ -0,0 +1,167 @@ |
||||
/* |
||||
* 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.http; |
||||
|
||||
import com.arialyy.aria.core.common.AbsEntity; |
||||
import com.arialyy.aria.core.common.CompleteInfo; |
||||
import com.arialyy.aria.core.download.DGTaskWrapper; |
||||
import com.arialyy.aria.core.download.DTaskWrapper; |
||||
import com.arialyy.aria.core.download.DownloadEntity; |
||||
import com.arialyy.aria.core.listener.DownloadGroupListener; |
||||
import com.arialyy.aria.core.loader.IInfoTask; |
||||
import com.arialyy.aria.core.loader.ILoaderVisitor; |
||||
import com.arialyy.aria.exception.AriaIOException; |
||||
import com.arialyy.aria.exception.BaseException; |
||||
import com.arialyy.aria.util.ALog; |
||||
import com.arialyy.aria.util.CommonUtil; |
||||
import java.util.concurrent.ExecutorService; |
||||
import java.util.concurrent.Executors; |
||||
|
||||
/** |
||||
* 组合任务文件信息,用于获取长度未知时,组合任务的长度 |
||||
*/ |
||||
public class HttpGroupInfoTask implements IInfoTask { |
||||
private String TAG = CommonUtil.getClassName(this); |
||||
private Callback callback; |
||||
private DGTaskWrapper wrapper; |
||||
private final Object LOCK = new Object(); |
||||
private ExecutorService mPool = null; |
||||
private boolean getLenComplete = false; |
||||
private int count; |
||||
private int failCount; |
||||
private DownloadGroupListener listener; |
||||
|
||||
/** |
||||
* 子任务回调 |
||||
*/ |
||||
private Callback subCallback = new Callback() { |
||||
@Override public void onSucceed(String url, CompleteInfo info) { |
||||
count++; |
||||
checkGetSizeComplete(count, failCount); |
||||
ALog.d(TAG, "获取子任务信息完成"); |
||||
} |
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { |
||||
ALog.e(TAG, String.format("获取文件信息失败,url:%s", ((DownloadEntity) entity).getUrl())); |
||||
count++; |
||||
failCount++; |
||||
listener.onSubFail((DownloadEntity) entity, new AriaIOException(TAG, |
||||
String.format("子任务获取文件长度失败,url:%s", ((DownloadEntity) entity).getUrl()))); |
||||
checkGetSizeComplete(count, failCount); |
||||
} |
||||
}; |
||||
|
||||
public HttpGroupInfoTask(DGTaskWrapper wrapper, DownloadGroupListener listener) { |
||||
this.wrapper = wrapper; |
||||
this.listener = listener; |
||||
} |
||||
|
||||
@Override public void run() { |
||||
// 如果是isUnknownSize()标志,并且获取大小没有完成,则直接回调onStop
|
||||
if (mPool != null && !getLenComplete) { |
||||
ALog.d(TAG, "获取长度未完成的情况下,停止组合任务"); |
||||
mPool.shutdown(); |
||||
//mListener.onStop(0);
|
||||
return; |
||||
} |
||||
// 处理组合任务大小未知的情况
|
||||
if (wrapper.isUnknownSize() && wrapper.getEntity().getFileSize() < 1) { |
||||
mPool = Executors.newCachedThreadPool(); |
||||
getGroupSize(); |
||||
try { |
||||
synchronized (LOCK) { |
||||
LOCK.wait(); |
||||
} |
||||
} catch (InterruptedException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} else { |
||||
for (DTaskWrapper wrapper : wrapper.getSubTaskWrapper()) { |
||||
cloneHeader(wrapper); |
||||
} |
||||
callback.onSucceed(wrapper.getKey(), new CompleteInfo()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取组合任务大小,使用该方式获取到的组合任务大小,子任务不需要再重新获取文件大小 |
||||
*/ |
||||
private void getGroupSize() { |
||||
new Thread(new Runnable() { |
||||
@Override public void run() { |
||||
for (DTaskWrapper dTaskWrapper : wrapper.getSubTaskWrapper()) { |
||||
cloneHeader(dTaskWrapper); |
||||
HttpFileInfoTask infoTask = new HttpFileInfoTask(dTaskWrapper); |
||||
infoTask.setCallback(subCallback); |
||||
} |
||||
} |
||||
}).start(); |
||||
} |
||||
|
||||
/** |
||||
* 检查组合任务大小是否获取完成,获取完成后取消阻塞,并设置组合任务大小 |
||||
*/ |
||||
private void checkGetSizeComplete(int count, int failCount) { |
||||
if (failCount == wrapper.getSubTaskWrapper().size()) { |
||||
callback.onFail(wrapper.getEntity(), new AriaIOException(TAG, "获取子任务长度失败"), false); |
||||
notifyLock(); |
||||
return; |
||||
} |
||||
if (count == wrapper.getSubTaskWrapper().size()) { |
||||
long size = 0; |
||||
for (DTaskWrapper wrapper : wrapper.getSubTaskWrapper()) { |
||||
size += wrapper.getEntity().getFileSize(); |
||||
} |
||||
wrapper.getEntity().setConvertFileSize(CommonUtil.formatFileSize(size)); |
||||
wrapper.getEntity().setFileSize(size); |
||||
wrapper.getEntity().update(); |
||||
getLenComplete = true; |
||||
ALog.d(TAG, String.format("获取组合任务长度完成,组合任务总长度:%s,失败的只任务数:%s", size, failCount)); |
||||
callback.onSucceed(wrapper.getKey(), new CompleteInfo()); |
||||
notifyLock(); |
||||
} |
||||
} |
||||
|
||||
private void notifyLock() { |
||||
synchronized (LOCK) { |
||||
LOCK.notifyAll(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 子任务使用父包裹器的属性 |
||||
*/ |
||||
private void cloneHeader(DTaskWrapper taskWrapper) { |
||||
HttpTaskOption groupOption = (HttpTaskOption) wrapper.getTaskOption(); |
||||
HttpTaskOption subOption = new HttpTaskOption(); |
||||
|
||||
// 设置属性
|
||||
subOption.setFileLenAdapter(groupOption.getFileLenAdapter()); |
||||
subOption.setRequestEnum(groupOption.getRequestEnum()); |
||||
subOption.setHeaders(groupOption.getHeaders()); |
||||
subOption.setProxy(groupOption.getProxy()); |
||||
subOption.setParams(groupOption.getParams()); |
||||
taskWrapper.setTaskOption(subOption); |
||||
} |
||||
|
||||
@Override public void setCallback(Callback callback) { |
||||
this.callback = callback; |
||||
} |
||||
|
||||
@Override public void accept(ILoaderVisitor visitor) { |
||||
visitor.addComponent(this); |
||||
} |
||||
} |
@ -1,100 +1,100 @@ |
||||
/* |
||||
* 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.http.download; |
||||
|
||||
import com.arialyy.aria.core.TaskRecord; |
||||
import com.arialyy.aria.core.common.RecordHandler; |
||||
import com.arialyy.aria.core.common.SubThreadConfig; |
||||
import com.arialyy.aria.core.download.DownloadEntity; |
||||
import com.arialyy.aria.core.inf.IRecordHandler; |
||||
import com.arialyy.aria.core.task.AbsNormalLoaderAdapter; |
||||
import com.arialyy.aria.core.task.IThreadTask; |
||||
import com.arialyy.aria.core.task.ThreadTask; |
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; |
||||
import com.arialyy.aria.http.HttpRecordAdapter; |
||||
import com.arialyy.aria.util.ALog; |
||||
import com.arialyy.aria.util.BufferedRandomAccessFile; |
||||
import com.arialyy.aria.util.FileUtil; |
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* @Author lyy |
||||
* @Date 2019-09-21 |
||||
*/ |
||||
final class HttpDLoaderAdapter extends AbsNormalLoaderAdapter { |
||||
HttpDLoaderAdapter(ITaskWrapper wrapper) { |
||||
super(wrapper); |
||||
} |
||||
|
||||
@Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) { |
||||
if (!record.isBlock) { |
||||
if (getTempFile().exists()) { |
||||
FileUtil.deleteFile(getTempFile()); |
||||
} |
||||
} else { |
||||
for (int i = 0; i < totalThreadNum; i++) { |
||||
File blockFile = |
||||
new File(String.format(IRecordHandler.SUB_PATH, getTempFile().getPath(), i)); |
||||
if (blockFile.exists()) { |
||||
ALog.d(TAG, String.format("分块【%s】已经存在,将删除该分块", i)); |
||||
FileUtil.deleteFile(blockFile); |
||||
} |
||||
} |
||||
} |
||||
BufferedRandomAccessFile file = null; |
||||
try { |
||||
if (totalThreadNum > 1 && !record.isBlock) { |
||||
file = new BufferedRandomAccessFile(new File(getTempFile().getPath()), "rwd", 8192); |
||||
//设置文件长度
|
||||
file.setLength(getEntity().getFileSize()); |
||||
} |
||||
return true; |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
ALog.e(TAG, String.format("下载失败,filePath: %s, url: %s", getEntity().getFilePath(), |
||||
getEntity().getUrl())); |
||||
} finally { |
||||
if (file != null) { |
||||
try { |
||||
file.close(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
@Override public IThreadTask createThreadTask(SubThreadConfig config) { |
||||
ThreadTask task = new ThreadTask(config); |
||||
HttpDThreadTaskAdapter adapter = new HttpDThreadTaskAdapter(config); |
||||
task.setAdapter(adapter); |
||||
return task; |
||||
} |
||||
|
||||
@Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) { |
||||
RecordHandler recordHandler = new RecordHandler(wrapper); |
||||
HttpRecordAdapter adapter = new HttpRecordAdapter(wrapper); |
||||
recordHandler.setAdapter(adapter); |
||||
return recordHandler; |
||||
} |
||||
|
||||
private DownloadEntity getEntity() { |
||||
return (DownloadEntity) getWrapper().getEntity(); |
||||
} |
||||
} |
||||
///*
|
||||
// * 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.http.download;
|
||||
//
|
||||
//import com.arialyy.aria.core.TaskRecord;
|
||||
//import com.arialyy.aria.core.common.RecordHandler;
|
||||
//import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
//import com.arialyy.aria.core.download.DownloadEntity;
|
||||
//import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
//import com.arialyy.aria.core.task.AbsNormalLoaderAdapter;
|
||||
//import com.arialyy.aria.core.task.IThreadTask;
|
||||
//import com.arialyy.aria.core.task.ThreadTask;
|
||||
//import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
//import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
//import com.arialyy.aria.http.HttpRecordHandler;
|
||||
//import com.arialyy.aria.util.ALog;
|
||||
//import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||
//import com.arialyy.aria.util.FileUtil;
|
||||
//import java.io.File;
|
||||
//import java.io.IOException;
|
||||
//
|
||||
///**
|
||||
// * @Author lyy
|
||||
// * @Date 2019-09-21
|
||||
// */
|
||||
//final class HttpDLoaderAdapter extends AbsNormalLoaderAdapter {
|
||||
// HttpDLoaderAdapter(ITaskWrapper wrapper) {
|
||||
// super(wrapper);
|
||||
// }
|
||||
//
|
||||
// @Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) {
|
||||
// if (!record.isBlock) {
|
||||
// if (getTempFile().exists()) {
|
||||
// FileUtil.deleteFile(getTempFile());
|
||||
// }
|
||||
// } else {
|
||||
// for (int i = 0; i < totalThreadNum; i++) {
|
||||
// File blockFile =
|
||||
// new File(String.format(IRecordHandler.SUB_PATH, getTempFile().getPath(), i));
|
||||
// if (blockFile.exists()) {
|
||||
// ALog.d(TAG, String.format("分块【%s】已经存在,将删除该分块", i));
|
||||
// FileUtil.deleteFile(blockFile);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// BufferedRandomAccessFile file = null;
|
||||
// try {
|
||||
// if (totalThreadNum > 1 && !record.isBlock) {
|
||||
// file = new BufferedRandomAccessFile(new File(getTempFile().getPath()), "rwd", 8192);
|
||||
// //设置文件长度
|
||||
// file.setLength(getEntity().getFileSize());
|
||||
// }
|
||||
// return true;
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// ALog.e(TAG, String.format("下载失败,filePath: %s, url: %s", getEntity().getFilePath(),
|
||||
// getEntity().getUrl()));
|
||||
// } finally {
|
||||
// if (file != null) {
|
||||
// try {
|
||||
// file.close();
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override public IThreadTask createThreadTask(SubThreadConfig config) {
|
||||
// ThreadTask task = new ThreadTask(config);
|
||||
// HttpDThreadTaskAdapter adapter = new HttpDThreadTaskAdapter(config);
|
||||
// task.setAdapter(adapter);
|
||||
// return task;
|
||||
// }
|
||||
//
|
||||
// @Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) {
|
||||
// RecordHandler recordHandler = new RecordHandler(wrapper);
|
||||
// HttpRecordHandler adapter = new HttpRecordHandler(wrapper);
|
||||
// recordHandler.setAdapter(adapter);
|
||||
// return recordHandler;
|
||||
// }
|
||||
//
|
||||
// private DownloadEntity getEntity() {
|
||||
// return (DownloadEntity) getWrapper().getEntity();
|
||||
// }
|
||||
//}
|
||||
|
@ -0,0 +1,62 @@ |
||||
package com.arialyy.aria.http.download; |
||||
|
||||
import com.arialyy.aria.core.TaskRecord; |
||||
import com.arialyy.aria.core.common.SubThreadConfig; |
||||
import com.arialyy.aria.core.loader.AbsNormalTTBuilder; |
||||
import com.arialyy.aria.core.loader.IRecordHandler; |
||||
import com.arialyy.aria.core.task.IThreadTaskAdapter; |
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
||||
import com.arialyy.aria.util.ALog; |
||||
import com.arialyy.aria.util.BufferedRandomAccessFile; |
||||
import com.arialyy.aria.util.FileUtil; |
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
|
||||
final class HttpDTTBuilder extends AbsNormalTTBuilder { |
||||
HttpDTTBuilder(AbsTaskWrapper wrapper) { |
||||
super(wrapper); |
||||
} |
||||
|
||||
@Override public IThreadTaskAdapter getAdapter(SubThreadConfig config) { |
||||
return new HttpDThreadTaskAdapter(config); |
||||
} |
||||
|
||||
@Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) { |
||||
if (!record.isBlock) { |
||||
if (getTempFile().exists()) { |
||||
FileUtil.deleteFile(getTempFile()); |
||||
} |
||||
} else { |
||||
for (int i = 0; i < totalThreadNum; i++) { |
||||
File blockFile = |
||||
new File(String.format(IRecordHandler.SUB_PATH, getTempFile().getPath(), i)); |
||||
if (blockFile.exists()) { |
||||
ALog.d(TAG, String.format("分块【%s】已经存在,将删除该分块", i)); |
||||
FileUtil.deleteFile(blockFile); |
||||
} |
||||
} |
||||
} |
||||
BufferedRandomAccessFile file = null; |
||||
try { |
||||
if (totalThreadNum > 1 && !record.isBlock) { |
||||
file = new BufferedRandomAccessFile(new File(getTempFile().getPath()), "rwd", 8192); |
||||
//设置文件长度
|
||||
file.setLength(getEntity().getFileSize()); |
||||
} |
||||
return true; |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
ALog.e(TAG, String.format("下载失败,filePath: %s, url: %s", getEntity().getFilePath(), |
||||
getEntity().getUrl())); |
||||
} finally { |
||||
if (file != null) { |
||||
try { |
||||
file.close(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
@ -1,44 +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.common; |
||||
|
||||
import com.arialyy.aria.core.inf.IRecordHandlerAdapter; |
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
||||
import com.arialyy.aria.util.CommonUtil; |
||||
|
||||
/** |
||||
* @Author lyy |
||||
* @Date 2019-09-19 |
||||
*/ |
||||
public abstract class AbsRecordHandlerAdapter implements IRecordHandlerAdapter { |
||||
private AbsTaskWrapper mWrapper; |
||||
protected String TAG = CommonUtil.getClassName(getClass()); |
||||
|
||||
@Override public void onPre() { |
||||
} |
||||
|
||||
public AbsRecordHandlerAdapter(AbsTaskWrapper wrapper) { |
||||
mWrapper = wrapper; |
||||
} |
||||
|
||||
public AbsTaskWrapper getWrapper() { |
||||
return mWrapper; |
||||
} |
||||
|
||||
protected AbsNormalEntity getEntity() { |
||||
return (AbsNormalEntity) getWrapper().getEntity(); |
||||
} |
||||
} |
@ -0,0 +1,185 @@ |
||||
package com.arialyy.aria.core.loader; |
||||
|
||||
import android.os.Handler; |
||||
import android.os.Looper; |
||||
import com.arialyy.aria.core.TaskRecord; |
||||
import com.arialyy.aria.core.ThreadRecord; |
||||
import com.arialyy.aria.core.common.AbsNormalEntity; |
||||
import com.arialyy.aria.core.common.SubThreadConfig; |
||||
import com.arialyy.aria.core.download.DGTaskWrapper; |
||||
import com.arialyy.aria.core.inf.IThreadState; |
||||
import com.arialyy.aria.core.task.IThreadTask; |
||||
import com.arialyy.aria.core.task.IThreadTaskAdapter; |
||||
import com.arialyy.aria.core.task.ThreadTask; |
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
||||
import com.arialyy.aria.util.ALog; |
||||
import com.arialyy.aria.util.CommonUtil; |
||||
import java.io.File; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
public abstract class AbsNormalTTBuilder implements IThreadTaskBuilder { |
||||
protected String TAG = CommonUtil.getClassName(this); |
||||
|
||||
private Handler mStateHandler; |
||||
private AbsTaskWrapper mWrapper; |
||||
private TaskRecord mRecord; |
||||
private int mTotalThreadNum; |
||||
private File mTempFile; |
||||
private int mStartThreadNum; |
||||
|
||||
public AbsNormalTTBuilder(AbsTaskWrapper wrapper) { |
||||
if (wrapper instanceof DGTaskWrapper) { |
||||
throw new AssertionError("NormalTTBuilder 不适用于组合任务"); |
||||
} |
||||
mWrapper = wrapper; |
||||
mTempFile = new File(((AbsNormalEntity) wrapper.getEntity()).getFilePath()); |
||||
} |
||||
|
||||
protected File getTempFile(){ |
||||
return mTempFile; |
||||
} |
||||
|
||||
protected AbsNormalEntity getEntity() { |
||||
return (AbsNormalEntity) mWrapper.getEntity(); |
||||
} |
||||
|
||||
/** |
||||
* 创建线程任务适配器 |
||||
*/ |
||||
public abstract IThreadTaskAdapter getAdapter(SubThreadConfig config); |
||||
|
||||
/** |
||||
* 处理新任务 |
||||
* |
||||
* @param record 任务记录 |
||||
* @param totalThreadNum 任务的线程总数 |
||||
* @return {@code true}创建新任务成功 |
||||
*/ |
||||
public abstract boolean handleNewTask(TaskRecord record, int totalThreadNum); |
||||
|
||||
/** |
||||
* 创建线程任务 |
||||
*/ |
||||
private IThreadTask createThreadTask(SubThreadConfig config) { |
||||
ThreadTask task = new ThreadTask(config); |
||||
task.setAdapter(getAdapter(config)); |
||||
return task; |
||||
} |
||||
|
||||
/** |
||||
* 启动断点任务时,创建单线程任务 |
||||
* |
||||
* @param record 线程记录 |
||||
* @param startNum 启动的线程数 |
||||
*/ |
||||
private IThreadTask createSingThreadTask(ThreadRecord record, int startNum) { |
||||
SubThreadConfig config = new SubThreadConfig(); |
||||
config.url = getEntity().isRedirect() ? getEntity().getRedirectUrl() : getEntity().getUrl(); |
||||
config.tempFile = |
||||
mRecord.isBlock ? new File( |
||||
String.format(IRecordHandler.SUB_PATH, mTempFile.getPath(), record.threadId)) |
||||
: mTempFile; |
||||
config.isBlock = mRecord.isBlock; |
||||
config.startThreadNum = startNum; |
||||
config.taskWrapper = mWrapper; |
||||
config.record = record; |
||||
config.stateHandler = mStateHandler; |
||||
return createThreadTask(config); |
||||
} |
||||
|
||||
/** |
||||
* 处理不支持断点的任务 |
||||
*/ |
||||
private List<IThreadTask> handleNoSupportBP() { |
||||
List<IThreadTask> list = new ArrayList<>(); |
||||
mStartThreadNum = 1; |
||||
|
||||
IThreadTask task = createSingThreadTask(mRecord.threadRecords.get(0), 1); |
||||
if (task == null) { |
||||
ALog.e(TAG, "创建线程任务失败"); |
||||
return null; |
||||
} |
||||
list.add(task); |
||||
return list; |
||||
} |
||||
|
||||
/** |
||||
* 处理支持断点的任务 |
||||
*/ |
||||
private List<IThreadTask> handleBreakpoint() { |
||||
long fileLength = getEntity().getFileSize(); |
||||
long blockSize = fileLength / mTotalThreadNum; |
||||
long currentProgress = 0; |
||||
List<IThreadTask> threadTasks = new ArrayList<>(); |
||||
|
||||
mRecord.fileLength = fileLength; |
||||
if (mWrapper.isNewTask() && !handleNewTask(mRecord, mTotalThreadNum)) { |
||||
ALog.e(TAG, "初始化线程任务失败"); |
||||
return null; |
||||
} |
||||
|
||||
for (ThreadRecord tr : mRecord.threadRecords) { |
||||
if (!tr.isComplete) { |
||||
mStartThreadNum++; |
||||
} |
||||
} |
||||
|
||||
for (int i = 0; i < mTotalThreadNum; i++) { |
||||
long startL = i * blockSize, endL = (i + 1) * blockSize; |
||||
ThreadRecord tr = mRecord.threadRecords.get(i); |
||||
|
||||
if (tr.isComplete) {//该线程已经完成
|
||||
currentProgress += endL - startL; |
||||
ALog.d(TAG, String.format("任务【%s】线程__%s__已完成", mWrapper.getKey(), i)); |
||||
mStateHandler.obtainMessage(IThreadState.STATE_COMPLETE).sendToTarget(); |
||||
continue; |
||||
} |
||||
|
||||
//如果有记录,则恢复任务
|
||||
long r = tr.startLocation; |
||||
//记录的位置需要在线程区间中
|
||||
if (startL < r && r <= (i == (mTotalThreadNum - 1) ? fileLength : endL)) { |
||||
currentProgress += r - startL; |
||||
} |
||||
ALog.d(TAG, String.format("任务【%s】线程__%s__恢复任务", getEntity().getFileName(), i)); |
||||
|
||||
IThreadTask task = createSingThreadTask(tr, mStartThreadNum); |
||||
if (task == null) { |
||||
ALog.e(TAG, "创建线程任务失败"); |
||||
return null; |
||||
} |
||||
threadTasks.add(task); |
||||
} |
||||
if (currentProgress != 0 && currentProgress != getEntity().getCurrentProgress()) { |
||||
ALog.d(TAG, String.format("进度修正,当前进度:%s", currentProgress)); |
||||
getEntity().setCurrentProgress(currentProgress); |
||||
} |
||||
//mStateManager.updateProgress(currentProgress);
|
||||
return threadTasks; |
||||
} |
||||
|
||||
private List<IThreadTask> handleTask() { |
||||
if (mWrapper.isSupportBP()) { |
||||
return handleBreakpoint(); |
||||
}else { |
||||
return handleNoSupportBP(); |
||||
} |
||||
} |
||||
|
||||
@Override public List<IThreadTask> buildThreadTask(TaskRecord record, Looper looper, |
||||
IThreadState stateManager) { |
||||
mRecord = record; |
||||
mStateHandler = new Handler(looper, stateManager.getHandlerCallback()); |
||||
mTotalThreadNum = mRecord.threadNum; |
||||
return handleTask(); |
||||
} |
||||
|
||||
@Override public int getCreatedThreadNum() { |
||||
return mStartThreadNum; |
||||
} |
||||
|
||||
@Override public void accept(ILoaderVisitor visitor) { |
||||
visitor.addComponent(this); |
||||
} |
||||
} |
@ -1,75 +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.loader; |
||||
|
||||
import com.arialyy.aria.core.TaskRecord; |
||||
import com.arialyy.aria.core.listener.IEventListener; |
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 责任链 |
||||
*/ |
||||
public final class LoaderChain implements ILoaderInterceptor.Chain { |
||||
private ITaskWrapper wrapper; |
||||
private IEventListener listener; |
||||
private TaskRecord taskRecord; |
||||
private int index; |
||||
private List<ILoaderInterceptor> interceptors; |
||||
|
||||
public LoaderChain(List<ILoaderInterceptor> interceptors, ITaskWrapper wrapper, |
||||
IEventListener listener, TaskRecord taskRecord, |
||||
int index) { |
||||
this.interceptors = interceptors; |
||||
this.wrapper = wrapper; |
||||
this.listener = listener; |
||||
this.taskRecord = taskRecord; |
||||
this.index = index; |
||||
} |
||||
|
||||
@Override public void updateRecord(TaskRecord record) { |
||||
this.taskRecord = record; |
||||
} |
||||
|
||||
@Override public TaskRecord getRecord() { |
||||
return taskRecord; |
||||
} |
||||
|
||||
@Override public IEventListener getListener() { |
||||
return listener; |
||||
} |
||||
|
||||
@Override public ITaskWrapper getWrapper() { |
||||
return wrapper; |
||||
} |
||||
|
||||
@Override public ILoader proceed() { |
||||
int index = this.index + 1; |
||||
if (index >= interceptors.size()) { |
||||
throw new AssertionError(); |
||||
} |
||||
|
||||
LoaderChain next = new LoaderChain(interceptors, wrapper, listener, taskRecord, index); |
||||
ILoaderInterceptor interceptor = interceptors.get(index); |
||||
ILoader loader = interceptor.intercept(next); |
||||
|
||||
if (loader == null) { |
||||
throw new NullPointerException("Loader为空"); |
||||
} |
||||
|
||||
return loader; |
||||
} |
||||
} |
Loading…
Reference in new issue