loader 优化
This commit is contained in:
@@ -35,7 +35,7 @@ import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.download.DownloadReceiver;
|
||||
import com.arialyy.aria.core.inf.AbsReceiver;
|
||||
import com.arialyy.aria.core.inf.IReceiver;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.inf.ReceiverType;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.upload.UploadReceiver;
|
||||
|
||||
@@ -19,7 +19,7 @@ import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import java.io.File;
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public class FTPFile implements Serializable {
|
||||
/** A constant indicating file/directory write permission. ***/
|
||||
public static final int WRITE_PERMISSION = 1;
|
||||
/**
|
||||
* A constant indicating file execute permission or directory listing
|
||||
* A constant indicating file accept permission or directory listing
|
||||
* permission.
|
||||
***/
|
||||
public static final int EXECUTE_PERMISSION = 2;
|
||||
|
||||
@@ -95,7 +95,7 @@ public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
|
||||
* Netware file permissions are in the following format: RWCEAFMS, and are explained as follows:
|
||||
* <ul>
|
||||
* <li><b>S</b> - Supervisor; All rights.
|
||||
* <li><b>R</b> - Read; Right to open and read or execute.
|
||||
* <li><b>R</b> - Read; Right to open and read or accept.
|
||||
* <li><b>W</b> - Write; Right to open and modify.
|
||||
* <li><b>C</b> - Create; Right to create; when assigned to a file, allows a deleted file to be
|
||||
* recovered.
|
||||
|
||||
@@ -164,7 +164,7 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
|
||||
|
||||
//Set file permission.
|
||||
//VMS has (SYSTEM,OWNER,GROUP,WORLD) users that can contain
|
||||
//R (read) W (write) E (execute) D (delete)
|
||||
//R (read) W (write) E (accept) D (delete)
|
||||
|
||||
//iterate for OWNER GROUP WORLD permissions
|
||||
for (int access = 0; access < 3; access++) {
|
||||
|
||||
@@ -17,11 +17,11 @@ package com.arialyy.aria.ftp;
|
||||
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
import com.arialyy.aria.core.common.AbsRecordHandlerAdapter;
|
||||
import com.arialyy.aria.core.common.RecordHandler;
|
||||
import com.arialyy.aria.core.common.RecordHelper;
|
||||
import com.arialyy.aria.core.config.Configuration;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
@@ -31,9 +31,9 @@ import java.util.ArrayList;
|
||||
* @Author lyy
|
||||
* @Date 2019-09-19
|
||||
*/
|
||||
public class FtpRecordAdapter extends AbsRecordHandlerAdapter {
|
||||
public class FtpRecordHandler extends RecordHandler {
|
||||
|
||||
public FtpRecordAdapter(AbsTaskWrapper wrapper) {
|
||||
public FtpRecordHandler(AbsTaskWrapper wrapper) {
|
||||
super(wrapper);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,13 @@ package com.arialyy.aria.ftp.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.inf.IRecordHandler;
|
||||
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.ftp.FtpRecordAdapter;
|
||||
import com.arialyy.aria.ftp.FtpRecordHandler;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
import java.io.File;
|
||||
@@ -66,7 +66,7 @@ public class FtpDLoaderAdapter extends AbsNormalLoaderAdapter {
|
||||
}
|
||||
|
||||
@Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) {
|
||||
FtpRecordAdapter adapter = new FtpRecordAdapter(wrapper);
|
||||
FtpRecordHandler adapter = new FtpRecordHandler(wrapper);
|
||||
RecordHandler handler = new RecordHandler(wrapper);
|
||||
handler.setAdapter(adapter);
|
||||
return handler;
|
||||
|
||||
@@ -21,7 +21,7 @@ import com.arialyy.aria.core.FtpUrlEntity;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.common.CompleteInfo;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.group.AbsGroupUtil;
|
||||
import com.arialyy.aria.core.group.AbsGroupLoaderUtil;
|
||||
import com.arialyy.aria.core.group.AbsSubDLoadUtil;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.OnFileInfoCallback;
|
||||
@@ -37,7 +37,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
* Created by Aria.Lao on 2017/7/27.
|
||||
* ftp文件夹下载工具
|
||||
*/
|
||||
public class FtpDirDLoaderUtil extends AbsGroupUtil {
|
||||
public class FtpDirDLoaderUtil extends AbsGroupLoaderUtil {
|
||||
private ReentrantLock LOCK = new ReentrantLock();
|
||||
private Condition condition = LOCK.newCondition();
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@ import com.arialyy.aria.core.common.RecordHandler;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.task.ThreadTask;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.task.IThreadTask;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.ftp.FtpRecordAdapter;
|
||||
import com.arialyy.aria.ftp.FtpRecordHandler;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
@@ -48,7 +48,7 @@ class FtpULoaferAdapter extends AbsNormalLoaderAdapter {
|
||||
}
|
||||
|
||||
@Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) {
|
||||
FtpRecordAdapter adapter = new FtpRecordAdapter(wrapper);
|
||||
FtpRecordHandler adapter = new FtpRecordHandler(wrapper);
|
||||
RecordHandler handler = new RecordHandler(wrapper);
|
||||
handler.setAdapter(adapter);
|
||||
return handler;
|
||||
|
||||
@@ -24,7 +24,8 @@ import com.arialyy.aria.core.common.CompleteInfo;
|
||||
import com.arialyy.aria.core.common.RequestEnum;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.inf.OnFileInfoCallback;
|
||||
import com.arialyy.aria.core.loader.IInfoTask;
|
||||
import com.arialyy.aria.core.loader.ILoaderVisitor;
|
||||
import com.arialyy.aria.core.processor.IHttpFileLenAdapter;
|
||||
import com.arialyy.aria.exception.AriaIOException;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
@@ -54,19 +55,18 @@ import java.util.UUID;
|
||||
/**
|
||||
* 下载文件信息获取
|
||||
*/
|
||||
public class HttpFileInfoThread implements Runnable {
|
||||
public class HttpFileInfoTask implements IInfoTask, Runnable {
|
||||
private static final String TAG = "HttpFileInfoThread";
|
||||
private DownloadEntity mEntity;
|
||||
private DTaskWrapper mTaskWrapper;
|
||||
private int mConnectTimeOut;
|
||||
private OnFileInfoCallback onFileInfoCallback;
|
||||
private Callback callback;
|
||||
private HttpTaskOption taskOption;
|
||||
|
||||
public HttpFileInfoThread(DTaskWrapper taskWrapper, OnFileInfoCallback callback) {
|
||||
public HttpFileInfoTask(DTaskWrapper taskWrapper) {
|
||||
this.mTaskWrapper = taskWrapper;
|
||||
mEntity = taskWrapper.getEntity();
|
||||
mConnectTimeOut = AriaConfig.getInstance().getDConfig().getConnectTimeOut();
|
||||
onFileInfoCallback = callback;
|
||||
taskOption = (HttpTaskOption) taskWrapper.getTaskOption();
|
||||
}
|
||||
|
||||
@@ -99,6 +99,10 @@ public class HttpFileInfoThread implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void setCallback(Callback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
private void handleConnect(HttpURLConnection conn) throws IOException {
|
||||
if (taskOption.getRequestEnum() == RequestEnum.POST) {
|
||||
Map<String, String> params = taskOption.getParams();
|
||||
@@ -223,9 +227,9 @@ public class HttpFileInfoThread implements Runnable {
|
||||
}
|
||||
if (end) {
|
||||
taskOption.setChunked(isChunked);
|
||||
if (onFileInfoCallback != null) {
|
||||
if (callback != null) {
|
||||
CompleteInfo info = new CompleteInfo(code, mTaskWrapper);
|
||||
onFileInfoCallback.onComplete(mEntity.getUrl(), info);
|
||||
callback.onSucceed(mEntity.getUrl(), info);
|
||||
}
|
||||
mEntity.update();
|
||||
}
|
||||
@@ -291,8 +295,8 @@ public class HttpFileInfoThread implements Runnable {
|
||||
private void handleUrlReTurn(HttpURLConnection conn, String newUrl) throws IOException {
|
||||
ALog.d(TAG, "30x跳转,新url为【" + newUrl + "】");
|
||||
if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null")) {
|
||||
if (onFileInfoCallback != null) {
|
||||
onFileInfoCallback.onFail(mEntity, new TaskException(TAG, "获取重定向链接失败"), false);
|
||||
if (callback != null) {
|
||||
callback.onFail(mEntity, new TaskException(TAG, "获取重定向链接失败"), false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -336,11 +340,15 @@ public class HttpFileInfoThread implements Runnable {
|
||||
}
|
||||
|
||||
private void failDownload(BaseException e, boolean needRetry) {
|
||||
if (onFileInfoCallback != null) {
|
||||
onFileInfoCallback.onFail(mEntity, e, needRetry);
|
||||
if (callback != null) {
|
||||
callback.onFail(mEntity, e, needRetry);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void accept(ILoaderVisitor visitor) {
|
||||
visitor.addComponent(this);
|
||||
}
|
||||
|
||||
private static class FileLenAdapter implements IHttpFileLenAdapter {
|
||||
|
||||
@Override public long handleFileLen(Map<String, List<String>> headers) {
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,11 @@ package com.arialyy.aria.http;
|
||||
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
import com.arialyy.aria.core.common.AbsRecordHandlerAdapter;
|
||||
import com.arialyy.aria.core.common.RecordHandler;
|
||||
import com.arialyy.aria.core.common.RecordHelper;
|
||||
import com.arialyy.aria.core.config.Configuration;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
@@ -31,16 +31,16 @@ import java.util.ArrayList;
|
||||
* @Author lyy
|
||||
* @Date 2019-09-23
|
||||
*/
|
||||
public class HttpRecordAdapter extends AbsRecordHandlerAdapter {
|
||||
public HttpRecordAdapter(AbsTaskWrapper wrapper) {
|
||||
public class HttpRecordHandler extends RecordHandler {
|
||||
public HttpRecordHandler(AbsTaskWrapper wrapper) {
|
||||
super(wrapper);
|
||||
}
|
||||
|
||||
@Override public void onPre() {
|
||||
super.onPre();
|
||||
if (getWrapper().getRequestType() == ITaskWrapper.U_HTTP) {
|
||||
RecordUtil.delTaskRecord(getEntity().getFilePath(), IRecordHandler.TYPE_UPLOAD);
|
||||
}
|
||||
//if (getWrapper().getRequestType() == ITaskWrapper.U_HTTP) {
|
||||
// RecordUtil.delTaskRecord(getEntity().getFilePath(), IRecordHandler.TYPE_UPLOAD);
|
||||
//}
|
||||
}
|
||||
|
||||
@Override public void handlerTaskRecord(TaskRecord record) {
|
||||
@@ -25,9 +25,9 @@ import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.AriaIOException;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.core.group.AbsGroupUtil;
|
||||
import com.arialyy.aria.core.group.AbsGroupLoaderUtil;
|
||||
import com.arialyy.aria.core.group.AbsSubDLoadUtil;
|
||||
import com.arialyy.aria.http.HttpFileInfoThread;
|
||||
import com.arialyy.aria.http.HttpFileInfoTask;
|
||||
import com.arialyy.aria.http.HttpTaskOption;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
@@ -40,7 +40,7 @@ import java.util.concurrent.Executors;
|
||||
* Created by AriaL on 2017/6/30.
|
||||
* 任务组下载工具
|
||||
*/
|
||||
public class DGroupLoaderUtil extends AbsGroupUtil {
|
||||
public class DGroupLoaderUtil extends AbsGroupLoaderUtil {
|
||||
private final Object LOCK = new Object();
|
||||
private ExecutorService mPool = null;
|
||||
private boolean getLenComplete = false;
|
||||
@@ -113,7 +113,7 @@ public class DGroupLoaderUtil extends AbsGroupUtil {
|
||||
@Override public void run() {
|
||||
for (DTaskWrapper dTaskWrapper : getWrapper().getSubTaskWrapper()) {
|
||||
cloneHeader(dTaskWrapper);
|
||||
mPool.submit(new HttpFileInfoThread(dTaskWrapper, new OnFileInfoCallback() {
|
||||
mPool.submit(new HttpFileInfoTask(dTaskWrapper, new OnFileInfoCallback() {
|
||||
@Override public void onComplete(String url, CompleteInfo info) {
|
||||
if (!getWrapper().isUnknownSize()) {
|
||||
startSubLoader(createSubLoader((DTaskWrapper) info.wrapper, false));
|
||||
|
||||
@@ -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();
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -15,17 +15,16 @@
|
||||
*/
|
||||
package com.arialyy.aria.http.download;
|
||||
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.common.CompleteInfo;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.inf.OnFileInfoCallback;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.core.loader.AbsLoader;
|
||||
import com.arialyy.aria.core.loader.AbsNormalLoaderUtil;
|
||||
import com.arialyy.aria.core.loader.LoaderStructure;
|
||||
import com.arialyy.aria.core.loader.NormalLoader;
|
||||
import com.arialyy.aria.core.loader.ThreadStateManager;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.http.HttpFileInfoThread;
|
||||
import com.arialyy.aria.http.HttpFileInfoTask;
|
||||
import com.arialyy.aria.http.HttpRecordHandler;
|
||||
import com.arialyy.aria.http.HttpTaskOption;
|
||||
|
||||
/**
|
||||
@@ -38,24 +37,17 @@ public class HttpDLoaderUtil extends AbsNormalLoaderUtil {
|
||||
wrapper.generateTaskOption(HttpTaskOption.class);
|
||||
}
|
||||
|
||||
@Override protected AbsLoader createLoader() {
|
||||
NormalLoader loader = new NormalLoader(getListener(), getTaskWrapper());
|
||||
HttpDLoaderAdapter adapter = new HttpDLoaderAdapter(getTaskWrapper());
|
||||
loader.setAdapter(adapter);
|
||||
return loader;
|
||||
@Override public AbsLoader getLoader() {
|
||||
return mLoader == null ? new NormalLoader(getTaskWrapper(), getListener()) : mLoader;
|
||||
}
|
||||
|
||||
@Override protected Runnable createInfoThread() {
|
||||
return new HttpFileInfoThread((DTaskWrapper) getTaskWrapper(), new OnFileInfoCallback() {
|
||||
@Override public void onComplete(String url, CompleteInfo info) {
|
||||
((NormalLoader) getLoader()).updateTempFile();
|
||||
getLoader().start();
|
||||
}
|
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
|
||||
fail(e, needRetry);
|
||||
getLoader().closeTimer();
|
||||
}
|
||||
});
|
||||
public LoaderStructure getLoaderStructure() {
|
||||
LoaderStructure structure = new LoaderStructure();
|
||||
structure.addComponent(new HttpRecordHandler(getTaskWrapper()))
|
||||
.addComponent(new ThreadStateManager(getListener()))
|
||||
.addComponent(new HttpFileInfoTask((DTaskWrapper) getTaskWrapper()))
|
||||
.addComponent(new HttpDTTBuilder(getTaskWrapper()));
|
||||
structure.accept(getLoader());
|
||||
return structure;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ import com.arialyy.aria.core.inf.OnFileInfoCallback;
|
||||
import com.arialyy.aria.core.listener.ISchedulers;
|
||||
import com.arialyy.aria.core.loader.NormalLoader;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.http.HttpFileInfoThread;
|
||||
import com.arialyy.aria.http.HttpFileInfoTask;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
@@ -49,7 +49,7 @@ class HttpSubDLoaderUtil extends AbsSubDLoadUtil {
|
||||
|
||||
@Override public void start() {
|
||||
if (isNeedGetInfo()) {
|
||||
new Thread(new HttpFileInfoThread(getWrapper(), new OnFileInfoCallback() {
|
||||
new Thread(new HttpFileInfoTask(getWrapper(), new OnFileInfoCallback() {
|
||||
|
||||
@Override public void onComplete(String url, CompleteInfo info) {
|
||||
getDownloader().start();
|
||||
|
||||
@@ -18,13 +18,13 @@ package com.arialyy.aria.http.upload;
|
||||
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.inf.IRecordHandler;
|
||||
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.HttpRecordAdapter;
|
||||
import com.arialyy.aria.http.HttpRecordHandler;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
@@ -48,7 +48,7 @@ final class HttpULoaderAdapter extends AbsNormalLoaderAdapter {
|
||||
|
||||
@Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) {
|
||||
RecordHandler recordHandler = new RecordHandler(wrapper);
|
||||
HttpRecordAdapter adapter = new HttpRecordAdapter(wrapper);
|
||||
HttpRecordHandler adapter = new HttpRecordHandler(wrapper);
|
||||
recordHandler.setAdapter(adapter);
|
||||
return recordHandler;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.arialyy.aria.core.common.RecordHandler;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.M3U8Entity;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.core.loader.AbsLoader;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
@@ -142,7 +142,7 @@ public abstract class BaseM3U8Loader extends AbsLoader {
|
||||
|
||||
@Override protected IRecordHandler getRecordHandler(AbsTaskWrapper wrapper) {
|
||||
RecordHandler handler = new RecordHandler(wrapper);
|
||||
M3U8RecordAdapter adapter = new M3U8RecordAdapter((DTaskWrapper) wrapper);
|
||||
M3U8RecordHandler adapter = new M3U8RecordHandler((DTaskWrapper) wrapper);
|
||||
handler.setAdapter(adapter);
|
||||
return handler;
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ package com.arialyy.aria.m3u8;
|
||||
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
import com.arialyy.aria.core.common.AbsRecordHandlerAdapter;
|
||||
import com.arialyy.aria.core.common.RecordHandler;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.M3U8Entity;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
@@ -33,10 +33,10 @@ import java.util.ArrayList;
|
||||
* @Author lyy
|
||||
* @Date 2019-09-24
|
||||
*/
|
||||
public class M3U8RecordAdapter extends AbsRecordHandlerAdapter {
|
||||
public class M3U8RecordHandler extends RecordHandler {
|
||||
private M3U8TaskOption mOption;
|
||||
|
||||
M3U8RecordAdapter(DTaskWrapper wrapper) {
|
||||
M3U8RecordHandler(DTaskWrapper wrapper) {
|
||||
super(wrapper);
|
||||
mOption = (M3U8TaskOption) wrapper.getM3u8Option();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,8 @@ package com.arialyy.aria.core.common;
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.inf.IRecordHandlerAdapter;
|
||||
import com.arialyy.aria.core.loader.ILoaderVisitor;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
@@ -38,22 +38,29 @@ import java.util.Set;
|
||||
/**
|
||||
* 处理任务记录,分配线程区间
|
||||
*/
|
||||
public class RecordHandler implements IRecordHandler {
|
||||
private final String TAG = "RecordHandler";
|
||||
public abstract class RecordHandler implements IRecordHandler {
|
||||
protected final String TAG = CommonUtil.getClassName(this);
|
||||
|
||||
@Deprecated private File mConfigFile;
|
||||
private TaskRecord mTaskRecord;
|
||||
private AbsTaskWrapper mTaskWrapper;
|
||||
private AbsNormalEntity mEntity;
|
||||
private IRecordHandlerAdapter mAdapter;
|
||||
|
||||
public RecordHandler(AbsTaskWrapper wrapper) {
|
||||
mTaskWrapper = wrapper;
|
||||
mEntity = (AbsNormalEntity) mTaskWrapper.getEntity();
|
||||
}
|
||||
|
||||
public void setAdapter(IRecordHandlerAdapter mAdapter) {
|
||||
this.mAdapter = mAdapter;
|
||||
public AbsTaskWrapper getWrapper() {
|
||||
return mTaskWrapper;
|
||||
}
|
||||
|
||||
public AbsNormalEntity getEntity() {
|
||||
return mEntity;
|
||||
}
|
||||
|
||||
@Override public void onPre() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,10 +77,10 @@ public class RecordHandler implements IRecordHandler {
|
||||
if (mConfigFile.exists()) {
|
||||
convertDb();
|
||||
} else {
|
||||
mAdapter.onPre();
|
||||
onPre();
|
||||
mTaskRecord = DbDataHelper.getTaskRecord(getFilePath(), mEntity.getTaskType());
|
||||
if (mTaskRecord == null) {
|
||||
if (!new File(getFilePath()).exists()){
|
||||
if (!new File(getFilePath()).exists()) {
|
||||
FileUtil.createFile(getFilePath());
|
||||
}
|
||||
initRecord(true);
|
||||
@@ -83,14 +90,14 @@ public class RecordHandler implements IRecordHandler {
|
||||
ALog.w(TAG, String.format("文件【%s】不存在,重新分配线程区间", mTaskRecord.filePath));
|
||||
DbEntity.deleteData(ThreadRecord.class, "taskKey=?", mTaskRecord.filePath);
|
||||
mTaskRecord.threadRecords.clear();
|
||||
mTaskRecord.threadNum = mAdapter.initTaskThreadNum();
|
||||
mTaskRecord.threadNum = initTaskThreadNum();
|
||||
initRecord(false);
|
||||
} else if (mTaskRecord.threadRecords == null || mTaskRecord.threadRecords.isEmpty()) {
|
||||
mTaskRecord.threadNum = mAdapter.initTaskThreadNum();
|
||||
mTaskRecord.threadNum = initTaskThreadNum();
|
||||
initRecord(false);
|
||||
}
|
||||
}
|
||||
mAdapter.handlerTaskRecord(mTaskRecord);
|
||||
handlerTaskRecord(mTaskRecord);
|
||||
}
|
||||
saveRecord();
|
||||
return mTaskRecord;
|
||||
@@ -127,7 +134,7 @@ public class RecordHandler implements IRecordHandler {
|
||||
return;
|
||||
}
|
||||
mTaskWrapper.setNewTask(false);
|
||||
mTaskRecord = mAdapter.createTaskRecord(threadNum);
|
||||
mTaskRecord = createTaskRecord(threadNum);
|
||||
mTaskRecord.isBlock = false;
|
||||
File tempFile = new File(getFilePath());
|
||||
for (int i = 0; i < threadNum; i++) {
|
||||
@@ -158,7 +165,7 @@ public class RecordHandler implements IRecordHandler {
|
||||
*/
|
||||
private void initRecord(boolean newRecord) {
|
||||
if (newRecord) {
|
||||
mTaskRecord = mAdapter.createTaskRecord(mAdapter.initTaskThreadNum());
|
||||
mTaskRecord = createTaskRecord(initTaskThreadNum());
|
||||
}
|
||||
mTaskWrapper.setNewTask(true);
|
||||
int requestType = mTaskWrapper.getRequestType();
|
||||
@@ -169,7 +176,7 @@ public class RecordHandler implements IRecordHandler {
|
||||
// 处理线程区间记录
|
||||
for (int i = 0; i < mTaskRecord.threadNum; i++) {
|
||||
long startL = i * blockSize, endL = (i + 1) * blockSize;
|
||||
ThreadRecord tr = mAdapter.createThreadRecord(mTaskRecord, i, startL, endL);
|
||||
ThreadRecord tr = createThreadRecord(mTaskRecord, i, startL, endL);
|
||||
mTaskRecord.threadRecords.add(tr);
|
||||
}
|
||||
}
|
||||
@@ -198,4 +205,23 @@ public class RecordHandler implements IRecordHandler {
|
||||
return ((UploadEntity) mTaskWrapper.getEntity()).getFilePath();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void accept(ILoaderVisitor visitor) {
|
||||
visitor.addComponent(this);
|
||||
}
|
||||
|
||||
@Override public boolean checkTaskCompleted() {
|
||||
if (mTaskRecord == null
|
||||
|| mTaskRecord.threadRecords == null
|
||||
|| mTaskRecord.threadRecords.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
int completeNum = 0;
|
||||
for (ThreadRecord tr : mTaskRecord.threadRecords) {
|
||||
if (tr.isComplete) {
|
||||
completeNum++;
|
||||
}
|
||||
}
|
||||
return completeNum != 0 && completeNum == mTaskRecord.threadNum;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ package com.arialyy.aria.core.common;
|
||||
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||
|
||||
@@ -62,13 +62,13 @@ public class XMLReader extends DefaultHandler {
|
||||
|
||||
String value = attributes.getValue("value");
|
||||
switch (qName) {
|
||||
case "threadNum": // 线程数
|
||||
case "getCreatedThreadNum": // 线程数
|
||||
int threadNum = checkInt(value) ? Integer.parseInt(value) : 3;
|
||||
if (threadNum < 1) {
|
||||
ALog.w(TAG, "下载线程数不能小于 1");
|
||||
threadNum = 1;
|
||||
}
|
||||
setField("threadNum", threadNum, ConfigType.DOWNLOAD);
|
||||
setField("getCreatedThreadNum", threadNum, ConfigType.DOWNLOAD);
|
||||
break;
|
||||
case "maxTaskNum": //最大任务书
|
||||
int maxTaskNum = checkInt(value) ? Integer.parseInt(value) : 2;
|
||||
|
||||
@@ -37,7 +37,7 @@ import java.util.concurrent.TimeUnit;
|
||||
* Created by AriaL on 2017/6/30.
|
||||
* 任务组核心逻辑
|
||||
*/
|
||||
public abstract class AbsGroupUtil implements IUtil, Runnable {
|
||||
public abstract class AbsGroupLoaderUtil implements IUtil, Runnable {
|
||||
protected final String TAG = CommonUtil.getClassName(getClass());
|
||||
|
||||
private long mCurrentLocation = 0;
|
||||
@@ -52,7 +52,7 @@ public abstract class AbsGroupUtil implements IUtil, Runnable {
|
||||
private DGTaskWrapper mGTWrapper;
|
||||
private GroupRunState mState;
|
||||
|
||||
protected AbsGroupUtil(AbsTaskWrapper groupWrapper, IEventListener listener) {
|
||||
protected AbsGroupLoaderUtil(AbsTaskWrapper groupWrapper, IEventListener listener) {
|
||||
mListener = (IDGroupListener) listener;
|
||||
mGTWrapper = (DGTaskWrapper) groupWrapper;
|
||||
mUpdateInterval = Configuration.getInstance().downloadCfg.getUpdateInterval();
|
||||
@@ -30,7 +30,7 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 组合任务子任务调度器,用于调度任务的开始、停止、失败、完成等情况
|
||||
* 该调度器生命周期和{@link AbsGroupUtil}生命周期一致
|
||||
* 该调度器生命周期和{@link AbsGroupLoaderUtil}生命周期一致
|
||||
*/
|
||||
class SimpleSchedulers implements ISchedulers {
|
||||
private static final String TAG = "SimpleSchedulers";
|
||||
|
||||
@@ -26,7 +26,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 组合任务队列,该队列生命周期和{@link AbsGroupUtil}生命周期一致
|
||||
* 组合任务队列,该队列生命周期和{@link AbsGroupLoaderUtil}生命周期一致
|
||||
*/
|
||||
class SimpleSubQueue implements ISubQueue<AbsSubDLoadUtil> {
|
||||
private static final String TAG = "SimpleSubQueue";
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
package com.arialyy.aria.core.inf;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.loader.ILoaderComponent;
|
||||
|
||||
/**
|
||||
* 线程任务状态
|
||||
*/
|
||||
public interface IThreadState extends Handler.Callback {
|
||||
public interface IThreadState extends ILoaderComponent {
|
||||
int STATE_STOP = 0x01;
|
||||
int STATE_FAIL = 0x02;
|
||||
int STATE_CANCEL = 0x03;
|
||||
@@ -50,4 +53,14 @@ public interface IThreadState extends Handler.Callback {
|
||||
* @return 任务当前进度
|
||||
*/
|
||||
long getCurrentProgress();
|
||||
|
||||
/**
|
||||
* 设置消息循环体
|
||||
*/
|
||||
void setLooper(TaskRecord taskRecord, Looper looper);
|
||||
|
||||
/**
|
||||
* 创建handler 回调
|
||||
*/
|
||||
Handler.Callback getHandlerCallback();
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import android.os.Handler;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.inf.TaskSchedulerType;
|
||||
import com.arialyy.aria.core.task.AbsTask;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
|
||||
@@ -17,7 +17,7 @@ package com.arialyy.aria.core.listener;
|
||||
|
||||
import android.os.Handler;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.inf.TaskSchedulerType;
|
||||
import com.arialyy.aria.core.task.AbsTask;
|
||||
import com.arialyy.aria.core.upload.UTaskWrapper;
|
||||
|
||||
@@ -21,7 +21,7 @@ import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.group.GroupSendParams;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.inf.TaskSchedulerType;
|
||||
import com.arialyy.aria.core.task.AbsTask;
|
||||
import com.arialyy.aria.core.task.DownloadGroupTask;
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
package com.arialyy.aria.core.loader;
|
||||
|
||||
import android.os.Looper;
|
||||
import android.util.SparseArray;
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.inf.IThreadState;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.core.manager.ThreadTaskManager;
|
||||
@@ -27,20 +25,27 @@ 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;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/7/1.
|
||||
* 控制线程任务状态,如:开始,停止,取消,重试
|
||||
* 任务执行器,用于处理任务的开始,停止
|
||||
* 流程:
|
||||
* 1、获取任务记录
|
||||
* 2、创建任务状态管理器,用于管理任务的状态
|
||||
* 3、创建文件信息获取器,获取文件信息,根据文件信息执行任务
|
||||
* 4、创建线程任务执行下载、上传操作
|
||||
*/
|
||||
public abstract class AbsLoader implements Runnable {
|
||||
public abstract class AbsLoader implements ILoaderVisitor, ILoader {
|
||||
protected final String TAG;
|
||||
protected IEventListener mListener;
|
||||
protected AbsTaskWrapper mTaskWrapper;
|
||||
protected File mTempFile;
|
||||
|
||||
private SparseArray<IThreadTask> mTask = new SparseArray<>();
|
||||
private List<IThreadTask> mTask = new ArrayList<>();
|
||||
private ScheduledThreadPoolExecutor mTimer;
|
||||
|
||||
/**
|
||||
@@ -48,20 +53,23 @@ public abstract class AbsLoader implements Runnable {
|
||||
*/
|
||||
private long mUpdateInterval = 1000;
|
||||
protected TaskRecord mRecord;
|
||||
private IThreadState mStateManager;
|
||||
private boolean isCancel = false, isStop = false;
|
||||
private boolean isRuning = false;
|
||||
private Looper mLooper;
|
||||
|
||||
protected AbsLoader(IEventListener listener, AbsTaskWrapper wrapper) {
|
||||
protected IRecordHandler mRecordHandler;
|
||||
protected IThreadState mStateManager;
|
||||
protected IInfoTask mInfoTask;
|
||||
protected IThreadTaskBuilder mTTBuilder;
|
||||
|
||||
protected AbsLoader(AbsTaskWrapper wrapper, IEventListener listener) {
|
||||
mListener = listener;
|
||||
mTaskWrapper = wrapper;
|
||||
TAG = CommonUtil.getClassName(getClass());
|
||||
}
|
||||
|
||||
protected abstract IThreadState createStateManager(Looper looper);
|
||||
|
||||
/**
|
||||
* 处理任务
|
||||
* 启动线程任务
|
||||
*/
|
||||
protected abstract void handleTask();
|
||||
|
||||
@@ -70,11 +78,6 @@ public abstract class AbsLoader implements Runnable {
|
||||
*/
|
||||
public abstract long getFileSize();
|
||||
|
||||
/**
|
||||
* 获取当前任务位置
|
||||
*/
|
||||
public abstract long getCurrentLocation();
|
||||
|
||||
public IThreadState getStateManager() {
|
||||
return mStateManager;
|
||||
}
|
||||
@@ -83,7 +86,7 @@ public abstract class AbsLoader implements Runnable {
|
||||
return mTaskWrapper.getKey();
|
||||
}
|
||||
|
||||
public SparseArray<IThreadTask> getTaskList() {
|
||||
public List<IThreadTask> getTaskList() {
|
||||
return mTask;
|
||||
}
|
||||
|
||||
@@ -94,16 +97,20 @@ public abstract class AbsLoader implements Runnable {
|
||||
closeTimer();
|
||||
if (mTask != null && mTask.size() != 0) {
|
||||
for (int i = 0; i < mTask.size(); i++) {
|
||||
mTask.valueAt(i).breakTask();
|
||||
mTask.get(i).breakTask();
|
||||
}
|
||||
mTask.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务记录工具
|
||||
*/
|
||||
protected abstract IRecordHandler getRecordHandler(AbsTaskWrapper wrapper);
|
||||
@Override public void run() {
|
||||
checkComponent();
|
||||
if (isRunning()) {
|
||||
ALog.d(TAG, String.format("任务【%s】正在执行,启动任务失败", mTaskWrapper.getKey()));
|
||||
return;
|
||||
}
|
||||
startFlow();
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始流程
|
||||
@@ -114,21 +121,18 @@ public abstract class AbsLoader implements Runnable {
|
||||
}
|
||||
isRuning = true;
|
||||
resetState();
|
||||
mRecord = getRecordHandler(mTaskWrapper).getRecord();
|
||||
Looper.prepare();
|
||||
Looper looper = Looper.myLooper();
|
||||
mStateManager = createStateManager(looper);
|
||||
onPostPre();
|
||||
handleTask();
|
||||
startTimer();
|
||||
Looper.loop();
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
if (isRunning()) {
|
||||
return;
|
||||
@Override public Looper getLooper() {
|
||||
if (mLooper == null) {
|
||||
Looper.prepare();
|
||||
mLooper = Looper.myLooper();
|
||||
}
|
||||
startFlow();
|
||||
return mLooper;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,7 +216,7 @@ public abstract class AbsLoader implements Runnable {
|
||||
isCancel = true;
|
||||
onCancel();
|
||||
for (int i = 0; i < mTask.size(); i++) {
|
||||
IThreadTask task = mTask.valueAt(i);
|
||||
IThreadTask task = mTask.get(i);
|
||||
if (task != null && !task.isThreadComplete()) {
|
||||
task.cancel();
|
||||
}
|
||||
@@ -245,7 +249,7 @@ public abstract class AbsLoader implements Runnable {
|
||||
isStop = true;
|
||||
onStop();
|
||||
for (int i = 0; i < mTask.size(); i++) {
|
||||
IThreadTask task = mTask.valueAt(i);
|
||||
IThreadTask task = mTask.get(i);
|
||||
if (task != null && !task.isThreadComplete()) {
|
||||
task.stop();
|
||||
}
|
||||
@@ -253,7 +257,7 @@ public abstract class AbsLoader implements Runnable {
|
||||
ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey());
|
||||
onPostStop();
|
||||
onDestroy();
|
||||
mListener.onStop(getCurrentLocation());
|
||||
mListener.onStop(getCurrentProgress());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,17 +274,6 @@ public abstract class AbsLoader implements Runnable {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接调用的时候会自动启动线程执行
|
||||
*/
|
||||
public synchronized void start() {
|
||||
if (isRunning()) {
|
||||
ALog.d(TAG, String.format("任务【%s】正在执行,启动任务失败", mTaskWrapper.getKey()));
|
||||
return;
|
||||
}
|
||||
new Thread(this).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重试任务
|
||||
*/
|
||||
@@ -303,4 +296,22 @@ public abstract class AbsLoader implements Runnable {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查组件: {@link #mRecordHandler}、{@link #mInfoTask}、{@link #mStateManager}、{@link #mTTBuilder}
|
||||
*/
|
||||
private void checkComponent() {
|
||||
if (mRecordHandler == null) {
|
||||
throw new NullPointerException("任务记录组件为空");
|
||||
}
|
||||
if (mInfoTask == null) {
|
||||
throw new NullPointerException(("文件信息组件为空"));
|
||||
}
|
||||
if (mStateManager == null) {
|
||||
throw new NullPointerException("任务状态管理组件为空");
|
||||
}
|
||||
if (mTTBuilder == null) {
|
||||
throw new NullPointerException("线程任务组件为空");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,19 +29,25 @@ import com.arialyy.aria.util.CommonUtil;
|
||||
public abstract class AbsNormalLoaderUtil implements IUtil {
|
||||
protected String TAG = CommonUtil.getClassName(getClass());
|
||||
private IEventListener mListener;
|
||||
private AbsLoader mLoader;
|
||||
protected AbsLoader mLoader;
|
||||
private AbsTaskWrapper mTaskWrapper;
|
||||
private boolean isStop = false, isCancel = false;
|
||||
|
||||
protected AbsNormalLoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) {
|
||||
mTaskWrapper = wrapper;
|
||||
mListener = listener;
|
||||
mLoader = createLoader();
|
||||
mLoader = getLoader();
|
||||
}
|
||||
|
||||
public AbsLoader getLoader() {
|
||||
return mLoader;
|
||||
}
|
||||
/**
|
||||
* 获取加载器
|
||||
*/
|
||||
public abstract AbsLoader getLoader();
|
||||
|
||||
/**
|
||||
* 获取构造器
|
||||
*/
|
||||
public abstract LoaderStructure getLoaderStructure();
|
||||
|
||||
@Override public String getKey() {
|
||||
return mTaskWrapper.getKey();
|
||||
@@ -55,7 +61,7 @@ public abstract class AbsNormalLoaderUtil implements IUtil {
|
||||
* 获取当前下载位置
|
||||
*/
|
||||
@Override public long getCurrentLocation() {
|
||||
return mLoader.getCurrentLocation();
|
||||
return mLoader.getCurrentProgress();
|
||||
}
|
||||
|
||||
@Override public boolean isRunning() {
|
||||
@@ -105,10 +111,10 @@ public abstract class AbsNormalLoaderUtil implements IUtil {
|
||||
//} else {
|
||||
// mDownloader.create();
|
||||
//}
|
||||
Runnable runnable = createInfoThread();
|
||||
if (runnable != null) {
|
||||
new Thread(runnable).start();
|
||||
}
|
||||
|
||||
getLoaderStructure();
|
||||
new Thread(mLoader).start();
|
||||
|
||||
onStart();
|
||||
}
|
||||
|
||||
@@ -139,14 +145,4 @@ public abstract class AbsNormalLoaderUtil implements IUtil {
|
||||
public AbsTaskWrapper getTaskWrapper() {
|
||||
return mTaskWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建加载器的适配器
|
||||
*/
|
||||
protected abstract AbsLoader createLoader();
|
||||
|
||||
/**
|
||||
* 通过链接类型创建不同的获取文件信息的线程
|
||||
*/
|
||||
protected abstract Runnable createInfoThread();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -13,24 +13,40 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.inf;
|
||||
package com.arialyy.aria.core.loader;
|
||||
|
||||
import com.arialyy.aria.core.common.CompleteInfo;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.common.CompleteInfo;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
|
||||
public interface OnFileInfoCallback {
|
||||
/**
|
||||
* 处理完成
|
||||
*
|
||||
* @param info 一些回调的信息
|
||||
*/
|
||||
void onComplete(String key, CompleteInfo info);
|
||||
/**
|
||||
* 任务信息采集
|
||||
*/
|
||||
public interface IInfoTask extends ILoaderComponent {
|
||||
|
||||
/**
|
||||
* 请求失败
|
||||
*
|
||||
* @param e 错误信息
|
||||
* 执行任务
|
||||
*/
|
||||
void onFail(AbsEntity entity, BaseException e, boolean needRetry);
|
||||
}
|
||||
void run();
|
||||
|
||||
/**
|
||||
* 设置回调
|
||||
*/
|
||||
void setCallback(Callback callback);
|
||||
|
||||
interface Callback {
|
||||
/**
|
||||
* 处理完成
|
||||
*
|
||||
* @param info 一些回调的信息
|
||||
*/
|
||||
void onSucceed(String key, CompleteInfo info);
|
||||
|
||||
/**
|
||||
* 请求失败
|
||||
*
|
||||
* @param e 错误信息
|
||||
*/
|
||||
void onFail(AbsEntity entity, BaseException e, boolean needRetry);
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,24 @@
|
||||
*/
|
||||
package com.arialyy.aria.core.loader;
|
||||
|
||||
public interface ILoader {
|
||||
import android.os.Looper;
|
||||
|
||||
void start();
|
||||
public interface ILoader extends Runnable{
|
||||
|
||||
//void start();
|
||||
|
||||
void stop();
|
||||
|
||||
void isBreak();
|
||||
/**
|
||||
* 任务是否被中断(停止,取消)
|
||||
*
|
||||
* @return true 任务中断,false 任务没有中断
|
||||
*/
|
||||
boolean isBreak();
|
||||
|
||||
String getKey();
|
||||
|
||||
long getCurrentProgress();
|
||||
|
||||
Looper getLooper();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.arialyy.aria.core.loader;
|
||||
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.task.IThreadTask;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
|
||||
@@ -15,33 +15,11 @@
|
||||
*/
|
||||
package com.arialyy.aria.core.loader;
|
||||
|
||||
public class LoaderIntercept implements ILoaderInterceptor, ILoader {
|
||||
/**
|
||||
* 加载器部件
|
||||
*/
|
||||
public interface ILoaderComponent {
|
||||
|
||||
void accept(ILoaderVisitor visitor);
|
||||
|
||||
|
||||
@Override public ILoader intercept(Chain chain) {
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public void start() {
|
||||
|
||||
}
|
||||
|
||||
@Override public void stop() {
|
||||
|
||||
}
|
||||
|
||||
@Override public void isBreak() {
|
||||
|
||||
}
|
||||
|
||||
@Override public String getKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public long getCurrentProgress() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -15,27 +15,30 @@
|
||||
*/
|
||||
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 com.arialyy.aria.core.inf.IThreadState;
|
||||
|
||||
/**
|
||||
* 拦截器
|
||||
* 加载器访问者
|
||||
*/
|
||||
public interface ILoaderInterceptor {
|
||||
public interface ILoaderVisitor {
|
||||
|
||||
ILoader intercept(Chain chain);
|
||||
/**
|
||||
* 处理任务记录
|
||||
*/
|
||||
void addComponent(IRecordHandler recordHandler);
|
||||
|
||||
interface Chain {
|
||||
/**
|
||||
* 处理任务的文件信息
|
||||
*/
|
||||
void addComponent(IInfoTask infoTask);
|
||||
|
||||
void updateRecord(TaskRecord record);
|
||||
/**
|
||||
* 线程状态
|
||||
*/
|
||||
void addComponent(IThreadState threadState);
|
||||
|
||||
TaskRecord getRecord();
|
||||
|
||||
IEventListener getListener();
|
||||
|
||||
ITaskWrapper getWrapper();
|
||||
|
||||
ILoader proceed();
|
||||
}
|
||||
/**
|
||||
* 构造线程任务
|
||||
*/
|
||||
void addComponent(IThreadTaskBuilder builder);
|
||||
}
|
||||
@@ -13,18 +13,38 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.inf;
|
||||
package com.arialyy.aria.core.loader;
|
||||
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
|
||||
/**
|
||||
* 任务记录处理适配器
|
||||
*
|
||||
* @Author lyy
|
||||
* @Date 2019-09-19
|
||||
* @Date 2019-09-18
|
||||
*/
|
||||
public interface IRecordHandlerAdapter {
|
||||
public interface IRecordHandler extends ILoaderComponent {
|
||||
|
||||
int TYPE_DOWNLOAD = 1;
|
||||
int TYPE_UPLOAD = 2;
|
||||
int TYPE_M3U8_VOD = 3;
|
||||
int TYPE_M3U8_LIVE = 4;
|
||||
|
||||
String STATE = "_state_";
|
||||
String RECORD = "_record_";
|
||||
/**
|
||||
* 小于1m的文件不启用多线程
|
||||
*/
|
||||
long SUB_LEN = 1024 * 1024;
|
||||
|
||||
/**
|
||||
* 分块文件路径
|
||||
*/
|
||||
String SUB_PATH = "%s.%s.part";
|
||||
|
||||
/**
|
||||
* 获取任务记录
|
||||
*/
|
||||
TaskRecord getRecord();
|
||||
|
||||
/**
|
||||
* 记录处理前的操作,可用来删除任务记录
|
||||
@@ -57,4 +77,11 @@ public interface IRecordHandlerAdapter {
|
||||
* @return 新任务的线程数
|
||||
*/
|
||||
int initTaskThreadNum();
|
||||
|
||||
/**
|
||||
* 检查任务是否已完成
|
||||
*
|
||||
* @return true 任务已完成
|
||||
*/
|
||||
boolean checkTaskCompleted();
|
||||
}
|
||||
@@ -13,35 +13,26 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.inf;
|
||||
package com.arialyy.aria.core.loader;
|
||||
|
||||
import android.os.Looper;
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.inf.IThreadState;
|
||||
import com.arialyy.aria.core.task.IThreadTask;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author lyy
|
||||
* @Date 2019-09-18
|
||||
* 线程任务构造器
|
||||
*/
|
||||
public interface IRecordHandler {
|
||||
|
||||
int TYPE_DOWNLOAD = 1;
|
||||
int TYPE_UPLOAD = 2;
|
||||
int TYPE_M3U8_VOD = 3;
|
||||
int TYPE_M3U8_LIVE = 4;
|
||||
|
||||
String STATE = "_state_";
|
||||
String RECORD = "_record_";
|
||||
/**
|
||||
* 小于1m的文件不启用多线程
|
||||
*/
|
||||
long SUB_LEN = 1024 * 1024;
|
||||
public interface IThreadTaskBuilder extends ILoaderComponent {
|
||||
|
||||
/**
|
||||
* 分块文件路径
|
||||
* 构造线程任务
|
||||
*/
|
||||
String SUB_PATH = "%s.%s.part";
|
||||
List<IThreadTask> buildThreadTask(TaskRecord record, Looper looper, IThreadState stateManager);
|
||||
|
||||
/**
|
||||
* 获取任务记录
|
||||
* 获取创建的线程任务数,需要先调用{@link #buildThreadTask(TaskRecord, Looper, IThreadState)}方法才能获取创建的线程任务数
|
||||
*/
|
||||
TaskRecord getRecord();
|
||||
int getCreatedThreadNum();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -15,25 +15,31 @@
|
||||
*/
|
||||
package com.arialyy.aria.core.loader;
|
||||
|
||||
import com.arialyy.aria.core.common.RecordHandler;
|
||||
import com.arialyy.aria.core.inf.IRecordHandlerAdapter;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.inf.IThreadState;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务记录拦截器,用于处理任务记录
|
||||
*/
|
||||
public final class RecordInterceptor implements ILoaderInterceptor {
|
||||
private IRecordHandlerAdapter adapter;
|
||||
public class LoaderStructure {
|
||||
private List<ILoaderComponent> parts = new ArrayList<>();
|
||||
|
||||
public RecordInterceptor(IRecordHandlerAdapter adapter) {
|
||||
this.adapter = adapter;
|
||||
public void accept(ILoaderVisitor visitor) {
|
||||
|
||||
for (ILoaderComponent part : parts) {
|
||||
part.accept(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public ILoader intercept(Chain chain) {
|
||||
RecordHandler recordHandler = new RecordHandler((AbsTaskWrapper) chain.getWrapper());
|
||||
recordHandler.setAdapter(adapter);
|
||||
chain.updateRecord(recordHandler.getRecord());
|
||||
|
||||
return chain.proceed();
|
||||
/**
|
||||
* 将组件加入到集合,必须添加以下集合:
|
||||
* 1 {@link IRecordHandler}
|
||||
* 2 {@link IInfoTask}
|
||||
* 3 {@link IThreadState}
|
||||
* 4 {@link IThreadTaskBuilder}
|
||||
*
|
||||
* @param component 待添加的组件
|
||||
*/
|
||||
public LoaderStructure addComponent(ILoaderComponent component) {
|
||||
parts.add(component);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -15,20 +15,17 @@
|
||||
*/
|
||||
package com.arialyy.aria.core.loader;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.common.AbsNormalEntity;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.common.CompleteInfo;
|
||||
import com.arialyy.aria.core.event.EventMsgUtil;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.inf.IThreadState;
|
||||
import com.arialyy.aria.core.listener.BaseDListener;
|
||||
import com.arialyy.aria.core.listener.IDLoadListener;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.core.manager.ThreadTaskManager;
|
||||
import com.arialyy.aria.core.task.IThreadTask;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import java.io.File;
|
||||
|
||||
@@ -36,23 +33,15 @@ import java.io.File;
|
||||
* 单文件
|
||||
*/
|
||||
public class NormalLoader extends AbsLoader {
|
||||
private ThreadStateManager mStateManager;
|
||||
private Handler mStateHandler;
|
||||
protected int mTotalThreadNum; //总线程数
|
||||
private int mStartThreadNum; //启动的线程数
|
||||
private ILoaderAdapter mAdapter;
|
||||
|
||||
public NormalLoader(IEventListener listener, AbsTaskWrapper wrapper) {
|
||||
super(listener, wrapper);
|
||||
public NormalLoader(AbsTaskWrapper wrapper, IEventListener listener) {
|
||||
super(wrapper, listener);
|
||||
mTempFile = new File(getEntity().getFilePath());
|
||||
EventMsgUtil.getDefault().register(this);
|
||||
setUpdateInterval(wrapper.getConfig().getUpdateInterval());
|
||||
}
|
||||
|
||||
public void setAdapter(ILoaderAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
}
|
||||
|
||||
public AbsNormalEntity getEntity() {
|
||||
return (AbsNormalEntity) mTaskWrapper.getEntity();
|
||||
}
|
||||
@@ -61,24 +50,15 @@ public class NormalLoader extends AbsLoader {
|
||||
return getEntity().getFileSize();
|
||||
}
|
||||
|
||||
@Override public long getCurrentLocation() {
|
||||
return isRunning() ? mStateManager.getCurrentProgress() : getEntity().getCurrentProgress();
|
||||
}
|
||||
|
||||
@Override protected IRecordHandler getRecordHandler(AbsTaskWrapper wrapper) {
|
||||
return mAdapter.recordHandler(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置最大下载/上传速度
|
||||
* 设置最大下载/上传速度AbsFtpInfoThread
|
||||
*
|
||||
* @param maxSpeed 单位为:kb
|
||||
*/
|
||||
protected void setMaxSpeed(int maxSpeed) {
|
||||
for (int i = 0; i < getTaskList().size(); i++) {
|
||||
IThreadTask task = getTaskList().valueAt(i);
|
||||
if (task != null && mStartThreadNum > 0) {
|
||||
task.setMaxSpeed(maxSpeed / mStartThreadNum);
|
||||
for (IThreadTask threadTask : getTaskList()) {
|
||||
if (threadTask != null && mStartThreadNum > 0) {
|
||||
threadTask.setMaxSpeed(maxSpeed / mStartThreadNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,11 +70,6 @@ public class NormalLoader extends AbsLoader {
|
||||
|
||||
@Override protected void onPostPre() {
|
||||
super.onPostPre();
|
||||
if (mAdapter == null) {
|
||||
throw new NullPointerException("请使用adapter设置适配器");
|
||||
}
|
||||
mTotalThreadNum = mRecord.threadNum;
|
||||
|
||||
if (mListener instanceof IDLoadListener) {
|
||||
((IDLoadListener) mListener).onPostPre(getEntity().getFileSize());
|
||||
}
|
||||
@@ -114,126 +89,63 @@ public class NormalLoader extends AbsLoader {
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected IThreadState createStateManager(Looper looper) {
|
||||
mStateManager = new ThreadStateManager(looper, mRecord, mListener);
|
||||
mStateHandler = new Handler(looper, mStateManager);
|
||||
return mStateManager;
|
||||
}
|
||||
|
||||
@Override protected void handleTask() {
|
||||
if (mTaskWrapper.isSupportBP()) {
|
||||
handleBreakpoint();
|
||||
} else {
|
||||
handleNoSupportBP();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动断点任务时,创建单线程任务
|
||||
*
|
||||
* @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 = mTaskWrapper;
|
||||
config.record = record;
|
||||
config.stateHandler = mStateHandler;
|
||||
return mAdapter.createThreadTask(config);
|
||||
}
|
||||
|
||||
private void handleBreakpoint() {
|
||||
long fileLength = getEntity().getFileSize();
|
||||
long blockSize = fileLength / mTotalThreadNum;
|
||||
long currentProgress = 0;
|
||||
|
||||
mRecord.fileLength = fileLength;
|
||||
if (mTaskWrapper.isNewTask() && !mAdapter.handleNewTask(mRecord, mTotalThreadNum)) {
|
||||
closeTimer();
|
||||
mListener.onFail(false, null);
|
||||
return;
|
||||
}
|
||||
|
||||
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__已完成", mTaskWrapper.getKey(), i));
|
||||
mStateHandler.obtainMessage(IThreadState.STATE_COMPLETE).sendToTarget();
|
||||
if (mStateManager.isComplete()) {
|
||||
mRecord.deleteData();
|
||||
mListener.onComplete();
|
||||
return;
|
||||
}
|
||||
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) return;
|
||||
getTaskList().put(tr.threadId, task);
|
||||
}
|
||||
if (currentProgress != 0 && currentProgress != getEntity().getCurrentProgress()) {
|
||||
ALog.d(TAG, String.format("进度修正,当前进度:%s", currentProgress));
|
||||
getEntity().setCurrentProgress(currentProgress);
|
||||
}
|
||||
mStateManager.updateProgress(currentProgress);
|
||||
startThreadTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动单线程任务
|
||||
*/
|
||||
private void startThreadTask() {
|
||||
@Override
|
||||
public void handleTask() {
|
||||
if (isBreak()) {
|
||||
return;
|
||||
}
|
||||
mStateManager.setLooper(mRecord, getLooper());
|
||||
mInfoTask.run();
|
||||
}
|
||||
|
||||
private void startThreadTask() {
|
||||
getTaskList().addAll(mTTBuilder.buildThreadTask(mRecord, getLooper(), mStateManager));
|
||||
mStartThreadNum = mTTBuilder.getCreatedThreadNum();
|
||||
if (mStateManager.getCurrentProgress() > 0) {
|
||||
mListener.onResume(mStateManager.getCurrentProgress());
|
||||
} else {
|
||||
mListener.onStart(mStateManager.getCurrentProgress());
|
||||
}
|
||||
|
||||
for (int i = 0; i < getTaskList().size(); i++) {
|
||||
ThreadTaskManager.getInstance().startThread(mTaskWrapper.getKey(), getTaskList().valueAt(i));
|
||||
for (IThreadTask threadTask : getTaskList()) {
|
||||
ThreadTaskManager.getInstance().startThread(mTaskWrapper.getKey(), threadTask);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理不支持断点的任务
|
||||
*/
|
||||
private void handleNoSupportBP() {
|
||||
if (mListener instanceof BaseDListener) {
|
||||
((BaseDListener) mListener).supportBreakpoint(false);
|
||||
}
|
||||
mStartThreadNum = 1;
|
||||
@Override public long getCurrentProgress() {
|
||||
return isRunning() ? mStateManager.getCurrentProgress() : getEntity().getCurrentProgress();
|
||||
}
|
||||
|
||||
IThreadTask task = createSingThreadTask(mRecord.threadRecords.get(0), 1);
|
||||
if (task == null) return;
|
||||
getTaskList().put(0, task);
|
||||
ThreadTaskManager.getInstance().startThread(mTaskWrapper.getKey(), task);
|
||||
mListener.onStart(0);
|
||||
@Override public void addComponent(IRecordHandler recordHandler) {
|
||||
mRecordHandler = recordHandler;
|
||||
mRecord = mRecordHandler.getRecord();
|
||||
if (recordHandler.checkTaskCompleted()) {
|
||||
mRecord.deleteData();
|
||||
mListener.onComplete();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void addComponent(IInfoTask infoTask) {
|
||||
mInfoTask = infoTask;
|
||||
infoTask.setCallback(new IInfoTask.Callback() {
|
||||
@Override public void onSucceed(String key, CompleteInfo info) {
|
||||
startThreadTask();
|
||||
}
|
||||
|
||||
@Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) {
|
||||
mListener.onFail(needRetry, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override public void addComponent(IThreadState threadState) {
|
||||
mStateManager = threadState;
|
||||
}
|
||||
|
||||
@Override public void addComponent(IThreadTaskBuilder builder) {
|
||||
mTTBuilder = builder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
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.IRecordHandler;
|
||||
import com.arialyy.aria.core.inf.IThreadState;
|
||||
import com.arialyy.aria.core.listener.IEventListener;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
@@ -49,16 +49,85 @@ public class ThreadStateManager implements IThreadState {
|
||||
private Looper mLooper;
|
||||
|
||||
/**
|
||||
* @param taskRecord 任务记录
|
||||
* @param listener 任务事件
|
||||
*/
|
||||
ThreadStateManager(Looper looper, TaskRecord taskRecord, IEventListener listener) {
|
||||
mLooper = looper;
|
||||
mTaskRecord = taskRecord;
|
||||
mThreadNum = mTaskRecord.threadNum;
|
||||
public ThreadStateManager(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++;
|
||||
if (isStop()) {
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_CANCEL:
|
||||
mCancelNum++;
|
||||
if (isCancel()) {
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_FAIL:
|
||||
mFailNum++;
|
||||
if (isFail()) {
|
||||
Bundle b = msg.getData();
|
||||
mListener.onFail(b.getBoolean(KEY_RETRY, false),
|
||||
(BaseException) b.getSerializable(KEY_ERROR_INFO));
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_COMPLETE:
|
||||
mCompleteNum++;
|
||||
if (isComplete()) {
|
||||
ALog.d(TAG, "isComplete, completeNum = " + mCompleteNum);
|
||||
if (mTaskRecord.isBlock) {
|
||||
if (mergeFile()) {
|
||||
mListener.onComplete();
|
||||
} else {
|
||||
mListener.onFail(false, null);
|
||||
}
|
||||
} else {
|
||||
mListener.onComplete();
|
||||
}
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_RUNNING:
|
||||
if (msg.obj instanceof Long) {
|
||||
mProgress += (long) msg.obj;
|
||||
}
|
||||
break;
|
||||
case STATE_UPDATE_PROGRESS:
|
||||
if (msg.obj == null) {
|
||||
mProgress = updateBlockProgress();
|
||||
} else if (msg.obj instanceof Long) {
|
||||
mProgress = (long) msg.obj;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 不要使用handle更新启动线程的进度,因为有延迟
|
||||
*/
|
||||
@@ -66,61 +135,6 @@ public class ThreadStateManager implements IThreadState {
|
||||
mProgress = curProgress;
|
||||
}
|
||||
|
||||
@Override public boolean handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case STATE_STOP:
|
||||
mStopNum++;
|
||||
if (isStop()) {
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_CANCEL:
|
||||
mCancelNum++;
|
||||
if (isCancel()) {
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_FAIL:
|
||||
mFailNum++;
|
||||
if (isFail()) {
|
||||
Bundle b = msg.getData();
|
||||
mListener.onFail(b.getBoolean(KEY_RETRY, false),
|
||||
(BaseException) b.getSerializable(KEY_ERROR_INFO));
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_COMPLETE:
|
||||
mCompleteNum++;
|
||||
if (isComplete()) {
|
||||
ALog.d(TAG, "isComplete, completeNum = " + mCompleteNum);
|
||||
if (mTaskRecord.isBlock) {
|
||||
if (mergeFile()) {
|
||||
mListener.onComplete();
|
||||
} else {
|
||||
mListener.onFail(false, null);
|
||||
}
|
||||
} else {
|
||||
mListener.onComplete();
|
||||
}
|
||||
quitLooper();
|
||||
}
|
||||
break;
|
||||
case STATE_RUNNING:
|
||||
if (msg.obj instanceof Long) {
|
||||
mProgress += (long) msg.obj;
|
||||
}
|
||||
break;
|
||||
case STATE_UPDATE_PROGRESS:
|
||||
if (msg.obj == null) {
|
||||
mProgress = updateBlockProgress();
|
||||
} else if (msg.obj instanceof Long) {
|
||||
mProgress = (long) msg.obj;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出looper循环
|
||||
*/
|
||||
@@ -138,6 +152,10 @@ public class ThreadStateManager implements IThreadState {
|
||||
return mProgress;
|
||||
}
|
||||
|
||||
@Override public Handler.Callback getHandlerCallback() {
|
||||
return callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有子线程是否都已经停止
|
||||
*/
|
||||
@@ -226,4 +244,8 @@ public class ThreadStateManager implements IThreadState {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void accept(ILoaderVisitor visitor) {
|
||||
visitor.addComponent(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
package com.arialyy.aria.core.task;
|
||||
|
||||
import com.arialyy.aria.core.download.AbsGroupTaskWrapper;
|
||||
import com.arialyy.aria.core.group.AbsGroupUtil;
|
||||
import com.arialyy.aria.core.group.AbsGroupLoaderUtil;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/6/29.
|
||||
@@ -36,7 +36,7 @@ public abstract class AbsGroupTask<TASK_ENTITY extends AbsGroupTaskWrapper>
|
||||
*/
|
||||
public void startSubTask(String url) {
|
||||
if (getUtil() != null) {
|
||||
((AbsGroupUtil) getUtil()).startSubTask(url);
|
||||
((AbsGroupLoaderUtil) getUtil()).startSubTask(url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public abstract class AbsGroupTask<TASK_ENTITY extends AbsGroupTaskWrapper>
|
||||
*/
|
||||
public void stopSubTask(String url) {
|
||||
if (getUtil() != null) {
|
||||
((AbsGroupUtil) getUtil()).stopSubTask(url);
|
||||
((AbsGroupLoaderUtil) getUtil()).stopSubTask(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,4 +87,10 @@ public interface IThreadTask extends Callable<IThreadTask> {
|
||||
* @return {@code true} 分块分大小正常,{@code false} 分块大小错误
|
||||
*/
|
||||
boolean checkBlock();
|
||||
|
||||
/**
|
||||
* 获取线程id
|
||||
* @return
|
||||
*/
|
||||
int getThreadId();
|
||||
}
|
||||
|
||||
@@ -228,6 +228,10 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public int getThreadId() {
|
||||
return mRecord.threadId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止任务
|
||||
*/
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.arialyy.aria.util;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
@@ -23,7 +23,7 @@ import com.arialyy.aria.core.common.AbsNormalEntity;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.download.M3U8Entity;
|
||||
import com.arialyy.aria.core.inf.IRecordHandler;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.core.wrapper.RecordWrapper;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# For more details on how to configure your build environment addComponent
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
@@ -13,6 +13,6 @@
|
||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# This option should only be used with decoupled projects. More details, addComponent
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
@@ -44,8 +44,8 @@ task clean(type: Delete) {
|
||||
}
|
||||
|
||||
ext {
|
||||
versionCode = 381
|
||||
versionName = '3.8.1'
|
||||
versionCode = 382
|
||||
versionName = '3.8.2'
|
||||
userOrg = 'arialyy'
|
||||
groupId = 'com.arialyy.aria'
|
||||
publishVersion = versionName
|
||||
|
||||
Reference in New Issue
Block a user