增加获取执行中的任务api
增加获取剩余时间的api 修复重构loader导致的m3u8问题
This commit is contained in:
@@ -36,6 +36,8 @@ import com.arialyy.aria.core.download.target.HttpNormalTarget;
|
||||
import com.arialyy.aria.core.event.EventMsgUtil;
|
||||
import com.arialyy.aria.core.inf.AbsReceiver;
|
||||
import com.arialyy.aria.core.inf.ReceiverType;
|
||||
import com.arialyy.aria.core.queue.DGroupTaskQueue;
|
||||
import com.arialyy.aria.core.queue.DTaskQueue;
|
||||
import com.arialyy.aria.core.scheduler.TaskSchedulers;
|
||||
import com.arialyy.aria.core.task.ITask;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
@@ -302,6 +304,24 @@ public class DownloadReceiver extends AbsReceiver {
|
||||
return DbDataHelper.getDGEntityByHash(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取执行中的任务
|
||||
*
|
||||
* @return 没有执行中的任务,返回null
|
||||
*/
|
||||
public List<DownloadEntity> getDRunningTask() {
|
||||
return DTaskQueue.getInstance().getRunningTask(DownloadEntity.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取执行中的任务
|
||||
*
|
||||
* @return 没有执行中的任务,返回null
|
||||
*/
|
||||
public List<DownloadGroupEntity> getDGRunningTask() {
|
||||
return DGroupTaskQueue.getInstance().getRunningTask(DownloadGroupEntity.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载任务是否存在
|
||||
*
|
||||
|
||||
@@ -17,8 +17,10 @@ package com.arialyy.aria.core.download.target;
|
||||
|
||||
import com.arialyy.aria.core.common.AbsNormalTarget;
|
||||
import com.arialyy.aria.core.common.HttpOption;
|
||||
import com.arialyy.aria.core.download.DGTaskWrapper;
|
||||
import com.arialyy.aria.core.manager.SubTaskManager;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -101,6 +103,37 @@ public class GroupNormalTarget extends AbsNormalTarget<GroupNormalTarget> {
|
||||
return mConfigHandler.setSubFileName(subTaskFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果无法获取到组合任务到总长度,请调用该方法,
|
||||
* 请注意:
|
||||
* 1、如果组合任务到子任务数过多,请不要使用该标志位,否则Aria将需要消耗大量的时间获取组合任务的总长度,直到获取完成组合任务总长度后才会执行下载。
|
||||
* 2、如果你的知道组合任务的总长度,请使用{@link #setFileSize(long)}设置组合任务的长度。
|
||||
* 3、由于网络或其它原因的存在,这种方式获取的组合任务大小有可能是不准确的。
|
||||
*/
|
||||
public GroupNormalTarget unknownSize() {
|
||||
((DGTaskWrapper) getTaskWrapper()).setUnknownSize(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务组总任务大小,任务组是一个抽象的概念,没有真实的数据实体,任务组的大小是Aria动态获取子任务大小相加而得到的,
|
||||
* 如果你知道当前任务组总大小,你也可以调用该方法给任务组设置大小
|
||||
*
|
||||
* 为了更好的用户体验,组合任务最好设置文件大小,默认需要强制设置文件大小。如果无法获取到总长度,请调用{@link #unknownSize()}
|
||||
*
|
||||
* @param fileSize 任务组总大小
|
||||
*/
|
||||
public GroupNormalTarget setFileSize(long fileSize) {
|
||||
if (fileSize <= 0) {
|
||||
ALog.e(TAG, "文件大小不能小于 0");
|
||||
return this;
|
||||
}
|
||||
if (getEntity().getFileSize() <= 1 || getEntity().getFileSize() != fileSize) {
|
||||
getEntity().setFileSize(fileSize);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public boolean isRunning() {
|
||||
return mConfigHandler.isRunning();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.arialyy.aria.core.queue;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.TaskSchedulerType;
|
||||
import com.arialyy.aria.core.manager.TaskWrapperManager;
|
||||
@@ -31,6 +33,8 @@ import com.arialyy.aria.core.task.DownloadTask;
|
||||
import com.arialyy.aria.core.task.UploadTask;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2017/2/23. 任务队列
|
||||
@@ -64,7 +68,33 @@ public abstract class AbsTaskQueue<TASK extends AbsTask, TASK_WRAPPER extends Ab
|
||||
|
||||
abstract int getQueueType();
|
||||
|
||||
/**
|
||||
* 获取执行中的任务
|
||||
*
|
||||
* @return 没有执行中的任务,返回null
|
||||
*/
|
||||
public <T extends AbsEntity> List<T> getRunningTask(Class<T> type) {
|
||||
List<TASK> exeTask = mExecutePool.getAllTask();
|
||||
List<TASK> cacheTask = mCachePool.getAllTask();
|
||||
List<T> entities = new ArrayList<>();
|
||||
if (exeTask != null && !exeTask.isEmpty()) {
|
||||
for (TASK task : exeTask) {
|
||||
entities.add((T) task.getTaskWrapper().getEntity());
|
||||
}
|
||||
}
|
||||
if (cacheTask != null && !cacheTask.isEmpty()) {
|
||||
for (TASK task : cacheTask) {
|
||||
entities.add((T) task.getTaskWrapper().getEntity());
|
||||
}
|
||||
}
|
||||
return entities.isEmpty() ? null : entities;
|
||||
}
|
||||
|
||||
@Override public boolean taskIsRunning(String key) {
|
||||
if (TextUtils.isEmpty(key)) {
|
||||
ALog.w(TAG, "key为空,无法确认任务是否执行");
|
||||
return false;
|
||||
}
|
||||
TASK task = mExecutePool.getTask(key);
|
||||
if (task == null && ThreadTaskManager.getInstance().taskIsRunning(key)) {
|
||||
ThreadTaskManager.getInstance().removeTaskThread(key);
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.arialyy.aria.core.queue;
|
||||
|
||||
import com.arialyy.aria.core.AriaConfig;
|
||||
import com.arialyy.aria.core.download.DTaskWrapper;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.event.DMaxNumEvent;
|
||||
import com.arialyy.aria.core.event.Event;
|
||||
import com.arialyy.aria.core.event.EventMsgUtil;
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.arialyy.aria.core.common.ProxyHelper;
|
||||
import com.arialyy.aria.core.event.EventMsgUtil;
|
||||
import com.arialyy.aria.core.inf.AbsReceiver;
|
||||
import com.arialyy.aria.core.inf.ReceiverType;
|
||||
import com.arialyy.aria.core.queue.UTaskQueue;
|
||||
import com.arialyy.aria.core.scheduler.TaskSchedulers;
|
||||
import com.arialyy.aria.core.task.ITask;
|
||||
import com.arialyy.aria.core.upload.target.FtpBuilderTarget;
|
||||
@@ -230,6 +231,15 @@ public class UploadReceiver extends AbsReceiver {
|
||||
ITask.UPLOAD));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取执行中的任务
|
||||
*
|
||||
* @return 没有执行中的任务,返回null
|
||||
*/
|
||||
public List<UploadEntity> getURunningTask() {
|
||||
return UTaskQueue.getInstance().getRunningTask(UploadEntity.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除所有任务
|
||||
*
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
- 添加ftp服务器标志 https://github.com/AriaLyy/Aria/issues/580
|
||||
- 重构loader模块,让loader模块的代码更加清晰,去除一些不必要的线程创建
|
||||
- 修复ftp上传完成后,删除服务器端的文件,无法重新下载的问题
|
||||
- 增加获取执行中的任务api,详情见:https://aria.laoyuyu.me/aria_doc/api/task_list.html
|
||||
- 增加获取剩余时间的api,详情见:https://aria.laoyuyu.me/aria_doc/start/task_explain.html
|
||||
+ v_3.8.1 (2019/12/22)
|
||||
- 修复一个表创建失败的问题 https://github.com/AriaLyy/Aria/issues/570
|
||||
- 修复一个非分块模式下导致下载失败的问题 https://github.com/AriaLyy/Aria/issues/571
|
||||
|
||||
@@ -42,7 +42,7 @@ public final class FtpDLoaderUtil extends AbsNormalLoaderUtil {
|
||||
|
||||
public LoaderStructure BuildLoaderStructure() {
|
||||
LoaderStructure structure = new LoaderStructure();
|
||||
structure.addComponent(new FtpDRecordHandler(getTaskWrapper()))
|
||||
structure.addComponent(new FtpDRecordHandler((DTaskWrapper) getTaskWrapper()))
|
||||
.addComponent(new NormalThreadStateManager(getListener()))
|
||||
.addComponent(new FtpDFileInfoTask((DTaskWrapper) getTaskWrapper()))
|
||||
.addComponent(new FtpDTTBuilder(getTaskWrapper()));
|
||||
|
||||
@@ -60,10 +60,7 @@ final class FtpUFileInfoTask extends AbsFtpInfoTask<UploadEntity, UTaskWrapper>
|
||||
return;
|
||||
}
|
||||
|
||||
//为了防止编码错乱,需要使用原始字符串
|
||||
if (files.length == 0) {
|
||||
handleFile(getRemotePath(), null);
|
||||
}
|
||||
handleFile(getRemotePath(), files.length == 0 ? null : files[0]);
|
||||
int reply = client.getReplyCode();
|
||||
if (!FTPReply.isPositiveCompletion(reply)) {
|
||||
//服务器上没有该文件路径,表示该任务为新的上传任务
|
||||
|
||||
@@ -36,7 +36,7 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
final class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
private String dir, remotePath;
|
||||
private boolean storeFail = false;
|
||||
private boolean storeSuccess = false;
|
||||
private ScheduledThreadPoolExecutor timer;
|
||||
private FTPClient client = null;
|
||||
private boolean isTimeOut = true;
|
||||
@@ -77,7 +77,11 @@ final class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
file.seek(getThreadRecord().startLocation);
|
||||
}
|
||||
boolean complete = upload(file);
|
||||
if (!complete || getThreadTask().isBreak()) {
|
||||
if (getThreadTask().isBreak()) {
|
||||
return;
|
||||
}
|
||||
if (!complete){
|
||||
fail(new AriaIOException(TAG, "ftp文件上传失败"), false);
|
||||
return;
|
||||
}
|
||||
ALog.i(TAG,
|
||||
@@ -158,12 +162,11 @@ final class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
private boolean upload(final BufferedRandomAccessFile bis)
|
||||
throws IOException {
|
||||
fa = new FtpFISAdapter(bis);
|
||||
storeFail = false;
|
||||
storeSuccess = false;
|
||||
startTimer();
|
||||
final long fileSize = getThreadConfig().tempFile.length();
|
||||
try {
|
||||
ALog.d(TAG, String.format("remotePath: %s", remotePath));
|
||||
client.storeFile(remotePath, fa, new OnFtpInputStreamListener() {
|
||||
storeSuccess = client.storeFile(remotePath, fa, new OnFtpInputStreamListener() {
|
||||
boolean isStoped = false;
|
||||
|
||||
@Override public void onFtpInputStream(FTPClient client, long totalBytesTransferred,
|
||||
@@ -181,7 +184,7 @@ final class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
progress(bytesTransferred);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
storeFail = true;
|
||||
storeSuccess = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -192,15 +195,11 @@ final class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
if (e.getMessage().contains("AriaIOException caught while copying")) {
|
||||
e.printStackTrace();
|
||||
} else {
|
||||
fail(new AriaIOException(TAG, msg, e), !storeFail);
|
||||
fail(new AriaIOException(TAG, msg, e), !storeSuccess);
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
fa.close();
|
||||
closeClient(client);
|
||||
}
|
||||
if (storeFail) {
|
||||
return false;
|
||||
}
|
||||
int reply = client.getReplyCode();
|
||||
if (!FTPReply.isPositiveCompletion(reply)) {
|
||||
@@ -212,6 +211,6 @@ final class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter {
|
||||
closeClient(client);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return storeSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.m3u8.live;
|
||||
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
import com.arialyy.aria.core.common.RecordHandler;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.m3u8.M3U8TaskOption;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* 直播m3u8文件处理器
|
||||
*/
|
||||
final class LiveRecordHandler extends RecordHandler {
|
||||
private M3U8TaskOption mOption;
|
||||
|
||||
LiveRecordHandler(AbsTaskWrapper wrapper) {
|
||||
super(wrapper);
|
||||
}
|
||||
|
||||
public void setOption(M3U8TaskOption option) {
|
||||
mOption = option;
|
||||
}
|
||||
|
||||
@Override public void onPre() {
|
||||
super.onPre();
|
||||
RecordUtil.delTaskRecord(getEntity().getFilePath(), IRecordHandler.TYPE_DOWNLOAD);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 直播文件不需要处理任务记录
|
||||
*/
|
||||
@Deprecated
|
||||
@Override public void handlerTaskRecord(TaskRecord record) {
|
||||
if (record.threadRecords == null) {
|
||||
record.threadRecords = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 交由{@link #createThreadRecord(TaskRecord, String, int)} 处理
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public ThreadRecord createThreadRecord(TaskRecord record, int threadId, long startL, long endL) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建线程记录
|
||||
*
|
||||
* @param taskRecord 任务记录
|
||||
* @param tsUrl ts下载地址
|
||||
* @param threadId 线程id
|
||||
*/
|
||||
ThreadRecord createThreadRecord(TaskRecord taskRecord, String tsUrl, int threadId) {
|
||||
ThreadRecord tr = new ThreadRecord();
|
||||
tr.taskKey = taskRecord.filePath;
|
||||
tr.isComplete = false;
|
||||
tr.tsUrl = tsUrl;
|
||||
tr.threadType = getEntity().getTaskType();
|
||||
tr.threadId = threadId;
|
||||
tr.startLocation = 0;
|
||||
taskRecord.threadRecords.add(tr);
|
||||
return tr;
|
||||
}
|
||||
|
||||
@Override public TaskRecord createTaskRecord(int threadNum) {
|
||||
TaskRecord record = new TaskRecord();
|
||||
record.fileName = getEntity().getFileName();
|
||||
record.filePath = getEntity().getFilePath();
|
||||
record.threadRecords = new ArrayList<>();
|
||||
record.threadNum = threadNum;
|
||||
record.isBlock = true;
|
||||
record.taskType = getEntity().getTaskType();
|
||||
record.bandWidth = mOption.getBandWidth();
|
||||
return record;
|
||||
}
|
||||
|
||||
@Override public int initTaskThreadNum() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.arialyy.aria.m3u8.live;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
@@ -80,7 +81,11 @@ final class LiveStateManager implements IThreadStateManager {
|
||||
msg.getData().getString(ISchedulers.DATA_M3U8_PEER_PATH), peerIndex);
|
||||
break;
|
||||
case STATE_RUNNING:
|
||||
mProgress += (long) msg.obj;
|
||||
Bundle b = msg.getData();
|
||||
if (b != null) {
|
||||
long len = b.getLong(IThreadStateManager.DATA_ADD_LEN, 0);
|
||||
mProgress += len;
|
||||
}
|
||||
break;
|
||||
case STATE_FAIL:
|
||||
mLoader.notifyLock(false, peerIndex);
|
||||
|
||||
@@ -68,11 +68,9 @@ final class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
private Condition mCondition = LOCK.newCondition();
|
||||
private LinkedBlockingQueue<ExtInfo> mPeerQueue = new LinkedBlockingQueue<>();
|
||||
private ExtInfo mCurExtInfo;
|
||||
private LiveStateManager mManager;
|
||||
private M3U8InfoTask mInfoTask;
|
||||
private ScheduledThreadPoolExecutor mTimer;
|
||||
private List<String> mPeerUrls = new ArrayList<>();
|
||||
private Looper mLooper;
|
||||
|
||||
M3U8LiveLoader(DTaskWrapper wrapper, M3U8Listener listener) {
|
||||
super(wrapper, listener);
|
||||
@@ -94,8 +92,22 @@ final class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
if (isBreak()) {
|
||||
return;
|
||||
}
|
||||
mLooper = looper;
|
||||
|
||||
// 处理记录
|
||||
getRecordHandler().setOption(mM3U8Option);
|
||||
mRecord = getRecordHandler().getRecord(0);
|
||||
|
||||
// 初始化状态管理器
|
||||
getStateManager().setLooper(mRecord, looper);
|
||||
getStateManager().setLoader(this);
|
||||
mStateHandler = new Handler(looper, getStateManager().getHandlerCallback());
|
||||
|
||||
// 循环获取直播文件列表
|
||||
startLoaderLiveInfo();
|
||||
|
||||
// 启动定时器
|
||||
startTimer();
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override public void run() {
|
||||
String cacheDir = getCacheDir();
|
||||
@@ -127,6 +139,14 @@ final class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override protected LiveStateManager getStateManager() {
|
||||
return (LiveStateManager) super.getStateManager();
|
||||
}
|
||||
|
||||
private LiveRecordHandler getRecordHandler() {
|
||||
return (LiveRecordHandler) mRecordHandler;
|
||||
}
|
||||
|
||||
@Override public long getFileSize() {
|
||||
return mTempFile.length();
|
||||
}
|
||||
@@ -165,20 +185,14 @@ final class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
* 配置config
|
||||
*/
|
||||
private ThreadTask createThreadTask(String cacheDir, int indexId, String tsUrl) {
|
||||
ThreadRecord record = new ThreadRecord();
|
||||
record.taskKey = mRecord.filePath;
|
||||
record.isComplete = false;
|
||||
record.tsUrl = tsUrl;
|
||||
record.threadType = getEntity().getTaskType();
|
||||
record.threadId = indexId;
|
||||
mRecord.threadRecords.add(record);
|
||||
ThreadRecord tr = getRecordHandler().createThreadRecord(mRecord, tsUrl, indexId);
|
||||
|
||||
SubThreadConfig config = new SubThreadConfig();
|
||||
config.url = tsUrl;
|
||||
config.tempFile = new File(getTsFilePath(cacheDir, indexId));
|
||||
config.isBlock = mRecord.isBlock;
|
||||
config.taskWrapper = mTaskWrapper;
|
||||
config.record = record;
|
||||
config.record = tr;
|
||||
config.stateHandler = mStateHandler;
|
||||
config.peerIndex = indexId;
|
||||
config.threadType = SubThreadConfig.getThreadType(ITaskWrapper.M3U8_LIVE);
|
||||
@@ -219,15 +233,10 @@ final class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
if (isSuccess) {
|
||||
// 合并成功,删除缓存文件
|
||||
for (String pp : partPath) {
|
||||
File f = new File(pp);
|
||||
if (f.exists()) {
|
||||
f.delete();
|
||||
}
|
||||
FileUtil.deleteFile(pp);
|
||||
}
|
||||
File cDir = new File(cacheDir);
|
||||
if (cDir.exists()) {
|
||||
cDir.delete();
|
||||
}
|
||||
FileUtil.deleteDir(cDir);
|
||||
return true;
|
||||
} else {
|
||||
ALog.e(TAG, "合并失败");
|
||||
@@ -323,10 +332,7 @@ final class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
* 需要在{@link #addComponent(IRecordHandler)} 后调用
|
||||
*/
|
||||
@Override public void addComponent(IThreadStateManager threadState) {
|
||||
mManager = (LiveStateManager) threadState;
|
||||
mManager.setLooper(mRecordHandler.getRecord(0), mLooper);
|
||||
mManager.setLoader(this);
|
||||
mStateHandler = new Handler(mLooper, mManager.getHandlerCallback());
|
||||
mStateManager = threadState;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -344,7 +350,7 @@ final class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
if (mInfoTask == null) {
|
||||
throw new NullPointerException(("文件信息组件为空"));
|
||||
}
|
||||
if (mManager == null) {
|
||||
if (mStateManager == null) {
|
||||
throw new NullPointerException("任务状态管理组件为空");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,7 @@ import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.http.HttpTaskOption;
|
||||
import com.arialyy.aria.m3u8.M3U8InfoTask;
|
||||
import com.arialyy.aria.m3u8.M3U8Listener;
|
||||
import com.arialyy.aria.m3u8.M3U8RecordHandler;
|
||||
import com.arialyy.aria.m3u8.M3U8TaskOption;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
|
||||
/**
|
||||
* M3U8直播文件下载工具,对于直播来说,需要定时更新m3u8文件
|
||||
@@ -37,7 +35,6 @@ import com.arialyy.aria.util.CommonUtil;
|
||||
* 5、不处理直播切片下载失败的状态
|
||||
*/
|
||||
public class M3U8LiveUtil extends AbsNormalLoaderUtil {
|
||||
private final String TAG = CommonUtil.getClassName(getClass());
|
||||
|
||||
public M3U8LiveUtil(AbsTaskWrapper wrapper, IEventListener listener) {
|
||||
super(wrapper, listener);
|
||||
@@ -57,7 +54,7 @@ public class M3U8LiveUtil extends AbsNormalLoaderUtil {
|
||||
|
||||
@Override public LoaderStructure BuildLoaderStructure() {
|
||||
LoaderStructure structure = new LoaderStructure();
|
||||
structure.addComponent(new M3U8RecordHandler(getTaskWrapper()))
|
||||
structure.addComponent(new LiveRecordHandler(getTaskWrapper()))
|
||||
.addComponent(new M3U8InfoTask(getTaskWrapper()))
|
||||
.addComponent(new LiveStateManager(getTaskWrapper(), getListener()));
|
||||
structure.accept(getLoader());
|
||||
|
||||
@@ -73,7 +73,6 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
private Condition mJumpCondition = JUMP_LOCK.newCondition();
|
||||
private SparseArray<ThreadRecord> mBeforePeer = new SparseArray<>();
|
||||
private SparseArray<ThreadRecord> mAfterPeer = new SparseArray<>();
|
||||
private VodStateManager mManager;
|
||||
private PeerIndexEvent mCurrentEvent;
|
||||
private String mCacheDir;
|
||||
private int aIndex = 0, bIndex = 0;
|
||||
@@ -136,11 +135,6 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void onPostPre() {
|
||||
super.onPostPre();
|
||||
initData();
|
||||
}
|
||||
|
||||
@Override public boolean isBreak() {
|
||||
return super.isBreak() || isDestroy;
|
||||
}
|
||||
@@ -154,6 +148,22 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
}
|
||||
|
||||
private void startThreadTask() {
|
||||
// 处理任务记录
|
||||
((VodRecordHandler) mRecordHandler).setOption(mM3U8Option);
|
||||
mRecord = mRecordHandler.getRecord(0);
|
||||
|
||||
// 处理任务管理器
|
||||
mStateHandler = new Handler(mLooper, getStateManager().getHandlerCallback());
|
||||
getStateManager().setVodLoader(this);
|
||||
getStateManager().setLooper(mRecord, mLooper);
|
||||
|
||||
// 初始化ts数据
|
||||
initData();
|
||||
|
||||
// 启动定时器
|
||||
startTimer();
|
||||
|
||||
// 启动线程开始下载ts切片
|
||||
Thread th = new Thread(new Runnable() {
|
||||
@Override public void run() {
|
||||
while (!isBreak()) {
|
||||
@@ -258,7 +268,7 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
mCompleteNum++;
|
||||
}
|
||||
}
|
||||
mManager.updateStateCount();
|
||||
getStateManager().updateStateCount();
|
||||
if (mCompleteNum <= 0) {
|
||||
getListener().onStart(0);
|
||||
} else {
|
||||
@@ -416,7 +426,7 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
String.format("beforeSize = %s, afterSize = %s, mCompleteNum = %s", mBeforePeer.size(),
|
||||
mAfterPeer.size(), mCompleteNum));
|
||||
ALog.i(TAG, String.format("完成处理数据的操作,将优先下载【%s】之后的切片", mCurrentEvent.peerIndex));
|
||||
mManager.updateStateCount();
|
||||
getStateManager().updateStateCount();
|
||||
|
||||
try {
|
||||
JUMP_LOCK.lock();
|
||||
@@ -487,7 +497,6 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
|
||||
@Override public void addComponent(IRecordHandler recordHandler) {
|
||||
mRecordHandler = recordHandler;
|
||||
mRecord = mRecordHandler.getRecord(0);
|
||||
}
|
||||
|
||||
@Override public void addComponent(IInfoTask infoTask) {
|
||||
@@ -543,10 +552,7 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
* 需要在 {@link #addComponent(IRecordHandler)}后调用
|
||||
*/
|
||||
@Override public void addComponent(IThreadStateManager threadState) {
|
||||
mManager = (VodStateManager) threadState;
|
||||
mStateHandler = new Handler(mLooper, mManager.getHandlerCallback());
|
||||
mManager.setVodLoader(this);
|
||||
mManager.setLooper(mRecord, mLooper);
|
||||
mStateManager = threadState;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -557,6 +563,11 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected VodStateManager getStateManager() {
|
||||
return (VodStateManager) mStateManager;
|
||||
}
|
||||
|
||||
@Override protected void checkComponent() {
|
||||
if (mRecordHandler == null) {
|
||||
throw new NullPointerException("任务记录组件为空");
|
||||
@@ -564,7 +575,7 @@ final class M3U8VodLoader extends BaseM3U8Loader {
|
||||
if (mInfoTask == null) {
|
||||
throw new NullPointerException(("文件信息组件为空"));
|
||||
}
|
||||
if (mManager == null) {
|
||||
if (getStateManager() == null) {
|
||||
throw new NullPointerException("任务状态管理组件为空");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||
import com.arialyy.aria.http.HttpTaskOption;
|
||||
import com.arialyy.aria.m3u8.M3U8InfoTask;
|
||||
import com.arialyy.aria.m3u8.M3U8Listener;
|
||||
import com.arialyy.aria.m3u8.M3U8RecordHandler;
|
||||
import com.arialyy.aria.m3u8.M3U8TaskOption;
|
||||
|
||||
/**
|
||||
@@ -54,7 +53,7 @@ public final class M3U8VodUtil extends AbsNormalLoaderUtil {
|
||||
|
||||
@Override public LoaderStructure BuildLoaderStructure() {
|
||||
LoaderStructure structure = new LoaderStructure();
|
||||
structure.addComponent(new M3U8RecordHandler(getTaskWrapper()))
|
||||
structure.addComponent(new VodRecordHandler(getTaskWrapper()))
|
||||
.addComponent(new M3U8InfoTask(getTaskWrapper()))
|
||||
.addComponent(new VodStateManager(getTaskWrapper(), (M3U8Listener) getListener()));
|
||||
structure.accept(getLoader());
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.m3u8;
|
||||
package com.arialyy.aria.m3u8.vod;
|
||||
|
||||
import com.arialyy.aria.core.TaskRecord;
|
||||
import com.arialyy.aria.core.ThreadRecord;
|
||||
@@ -21,11 +21,12 @@ 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.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.wrapper.ITaskWrapper;
|
||||
import com.arialyy.aria.m3u8.BaseM3U8Loader;
|
||||
import com.arialyy.aria.m3u8.M3U8InfoTask;
|
||||
import com.arialyy.aria.m3u8.M3U8TaskOption;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.FileUtil;
|
||||
import com.arialyy.aria.util.RecordUtil;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -33,19 +34,15 @@ import java.util.ArrayList;
|
||||
* @Author lyy
|
||||
* @Date 2019-09-24
|
||||
*/
|
||||
public final class M3U8RecordHandler extends RecordHandler {
|
||||
final class VodRecordHandler extends RecordHandler {
|
||||
private M3U8TaskOption mOption;
|
||||
|
||||
public M3U8RecordHandler(DTaskWrapper wrapper) {
|
||||
VodRecordHandler(DTaskWrapper wrapper) {
|
||||
super(wrapper);
|
||||
mOption = (M3U8TaskOption) wrapper.getM3u8Option();
|
||||
}
|
||||
|
||||
@Override public void onPre() {
|
||||
super.onPre();
|
||||
if (getWrapper().getRequestType() == ITaskWrapper.M3U8_LIVE) {
|
||||
RecordUtil.delTaskRecord(getEntity().getFilePath(), IRecordHandler.TYPE_DOWNLOAD);
|
||||
}
|
||||
public void setOption(M3U8TaskOption option) {
|
||||
mOption = option;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +52,6 @@ public final class VodStateManager implements IThreadStateManager {
|
||||
private int cancelNum = 0; // 已经取消的线程的数
|
||||
private int stopNum = 0; // 已经停止的线程数
|
||||
private int failNum = 0; // 失败的线程数
|
||||
private long percent; //当前总进度,百分比进度
|
||||
private long progress;
|
||||
private TaskRecord taskRecord; // 任务记录
|
||||
private Looper looper;
|
||||
@@ -164,7 +163,11 @@ public final class VodStateManager implements IThreadStateManager {
|
||||
}
|
||||
break;
|
||||
case STATE_RUNNING:
|
||||
progress += (long) msg.obj;
|
||||
Bundle b = msg.getData();
|
||||
if (b != null) {
|
||||
long len = b.getLong(IThreadStateManager.DATA_ADD_LEN, 0);
|
||||
progress += len;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
@@ -226,7 +229,6 @@ public final class VodStateManager implements IThreadStateManager {
|
||||
int percent = completeNum * 100 / taskRecord.threadRecords.size();
|
||||
getEntity().setPercent(percent);
|
||||
getEntity().update();
|
||||
this.percent = percent;
|
||||
}
|
||||
|
||||
@Override public boolean isFail() {
|
||||
|
||||
@@ -41,6 +41,11 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable,
|
||||
*/
|
||||
@Ignore private int failNum = 0;
|
||||
|
||||
/**
|
||||
* 剩余时间,单位:s
|
||||
*/
|
||||
@Ignore private int timeLeft = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* 扩展字段
|
||||
*/
|
||||
@@ -81,6 +86,18 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable,
|
||||
*/
|
||||
private long stopTime = 0;
|
||||
|
||||
/**
|
||||
* 获取剩余时间,单位:s
|
||||
* 如果是m3u8任务,无法获取剩余时间;m2u8任务如果需要获取剩余时间,请设置文件长度{@link #setFileSize(long)}
|
||||
*/
|
||||
public int getTimeLeft() {
|
||||
return timeLeft;
|
||||
}
|
||||
|
||||
public void setTimeLeft(int timeLeft) {
|
||||
this.timeLeft = timeLeft;
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return isComplete;
|
||||
}
|
||||
|
||||
@@ -156,10 +156,18 @@ public class RecordHelper {
|
||||
: mTaskRecord.filePath);
|
||||
ThreadRecord tr = mTaskRecord.threadRecords.get(0);
|
||||
if (!file.exists()) {
|
||||
ALog.w(TAG, String.format("文件【%s】不存在,任务将重新开始", file.getPath()));
|
||||
tr.startLocation = 0;
|
||||
tr.isComplete = false;
|
||||
tr.endLocation = mWrapper.getEntity().getFileSize();
|
||||
// 目标文件
|
||||
File targetFile = new File(mTaskRecord.filePath);
|
||||
// 处理组合任务其中一个子任务完成的情况
|
||||
if (tr.isComplete && targetFile.exists() && targetFile.length() == mWrapper.getEntity()
|
||||
.getFileSize()) {
|
||||
tr.isComplete = true;
|
||||
} else {
|
||||
ALog.w(TAG, String.format("文件【%s】不存在,任务将重新开始", file.getPath()));
|
||||
tr.startLocation = 0;
|
||||
tr.isComplete = false;
|
||||
tr.endLocation = mWrapper.getEntity().getFileSize();
|
||||
}
|
||||
} else if (file.length() > mWrapper.getEntity().getFileSize()) {
|
||||
ALog.i(TAG, String.format("文件【%s】错误,任务重新开始", file.getPath()));
|
||||
FileUtil.deleteFile(file);
|
||||
|
||||
@@ -46,7 +46,7 @@ public class SubThreadConfig {
|
||||
public int peerIndex;
|
||||
// 线程任务类型
|
||||
public int threadType = TYPE_HTTP;
|
||||
// 更新间隔,单位:毫秒
|
||||
// 进度更新间隔,单位:毫秒
|
||||
public long updateInterval = 1000;
|
||||
|
||||
/**
|
||||
|
||||
@@ -272,8 +272,8 @@ public abstract class AbsGroupLoader implements ILoaderVisitor, ILoader {
|
||||
mListener.onComplete();
|
||||
return;
|
||||
}
|
||||
startTimer();
|
||||
handlerTask(looper);
|
||||
startTimer();
|
||||
Looper.loop();
|
||||
}
|
||||
|
||||
|
||||
@@ -140,6 +140,13 @@ public abstract class BaseListener<ENTITY extends AbsEntity, TASK_WRAPPER extend
|
||||
mEntity.setPercent((int) (mEntity.getFileSize() <= 0 ? 0
|
||||
: mEntity.getCurrentProgress() * 100 / mEntity.getFileSize()));
|
||||
}
|
||||
if (mEntity.getFileSize() != 0) {
|
||||
if (speed == 0) {
|
||||
mEntity.setTimeLeft(Integer.MAX_VALUE);
|
||||
} else {
|
||||
mEntity.setTimeLeft((int) ((mEntity.getFileSize() - mEntity.getCurrentProgress()) / speed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,6 @@ 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.TaskSchedulerType;
|
||||
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||
import com.arialyy.aria.core.task.AbsTask;
|
||||
import com.arialyy.aria.core.task.DownloadGroupTask;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
@@ -113,18 +112,25 @@ public class DownloadGroupListener
|
||||
}
|
||||
|
||||
private void handleSubSpeed(DownloadEntity subEntity, long currentProgress) {
|
||||
if (currentProgress == 0){
|
||||
if (currentProgress == 0) {
|
||||
subEntity.setSpeed(0);
|
||||
subEntity.setConvertSpeed("0kb/s");
|
||||
return;
|
||||
}
|
||||
long range = currentProgress - subEntity.getCurrentProgress() ;
|
||||
subEntity.setSpeed(range);
|
||||
long speed = currentProgress - subEntity.getCurrentProgress();
|
||||
subEntity.setSpeed(speed);
|
||||
subEntity.setConvertSpeed(
|
||||
range <= 0 ? "" : String.format("%s/s", CommonUtil.formatFileSize(range)));
|
||||
speed <= 0 ? "" : String.format("%s/s", CommonUtil.formatFileSize(speed)));
|
||||
subEntity.setPercent((int) (subEntity.getFileSize() <= 0 ? 0
|
||||
: subEntity.getCurrentProgress() * 100 / subEntity.getFileSize()));
|
||||
subEntity.setCurrentProgress(currentProgress);
|
||||
|
||||
if (speed == 0) {
|
||||
subEntity.setTimeLeft(Integer.MAX_VALUE);
|
||||
} else {
|
||||
subEntity.setTimeLeft(
|
||||
(int) ((subEntity.getFileSize() - subEntity.getCurrentProgress()) / speed));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,8 +156,6 @@ public class DownloadGroupListener
|
||||
subEntity.setPercent(100);
|
||||
subEntity.setConvertSpeed("0kb/s");
|
||||
subEntity.setSpeed(0);
|
||||
ALog.i(TAG, String.format("任务【%s】完成,将删除线程任务记录", mEntity.getKey()));
|
||||
RecordUtil.delTaskRecord(subEntity.getFilePath(), IRecordHandler.TYPE_DOWNLOAD, false, false);
|
||||
}
|
||||
subEntity.update();
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
public abstract class AbsNormalLoader implements ILoaderVisitor, ILoader {
|
||||
protected final String TAG = CommonUtil.getClassName(getClass());
|
||||
;
|
||||
private IEventListener mListener;
|
||||
protected AbsTaskWrapper mTaskWrapper;
|
||||
protected File mTempFile;
|
||||
@@ -127,7 +126,6 @@ public abstract class AbsNormalLoader implements ILoaderVisitor, ILoader {
|
||||
isRuning = true;
|
||||
resetState();
|
||||
onPostPre();
|
||||
startTimer();
|
||||
handleTask(looper);
|
||||
Looper.loop();
|
||||
}
|
||||
@@ -149,7 +147,7 @@ public abstract class AbsNormalLoader implements ILoaderVisitor, ILoader {
|
||||
/**
|
||||
* 启动进度获取定时器
|
||||
*/
|
||||
private synchronized void startTimer() {
|
||||
protected synchronized void startTimer() {
|
||||
if (isBreak()) {
|
||||
return;
|
||||
}
|
||||
@@ -157,25 +155,32 @@ public abstract class AbsNormalLoader implements ILoaderVisitor, ILoader {
|
||||
mTimer = new ScheduledThreadPoolExecutor(1);
|
||||
mTimer.scheduleWithFixedDelay(new Runnable() {
|
||||
@Override public void run() {
|
||||
if (mStateManager.isComplete()
|
||||
|| mStateManager.isFail()
|
||||
|| !isRunning()
|
||||
|| isBreak()) {
|
||||
//ALog.d(TAG, "isComplete = " + mStateManager.isComplete()
|
||||
// + "; isFail = " + mStateManager.isFail()
|
||||
// + "; isRunning = " + isRunning()
|
||||
// + "; isBreak = " + isBreak());
|
||||
ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey());
|
||||
closeTimer();
|
||||
onDestroy();
|
||||
} else if (mStateManager.getCurrentProgress() >= 0) {
|
||||
mListener.onProgress(mStateManager.getCurrentProgress());
|
||||
// 线程池中是不抛异常的,没有日志,很难定位问题,需要手动try-catch
|
||||
try {
|
||||
if (mStateManager == null) {
|
||||
ALog.e(TAG, "stateManager is null");
|
||||
} else if (mStateManager.isComplete()
|
||||
|| mStateManager.isFail()
|
||||
|| !isRunning()
|
||||
|| isBreak()) {
|
||||
//ALog.d(TAG, "isComplete = " + mStateManager.isComplete()
|
||||
// + "; isFail = " + mStateManager.isFail()
|
||||
// + "; isRunning = " + isRunning()
|
||||
// + "; isBreak = " + isBreak());
|
||||
ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey());
|
||||
closeTimer();
|
||||
onDestroy();
|
||||
} else if (mStateManager.getCurrentProgress() >= 0) {
|
||||
mListener.onProgress(mStateManager.getCurrentProgress());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, delayTimer(), mUpdateInterval, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public synchronized void closeTimer() {
|
||||
private synchronized void closeTimer() {
|
||||
if (mTimer != null && !mTimer.isShutdown()) {
|
||||
mTimer.shutdown();
|
||||
}
|
||||
|
||||
@@ -125,6 +125,9 @@ public class NormalLoader extends AbsNormalLoader {
|
||||
for (IThreadTask threadTask : getTaskList()) {
|
||||
ThreadTaskManager.getInstance().startThread(mTaskWrapper.getKey(), threadTask);
|
||||
}
|
||||
|
||||
// 启动定时器
|
||||
startTimer();
|
||||
}
|
||||
|
||||
@Override public long getCurrentProgress() {
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.arialyy.aria.core.task;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.common.AbsEntity;
|
||||
import com.arialyy.aria.core.inf.IEntity;
|
||||
import com.arialyy.aria.core.inf.IUtil;
|
||||
import com.arialyy.aria.core.inf.TaskSchedulerType;
|
||||
@@ -71,6 +72,25 @@ public abstract class AbsTask<TASK_WRAPPER extends AbsTaskWrapper>
|
||||
return mUtil;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取剩余时间,单位:s
|
||||
* 如果是m3u8任务,无法获取剩余时间;m2u8任务如果需要获取剩余时间,请设置文件长度{@link AbsEntity#setFileSize(long)}
|
||||
*/
|
||||
public int getTimeLeft() {
|
||||
return getTaskWrapper().getEntity().getTimeLeft();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换时间
|
||||
* 时间<1 小时,显示分秒,显示样式 00:20
|
||||
* 时间 ≥1 小时,显示时分秒,显示样式 01:11:12
|
||||
* 时间 ≥1 天,显示天时分,显示样式 1d 01:11
|
||||
* 时间 ≥7 天,显示样式 ∞
|
||||
*/
|
||||
public String getConvertTimeLeft() {
|
||||
return CommonUtil.formatTime(getTaskWrapper().getEntity().getTimeLeft());
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加扩展数据 读取扩展数据{@link #getExpand(String)}
|
||||
*/
|
||||
@@ -194,12 +214,16 @@ public abstract class AbsTask<TASK_WRAPPER extends AbsTaskWrapper>
|
||||
|
||||
@Override public void start(int type) {
|
||||
mSchedulerType = type;
|
||||
mUtil = createUtil();
|
||||
if (mUtil == null){
|
||||
ALog.e(TAG, "任务工具创建失败");
|
||||
return;
|
||||
}
|
||||
if (type == TaskSchedulerType.TYPE_START_AND_RESET_STATE) {
|
||||
if (getUtil().isRunning()) {
|
||||
ALog.e(TAG, String.format("任务【%s】重启失败", getTaskName()));
|
||||
return;
|
||||
}
|
||||
mUtil = createUtil();
|
||||
mUtil.start();
|
||||
ALog.d(TAG, String.format("任务【%s】重启成功", getTaskName()));
|
||||
return;
|
||||
@@ -216,6 +240,11 @@ public abstract class AbsTask<TASK_WRAPPER extends AbsTaskWrapper>
|
||||
}
|
||||
|
||||
@Override public void stop(int type) {
|
||||
mUtil = createUtil();
|
||||
if (mUtil == null){
|
||||
ALog.e(TAG, "任务工具创建失败");
|
||||
return;
|
||||
}
|
||||
isStop = true;
|
||||
mSchedulerType = type;
|
||||
getUtil().stop();
|
||||
@@ -226,6 +255,11 @@ public abstract class AbsTask<TASK_WRAPPER extends AbsTaskWrapper>
|
||||
}
|
||||
|
||||
@Override public void cancel(int type) {
|
||||
mUtil = createUtil();
|
||||
if (mUtil == null){
|
||||
ALog.e(TAG, "任务工具创建失败");
|
||||
return;
|
||||
}
|
||||
isCancel = true;
|
||||
mSchedulerType = type;
|
||||
getUtil().cancel();
|
||||
|
||||
@@ -67,8 +67,8 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
private long mRangeProgress, mLastRangeProgress;
|
||||
private IThreadTaskAdapter mAdapter;
|
||||
private ThreadRecord mRecord;
|
||||
private String mThreadNmae;
|
||||
private long updateInterval = 1000; // 更新间隔
|
||||
private String mThreadName;
|
||||
private long updateInterval; // 更新间隔
|
||||
|
||||
private Thread mConfigThread = new Thread(new Runnable() {
|
||||
@Override public void run() {
|
||||
@@ -243,8 +243,8 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
}
|
||||
|
||||
@Override public String getThreadName() {
|
||||
return mThreadNmae == null ? CommonUtil.getThreadName(getConfig().url, getThreadId())
|
||||
: mThreadNmae;
|
||||
return mThreadName == null ? (mThreadName =
|
||||
CommonUtil.getThreadName(getConfig().url, getThreadId())) : mThreadName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,7 +287,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
bundle.putLong(IThreadStateManager.DATA_THREAD_LOCATION, mRangeProgress);
|
||||
msg.what = state;
|
||||
int reqType = getConfig().threadType;
|
||||
if (reqType == ITaskWrapper.M3U8_VOD || reqType == ITaskWrapper.M3U8_LIVE) {
|
||||
if (reqType == SubThreadConfig.TYPE_M3U8_PEER) {
|
||||
sendM3U8Info(state, msg);
|
||||
}
|
||||
|
||||
@@ -299,10 +299,10 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
}
|
||||
|
||||
private void sendM3U8Info(int state, Message msg) {
|
||||
Bundle bundle = msg.getData();
|
||||
if (state != IThreadStateManager.STATE_UPDATE_PROGRESS) {
|
||||
msg.obj = this;
|
||||
}
|
||||
Bundle bundle = msg.getData();
|
||||
if ((state == IThreadStateManager.STATE_COMPLETE || state == IThreadStateManager.STATE_FAIL)) {
|
||||
bundle.putString(ISchedulers.DATA_M3U8_URL, getConfig().url);
|
||||
bundle.putString(ISchedulers.DATA_M3U8_PEER_PATH, getConfig().tempFile.getPath());
|
||||
@@ -313,6 +313,8 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
@Override public synchronized void updateCompleteState() {
|
||||
ALog.i(TAG, String.format("任务【%s】线程__%s__完成", getTaskWrapper().getKey(), mRecord.threadId));
|
||||
writeConfig(true, mRecord.endLocation);
|
||||
// 进度发送不是实时的,发送完成任务前,需要更新一次进度
|
||||
sendRunningState();
|
||||
updateState(IThreadStateManager.STATE_COMPLETE, null);
|
||||
}
|
||||
|
||||
@@ -334,17 +336,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
}
|
||||
// 不需要太频繁发送,以减少消息队列的压力
|
||||
if (System.currentTimeMillis() - mLastSendProgressTime > updateInterval) {
|
||||
Message msg = mStateHandler.obtainMessage();
|
||||
Bundle b = msg.getData();
|
||||
if (b == null) {
|
||||
b = new Bundle();
|
||||
msg.setData(b);
|
||||
}
|
||||
b.putString(IThreadStateManager.DATA_THREAD_NAME, getThreadName());
|
||||
b.putLong(IThreadStateManager.DATA_ADD_LEN, mRangeProgress - mLastRangeProgress);
|
||||
msg.what = IThreadStateManager.STATE_RUNNING;
|
||||
msg.obj = mRangeProgress;
|
||||
msg.sendToTarget();
|
||||
sendRunningState();
|
||||
mLastRangeProgress = mRangeProgress;
|
||||
mLastSendProgressTime = System.currentTimeMillis();
|
||||
}
|
||||
@@ -358,6 +350,23 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送执行中的数据
|
||||
*/
|
||||
private void sendRunningState() {
|
||||
Message msg = mStateHandler.obtainMessage();
|
||||
Bundle b = msg.getData();
|
||||
if (b == null) {
|
||||
b = new Bundle();
|
||||
msg.setData(b);
|
||||
}
|
||||
b.putString(IThreadStateManager.DATA_THREAD_NAME, getThreadName());
|
||||
b.putLong(IThreadStateManager.DATA_ADD_LEN, mRangeProgress - mLastRangeProgress);
|
||||
msg.what = IThreadStateManager.STATE_RUNNING;
|
||||
msg.obj = mRangeProgress;
|
||||
msg.sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getThreadProgress() {
|
||||
return mRangeProgress;
|
||||
|
||||
@@ -48,6 +48,7 @@ import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -794,6 +795,39 @@ public class CommonUtil {
|
||||
return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "tb";
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换时间
|
||||
* 时间<1 小时,显示分秒,显示样式 00:20
|
||||
* 时间 ≥1 小时,显示时分秒,显示样式 01:11:12
|
||||
* 时间 ≥1 天,显示天时分,显示样式 1d 01:11
|
||||
* 时间 ≥7 天,显示样式 ∞
|
||||
*
|
||||
* @param seconds 单位为s的时间
|
||||
*/
|
||||
public static String formatTime(int seconds) {
|
||||
String standardTime;
|
||||
if (seconds <= 0) {
|
||||
standardTime = "00:00";
|
||||
} else if (seconds < 60) {
|
||||
standardTime = String.format(Locale.getDefault(), "00:%02d", seconds % 60);
|
||||
} else if (seconds < 3600) {
|
||||
standardTime = String.format(Locale.getDefault(), "%02d:%02d", seconds / 60, seconds % 60);
|
||||
} else if (seconds < 86400) {
|
||||
standardTime =
|
||||
String.format(Locale.getDefault(), "%02d:%02d:%02d", seconds / 3600, seconds % 3600 / 60,
|
||||
seconds % 60);
|
||||
} else if (seconds < 604800) {
|
||||
standardTime =
|
||||
String.format(Locale.getDefault(), "%dd %02d:%02d", seconds / 86400,
|
||||
seconds % 86400 / 3600,
|
||||
seconds % 3600);
|
||||
} else {
|
||||
standardTime = "∞";
|
||||
}
|
||||
|
||||
return standardTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过文件名获取下载配置文件路径
|
||||
*
|
||||
|
||||
@@ -128,6 +128,7 @@ public class ComponentUtil {
|
||||
break;
|
||||
}
|
||||
if (className == null) {
|
||||
ALog.e(TAG, "不识别的类名:" + className);
|
||||
return null;
|
||||
}
|
||||
T util = null;
|
||||
|
||||
@@ -204,6 +204,7 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
|
||||
getBinding().setProgress(task.getPercent());
|
||||
}
|
||||
getBinding().setSpeed(task.getConvertSpeed());
|
||||
getBinding().setTimeLeft(task.getConvertTimeLeft());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -155,10 +155,11 @@ public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBin
|
||||
+ task.getPercent()
|
||||
+ ", speed = "
|
||||
+ task.getConvertSpeed()
|
||||
+ "current_p = "
|
||||
+ ", current_p = "
|
||||
+ task.getCurrentProgress());
|
||||
getBinding().setProgress(task.getPercent());
|
||||
getBinding().setSpeed(task.getConvertSpeed());
|
||||
getBinding().setTimeLeft(task.getConvertTimeLeft());
|
||||
//Log.d(TAG, "sub_len = " + task.getEntity().getSubEntities().size());
|
||||
mChildList.updateChildProgress(task.getEntity().getSubEntities());
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ public class M3U8LiveDLoadActivity extends BaseActivity<ActivityM3u8LiveBinding>
|
||||
|
||||
@Download.onTaskFail
|
||||
void taskFail(DownloadTask task, Exception e) {
|
||||
if (task.getKey().equals(mUrl)) {
|
||||
if (task != null && task.getKey().equals(mUrl)) {
|
||||
Toast.makeText(M3U8LiveDLoadActivity.this, getString(R.string.download_fail),
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
@@ -216,14 +216,14 @@ public class M3U8LiveDLoadActivity extends BaseActivity<ActivityM3u8LiveBinding>
|
||||
switch (view.getId()) {
|
||||
case R.id.start:
|
||||
if (Aria.download(this).load(mTaskId).isRunning()) {
|
||||
Aria.download(this).load(mEntity.getId()).stop();
|
||||
Aria.download(this).load(mTaskId).stop();
|
||||
} else {
|
||||
startD();
|
||||
}
|
||||
break;
|
||||
case R.id.cancel:
|
||||
if (mTaskId != -1){
|
||||
Aria.download(this).load(mEntity.getId()).cancel(true);
|
||||
Aria.download(this).load(mTaskId).cancel(true);
|
||||
mTaskId = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -210,7 +210,7 @@ public class M3U8VodDLoadActivity extends BaseActivity<ActivityM3u8VodBinding> {
|
||||
@Download.onTaskRunning
|
||||
protected void running(DownloadTask task) {
|
||||
if (task.getKey().equals(mUrl)) {
|
||||
//ALog.d(TAG, "isRunning");
|
||||
ALog.d(TAG, "m3u8 void running, p = " + task.getPercent() + ", speed = " + task.getConvertSpeed());
|
||||
getBinding().setProgress(task.getPercent());
|
||||
getBinding().setSpeed(task.getConvertSpeed());
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
name="stateStr"
|
||||
type="String"
|
||||
/>
|
||||
<variable
|
||||
name="timeLeft"
|
||||
type="String"
|
||||
/>
|
||||
|
||||
</data>
|
||||
|
||||
@@ -40,6 +44,7 @@
|
||||
bind:progress="@{progress}"
|
||||
bind:speed="@{speed}"
|
||||
bind:stateStr="@{stateStr}"
|
||||
bind:timeLeft="@{timeLeft}"
|
||||
/>
|
||||
|
||||
<com.arialyy.simple.widget.SubStateLinearLayout
|
||||
|
||||
@@ -105,6 +105,16 @@
|
||||
style="?buttonBarButtonStyle"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/cancel"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:onClick="onClick"
|
||||
android:text="@string/cancel"
|
||||
style="?buttonBarButtonStyle"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
name="viewModel"
|
||||
type="com.arialyy.simple.core.download.SingleTaskActivity"
|
||||
/>
|
||||
<variable
|
||||
name="timeLeft"
|
||||
type="String"
|
||||
/>
|
||||
</data>
|
||||
|
||||
<LinearLayout
|
||||
@@ -74,6 +78,7 @@
|
||||
bind:progress="@{progress}"
|
||||
bind:speed="@{speed}"
|
||||
bind:stateStr="@{stateStr}"
|
||||
bind:timeLeft="@{timeLeft}"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
name="speed"
|
||||
type="String"
|
||||
/>
|
||||
<variable
|
||||
name="timeLeft"
|
||||
type="String"
|
||||
/>
|
||||
<variable
|
||||
name="progress"
|
||||
type="int"
|
||||
@@ -64,6 +68,7 @@
|
||||
android:layout_below="@+id/progressBar"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/speed"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -74,6 +79,16 @@
|
||||
android:textColor="@color/black"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time_left"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@{timeLeft}"
|
||||
android:textColor="@color/black"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/start"
|
||||
android:layout_width="0dp"
|
||||
|
||||
Reference in New Issue
Block a user