修复任务记录删除失败的问题,优化网络连接状态获取的逻辑,修复配置文件的某些配置失效的问题

v3.6.6
laoyuyu 6 years ago
parent 8f8f8fa7d7
commit ae3d24f471
  1. 58
      Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
  2. 26
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
  3. 15
      Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java
  4. 6
      Aria/src/main/java/com/arialyy/aria/core/common/BaseListener.java
  5. 81
      Aria/src/main/java/com/arialyy/aria/core/common/RecordHandler.java
  6. 5
      Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java
  7. 6
      Aria/src/main/java/com/arialyy/aria/core/common/ThreadRecord.java
  8. 8
      Aria/src/main/java/com/arialyy/aria/core/common/ftp/FtpDelegate.java
  9. 17
      Aria/src/main/java/com/arialyy/aria/core/config/DownloadConfig.java
  10. 36
      Aria/src/main/java/com/arialyy/aria/core/config/XMLReader.java
  11. 2
      Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java
  12. 8
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java
  13. 4
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
  14. 5
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
  15. 4
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java
  16. 1
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/BaseM3U8Loader.java
  17. 2
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/ITsMergeHandler.java
  18. 37
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8KeyInfo.java
  19. 4
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8LiveUtil.java
  20. 18
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8VodLoader.java
  21. 4
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8VodUtil.java
  22. 2
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
  23. 14
      Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java
  24. 4
      Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java
  25. 2
      Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java
  26. 34
      Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
  27. 8
      Aria/src/main/java/com/arialyy/aria/util/NetUtils.java
  28. 7
      Aria/src/main/java/com/arialyy/aria/util/RecordUtil.java
  29. 3
      DEV_LOG.md
  30. 4
      app/build.gradle
  31. 4
      app/src/main/assets/aria_config.xml
  32. 3
      app/src/main/java/com/arialyy/simple/core/download/HttpDownloadModule.java
  33. 5
      app/src/main/java/com/arialyy/simple/core/download/SingleTaskActivity.java
  34. 9
      app/src/main/java/com/arialyy/simple/core/download/m3u8/M3U8VodDownloadActivity.java
  35. 2
      aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java
  36. 2
      build.gradle

@ -21,13 +21,20 @@ import android.app.Activity;
import android.app.Application; import android.app.Application;
import android.app.Dialog; import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.support.annotation.RequiresApi;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.widget.PopupWindow; import android.widget.PopupWindow;
import com.arialyy.aria.BuildConfig;
import com.arialyy.aria.core.command.ICmd; import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.common.QueueMod; import com.arialyy.aria.core.common.QueueMod;
import com.arialyy.aria.core.common.RecordHandler; import com.arialyy.aria.core.common.RecordHandler;
@ -71,6 +78,10 @@ import org.xml.sax.SAXException;
public static final Object LOCK = new Object(); public static final Object LOCK = new Object();
public static final String DOWNLOAD_TEMP_DIR = "/Aria/temp/download/"; public static final String DOWNLOAD_TEMP_DIR = "/Aria/temp/download/";
public static final String UPLOAD_TEMP_DIR = "/Aria/temp/upload/"; public static final String UPLOAD_TEMP_DIR = "/Aria/temp/upload/";
/**
* 是否已经联网true 已经联网
*/
private static boolean isConnectedNet = true;
@SuppressLint("StaticFieldLeak") private static volatile AriaManager INSTANCE = null; @SuppressLint("StaticFieldLeak") private static volatile AriaManager INSTANCE = null;
private Map<String, AbsReceiver> mReceivers = new ConcurrentHashMap<>(); private Map<String, AbsReceiver> mReceivers = new ConcurrentHashMap<>();
@ -85,7 +96,6 @@ import org.xml.sax.SAXException;
private AppConfig mAConfig; private AppConfig mAConfig;
private DGroupConfig mDGConfig; private DGroupConfig mDGConfig;
private Handler mAriaHandler; private Handler mAriaHandler;
private File[] files;
private AriaManager(Context context) { private AriaManager(Context context) {
APP = context.getApplicationContext(); APP = context.getApplicationContext();
@ -94,6 +104,7 @@ import org.xml.sax.SAXException;
initConfig(); initConfig();
initAria(); initAria();
amendTaskState(); amendTaskState();
regNetCallBack(context);
} }
public static AriaManager getInstance(Context context) { public static AriaManager getInstance(Context context) {
@ -109,6 +120,47 @@ import org.xml.sax.SAXException;
return INSTANCE; return INSTANCE;
} }
/**
* 注册网络监听只有配置了检查网络{@link AppConfig#isNetCheck()}才会注册事件
*/
private void regNetCallBack(Context context) {
if (!getAppConfig().isNetCheck()) {
return;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return;
}
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm == null) {
return;
}
NetworkRequest.Builder builder = new NetworkRequest.Builder();
NetworkRequest request = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build();
cm.registerNetworkCallback(request, new ConnectivityManager.NetworkCallback() {
@Override public void onLost(Network network) {
super.onLost(network);
isConnectedNet = false;
ALog.d(TAG, "onLost");
}
@Override public void onAvailable(Network network) {
super.onAvailable(network);
ALog.d(TAG, "onAvailable");
isConnectedNet = true;
}
});
}
/**
* 初始化数据库
*/
private void initDb(Context context) { private void initDb(Context context) {
// 这个地方错误了,获取数据库路径见:https://www.jianshu.com/p/815c9efc5449 // 这个地方错误了,获取数据库路径见:https://www.jianshu.com/p/815c9efc5449
String oldDbName = "AriaLyyDb"; String oldDbName = "AriaLyyDb";
@ -153,6 +205,10 @@ import org.xml.sax.SAXException;
return mAriaHandler; return mAriaHandler;
} }
public boolean isConnectedNet() {
return isConnectedNet;
}
public Map<String, AbsReceiver> getReceiver() { public Map<String, AbsReceiver> getReceiver() {
return mReceivers; return mReceivers;
} }

@ -193,7 +193,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
return b; return b;
} }
public synchronized void cancel() { final public synchronized void cancel() {
if (isCancel) { if (isCancel) {
ALog.d(TAG, String.format("任务【%s】正在删除,删除任务失败", mTaskWrapper.getKey())); ALog.d(TAG, String.format("任务【%s】正在删除,删除任务失败", mTaskWrapper.getKey()));
return; return;
@ -208,13 +208,24 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
} }
} }
ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey()); ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey());
onPostCancel();
} }
/**
* 删除线程任务前的操作
*/
protected void onCancel() { protected void onCancel() {
} }
public synchronized void stop() { /**
* 删除操作处理完成
*/
protected void onPostCancel() {
}
final public synchronized void stop() {
if (isStop) { if (isStop) {
return; return;
} }
@ -229,12 +240,23 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
} }
} }
ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey()); ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey());
onPostStop();
} }
/**
* 停止线程任务前的操作
*/
protected void onStop() { protected void onStop() {
} }
/**
* 停止操作完成
*/
protected void onPostStop() {
}
/** /**
* 直接调用的时候会自动启动线程执行 * 直接调用的时候会自动启动线程执行
*/ */

@ -175,7 +175,6 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
* 中断任务 * 中断任务
*/ */
void breakTask() { void breakTask() {
synchronized (AriaManager.LOCK) {
taskBreak = true; taskBreak = true;
if (mTaskWrapper.isSupportBP()) { if (mTaskWrapper.isSupportBP()) {
final long currentTemp = mChildCurrentLocation; final long currentTemp = mChildCurrentLocation;
@ -187,7 +186,6 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
ALog.i(TAG, String.format("任务【%s】已中断", getFileName())); ALog.i(TAG, String.format("任务【%s】已中断", getFileName()));
} }
} }
}
/** /**
* 发送状态给状态处理器 * 发送状态给状态处理器
@ -276,7 +274,6 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
* 执行中 * 执行中
*/ */
protected void progress(long len) { protected void progress(long len) {
synchronized (AriaManager.LOCK) {
//if (getState().CURRENT_LOCATION > getEntity().getFileSize() && !getTaskWrapper().asHttp() //if (getState().CURRENT_LOCATION > getEntity().getFileSize() && !getTaskWrapper().asHttp()
// .isChunked()) { // .isChunked()) {
// String errorMsg = // String errorMsg =
@ -300,7 +297,6 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
} }
} }
} }
}
/** /**
* 取消任务 * 取消任务
@ -350,14 +346,15 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
* 重试ts分片 * 重试ts分片
*/ */
private void retryM3U8Peer(boolean needRetry) { private void retryM3U8Peer(boolean needRetry) {
if (!NetUtils.isConnected(AriaManager.APP) && !isNotNetRetry) { boolean isConnected = NetUtils.isConnected(AriaManager.APP);
ALog.w(TAG, String.format("任务【%s】重试失败,网络未连接", getFileName())); if (!isConnected && !isNotNetRetry) {
ALog.w(TAG, String.format("ts切片【%s】重试失败,网络未连接", getFileName()));
sendFailMsg(null); sendFailMsg(null);
return; return;
} }
if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(AriaManager.APP) if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(AriaManager.APP)
|| isNotNetRetry) && !isBreak()) { || isNotNetRetry) && !isBreak()) {
ALog.w(TAG, String.format("任务【%s】正在重试", getFileName())); ALog.w(TAG, String.format("ts切片【%s】正在重试", getFileName()));
mFailTimes++; mFailTimes++;
mConfig.tempFile.delete(); mConfig.tempFile.delete();
CommonUtil.createFile(mConfig.tempFile.getPath()); CommonUtil.createFile(mConfig.tempFile.getPath());
@ -374,13 +371,13 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
*/ */
private void retryBlockTask(boolean needRetry) { private void retryBlockTask(boolean needRetry) {
if (!NetUtils.isConnected(AriaManager.APP) && !isNotNetRetry) { if (!NetUtils.isConnected(AriaManager.APP) && !isNotNetRetry) {
ALog.w(TAG, String.format("任务【%s】重试失败,网络未连接", getFileName())); ALog.w(TAG, String.format("分块【%s】重试失败,网络未连接", getFileName()));
sendFailMsg(null); sendFailMsg(null);
return; return;
} }
if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(AriaManager.APP) if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(AriaManager.APP)
|| isNotNetRetry) && !isBreak()) { || isNotNetRetry) && !isBreak()) {
ALog.w(TAG, String.format("任务【%s】正在重试", getFileName())); ALog.w(TAG, String.format("分块【%s】正在重试", getFileName()));
mFailTimes++; mFailTimes++;
handleBlockRecord(); handleBlockRecord();
ThreadTaskManager.getInstance().retryThread(this); ThreadTaskManager.getInstance().retryThread(this);

@ -156,13 +156,13 @@ public abstract class BaseListener<ENTITY extends AbsEntity, TASK_WRAPPER extend
mEntity.setCurrentProgress(mEntity.getFileSize()); mEntity.setCurrentProgress(mEntity.getFileSize());
mEntity.setPercent(100); mEntity.setPercent(100);
handleSpeed(0); handleSpeed(0);
ALog.i(TAG, String.format("任务【%s】完成,将删除线程任务记录", mEntity.getKey())); ALog.i(TAG, String.format("任务【%s】完成,将删除任务任务记录", mEntity.getKey()));
if (mEntity instanceof DownloadGroupEntity) { if (mEntity instanceof DownloadGroupEntity) {
RecordUtil.delGroupTaskRecord((DownloadGroupEntity) mEntity, false, false); RecordUtil.delGroupTaskRecord((DownloadGroupEntity) mEntity, false, false);
} else if (mEntity instanceof DownloadEntity) { } else if (mEntity instanceof DownloadEntity) {
RecordUtil.delTaskRecord(mEntity.getKey(), RecordHandler.TYPE_DOWNLOAD, false, false); RecordUtil.delTaskRecord(((DownloadEntity) mEntity).getFilePath(), RecordHandler.TYPE_DOWNLOAD, false, false);
} else if (mEntity instanceof UploadEntity) { } else if (mEntity instanceof UploadEntity) {
RecordUtil.delTaskRecord(mEntity.getKey(), RecordHandler.TYPE_UPLOAD, false, false); RecordUtil.delTaskRecord(((UploadEntity) mEntity).getFilePath(), RecordHandler.TYPE_UPLOAD, false, false);
} }
} }

@ -59,7 +59,7 @@ public class RecordHandler {
public static final String SUB_PATH = "%s.%s.part"; public static final String SUB_PATH = "%s.%s.part";
@Deprecated private File mConfigFile; @Deprecated private File mConfigFile;
private TaskRecord mRecord; private TaskRecord mTaskRecord;
private AbsTaskWrapper mTaskWrapper; private AbsTaskWrapper mTaskWrapper;
private AbsNormalEntity mEntity; private AbsNormalEntity mEntity;
@ -81,11 +81,11 @@ public class RecordHandler {
if (mConfigFile.exists()) { if (mConfigFile.exists()) {
convertDb(); convertDb();
} else { } else {
mRecord = DbDataHelper.getTaskRecord(getFilePath()); mTaskRecord = DbDataHelper.getTaskRecord(getFilePath());
if (mRecord == null) { if (mTaskRecord == null) {
initRecord(true); initRecord(true);
} else { } else {
if (mRecord.threadRecords == null || mRecord.threadRecords.isEmpty()) { if (mTaskRecord.threadRecords == null || mTaskRecord.threadRecords.isEmpty()) {
initRecord(false); initRecord(false);
} }
@ -94,10 +94,12 @@ public class RecordHandler {
} else if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE) { } else if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE) {
ALog.i(TAG, "直播下载不处理历史记录"); ALog.i(TAG, "直播下载不处理历史记录");
} else { } else {
if (mRecord.isBlock) { if (mTaskRecord.isBlock) {
handleBlockRecord(); handleBlockRecord();
} else if (!mTaskWrapper.isSupportBP()) { } else if (!mTaskWrapper.isSupportBP()) {
handleNoSupportBPRecord(); handleNoSupportBPRecord();
} else if (!mTaskRecord.isBlock && mTaskRecord.threadNum > 1) {
handleNoBlockMultiThreadRecord();
} else { } else {
handleSingleThreadRecord(); handleSingleThreadRecord();
} }
@ -105,7 +107,7 @@ public class RecordHandler {
} }
} }
saveRecord(); saveRecord();
return mRecord; return mTaskRecord;
} }
/** /**
@ -119,7 +121,7 @@ public class RecordHandler {
String cacheDir = wrapper.asM3U8().getCacheDir(); String cacheDir = wrapper.asM3U8().getCacheDir();
long currentProgress = 0; long currentProgress = 0;
int completeNum = 0; int completeNum = 0;
for (ThreadRecord record : mRecord.threadRecords) { for (ThreadRecord record : mTaskRecord.threadRecords) {
File temp = new File(BaseM3U8Loader.getTsFilePath(cacheDir, record.threadId)); File temp = new File(BaseM3U8Loader.getTsFilePath(cacheDir, record.threadId));
if (!record.isComplete) { if (!record.isComplete) {
if (temp.exists()) { if (temp.exists()) {
@ -140,32 +142,45 @@ public class RecordHandler {
} }
wrapper.asM3U8().setCompleteNum(completeNum); wrapper.asM3U8().setCompleteNum(completeNum);
wrapper.getEntity().setCurrentProgress(currentProgress); wrapper.getEntity().setCurrentProgress(currentProgress);
mTaskRecord.bandWidth = wrapper.asM3U8().getBandWidth();
} }
/** /**
* 处理不支持断点的记录 * 处理不支持断点的记录
*/ */
private void handleNoSupportBPRecord() { private void handleNoSupportBPRecord() {
ThreadRecord tr = mRecord.threadRecords.get(0); ThreadRecord tr = mTaskRecord.threadRecords.get(0);
tr.startLocation = 0; tr.startLocation = 0;
tr.endLocation = mEntity.getFileSize(); tr.endLocation = mEntity.getFileSize();
tr.key = mRecord.filePath; tr.key = mTaskRecord.filePath;
tr.blockLen = tr.endLocation; tr.blockLen = tr.endLocation;
tr.isComplete = false; tr.isComplete = false;
} }
/**
* 处理为不分块的多线程任务
*/
private void handleNoBlockMultiThreadRecord() {
File file = new File(mTaskRecord.filePath);
if (!file.exists()) {
ALog.w(TAG, String.format("文件【%s】不存在,重新分配线程区间", mTaskRecord.filePath));
DbEntity.deleteData(ThreadRecord.class, "key=?", mTaskRecord.filePath);
initRecord(false);
}
}
/** /**
* 处理单线程的任务的记录 * 处理单线程的任务的记录
*/ */
private void handleSingleThreadRecord() { private void handleSingleThreadRecord() {
File file = new File(mRecord.filePath); File file = new File(mTaskRecord.filePath);
ThreadRecord tr = mRecord.threadRecords.get(0); ThreadRecord tr = mTaskRecord.threadRecords.get(0);
if (!file.exists()) { if (!file.exists()) {
ALog.w(TAG, String.format("文件【%s】不存在,任务将重新开始", file.getPath())); ALog.w(TAG, String.format("文件【%s】不存在,任务将重新开始", file.getPath()));
tr.startLocation = 0; tr.startLocation = 0;
tr.isComplete = false; tr.isComplete = false;
tr.endLocation = mEntity.getFileSize(); tr.endLocation = mEntity.getFileSize();
} else if (mRecord.isOpenDynamicFile) { } else if (mTaskRecord.isOpenDynamicFile) {
if (file.length() > mEntity.getFileSize()) { if (file.length() > mEntity.getFileSize()) {
ALog.i(TAG, String.format("文件【%s】错误,任务重新开始", file.getPath())); ALog.i(TAG, String.format("文件【%s】错误,任务重新开始", file.getPath()));
file.delete(); file.delete();
@ -190,11 +205,11 @@ public class RecordHandler {
*/ */
private void handleBlockRecord() { private void handleBlockRecord() {
// 默认线程分块长度 // 默认线程分块长度
long normalRectLen = mEntity.getFileSize() / mRecord.threadRecords.size(); long normalRectLen = mEntity.getFileSize() / mTaskRecord.threadRecords.size();
for (ThreadRecord tr : mRecord.threadRecords) { for (ThreadRecord tr : mTaskRecord.threadRecords) {
long threadRect = tr.blockLen; long threadRect = tr.blockLen;
File temp = new File(String.format(SUB_PATH, mRecord.filePath, tr.threadId)); File temp = new File(String.format(SUB_PATH, mTaskRecord.filePath, tr.threadId));
if (!temp.exists()) { if (!temp.exists()) {
ALog.i(TAG, String.format("分块文件【%s】不存在,该分块将重新开始", temp.getPath())); ALog.i(TAG, String.format("分块文件【%s】不存在,该分块将重新开始", temp.getPath()));
tr.isComplete = false; tr.isComplete = false;
@ -269,13 +284,13 @@ public class RecordHandler {
return; return;
} }
mTaskWrapper.setNewTask(false); mTaskWrapper.setNewTask(false);
mRecord = createTaskRecord(threadNum); mTaskRecord = createTaskRecord(threadNum);
mRecord.isOpenDynamicFile = false; mTaskRecord.isOpenDynamicFile = false;
mRecord.isBlock = false; mTaskRecord.isBlock = false;
File tempFile = new File(getFilePath()); File tempFile = new File(getFilePath());
for (int i = 0; i < threadNum; i++) { for (int i = 0; i < threadNum; i++) {
ThreadRecord tRecord = new ThreadRecord(); ThreadRecord tRecord = new ThreadRecord();
tRecord.key = mRecord.filePath; tRecord.key = mTaskRecord.filePath;
Object state = pro.getProperty(tempFile.getName() + STATE + i); Object state = pro.getProperty(tempFile.getName() + STATE + i);
Object record = pro.getProperty(tempFile.getName() + RECORD + i); Object record = pro.getProperty(tempFile.getName() + RECORD + i);
if (state != null && Integer.parseInt(String.valueOf(state)) == 1) { if (state != null && Integer.parseInt(String.valueOf(state)) == 1) {
@ -288,7 +303,7 @@ public class RecordHandler {
} else { } else {
tRecord.startLocation = 0; tRecord.startLocation = 0;
} }
mRecord.threadRecords.add(tRecord); mTaskRecord.threadRecords.add(tRecord);
} }
mConfigFile.delete(); mConfigFile.delete();
} }
@ -301,20 +316,20 @@ public class RecordHandler {
*/ */
private void initRecord(boolean newRecord) { private void initRecord(boolean newRecord) {
if (newRecord) { if (newRecord) {
mRecord = createTaskRecord(getNewTaskThreadNum()); mTaskRecord = createTaskRecord(getNewTaskThreadNum());
} }
mTaskWrapper.setNewTask(true); mTaskWrapper.setNewTask(true);
int requestType = mTaskWrapper.getRequestType(); int requestType = mTaskWrapper.getRequestType();
if (requestType == ITaskWrapper.M3U8_LIVE) { if (requestType == ITaskWrapper.M3U8_LIVE) {
return; return;
} }
long blockSize = mEntity.getFileSize() / mRecord.threadNum; long blockSize = mEntity.getFileSize() / mTaskRecord.threadNum;
// 处理线程区间记录 // 处理线程区间记录
for (int i = 0; i < mRecord.threadNum; i++) { for (int i = 0; i < mTaskRecord.threadNum; i++) {
long startL = i * blockSize, endL = (i + 1) * blockSize; long startL = i * blockSize, endL = (i + 1) * blockSize;
ThreadRecord tr; ThreadRecord tr;
tr = new ThreadRecord(); tr = new ThreadRecord();
tr.key = mRecord.filePath; tr.key = mTaskRecord.filePath;
tr.threadId = i; tr.threadId = i;
tr.startLocation = startL; tr.startLocation = startL;
tr.isComplete = false; tr.isComplete = false;
@ -325,13 +340,13 @@ public class RecordHandler {
} else { } else {
tr.threadType = TaskRecord.TYPE_HTTP_FTP; tr.threadType = TaskRecord.TYPE_HTTP_FTP;
//最后一个线程的结束位置即为文件的总长度 //最后一个线程的结束位置即为文件的总长度
if (i == (mRecord.threadNum - 1)) { if (i == (mTaskRecord.threadNum - 1)) {
endL = mEntity.getFileSize(); endL = mEntity.getFileSize();
} }
tr.endLocation = endL; tr.endLocation = endL;
tr.blockLen = RecordUtil.getBlockLen(mEntity.getFileSize(), i, mRecord.threadNum); tr.blockLen = RecordUtil.getBlockLen(mEntity.getFileSize(), i, mTaskRecord.threadNum);
} }
mRecord.threadRecords.add(tr); mTaskRecord.threadRecords.add(tr);
} }
} }
@ -350,9 +365,11 @@ public class RecordHandler {
if (requestType == ITaskWrapper.M3U8_VOD) { if (requestType == ITaskWrapper.M3U8_VOD) {
record.taskType = TaskRecord.TYPE_M3U8_VOD; record.taskType = TaskRecord.TYPE_M3U8_VOD;
record.isOpenDynamicFile = true; record.isOpenDynamicFile = true;
record.bandWidth = ((DTaskWrapper)mTaskWrapper).asM3U8().getBandWidth();
} else if (requestType == ITaskWrapper.M3U8_LIVE) { } else if (requestType == ITaskWrapper.M3U8_LIVE) {
record.taskType = TaskRecord.TYPE_M3U8_LIVE; record.taskType = TaskRecord.TYPE_M3U8_LIVE;
record.isOpenDynamicFile = true; record.isOpenDynamicFile = true;
record.bandWidth = ((DTaskWrapper)mTaskWrapper).asM3U8().getBandWidth();
} else { } else {
if (getRecordType() == TYPE_DOWNLOAD) { if (getRecordType() == TYPE_DOWNLOAD) {
record.isBlock = threadNum > 1 && Configuration.getInstance().downloadCfg.isUseBlock(); record.isBlock = threadNum > 1 && Configuration.getInstance().downloadCfg.isUseBlock();
@ -377,12 +394,12 @@ public class RecordHandler {
* 保存任务记录 * 保存任务记录
*/ */
private void saveRecord() { private void saveRecord() {
mRecord.threadNum = mRecord.threadRecords.size(); mTaskRecord.threadNum = mTaskRecord.threadRecords.size();
mRecord.save(); mTaskRecord.save();
if (mRecord.threadRecords != null && !mRecord.threadRecords.isEmpty()) { if (mTaskRecord.threadRecords != null && !mTaskRecord.threadRecords.isEmpty()) {
DbEntity.saveAll(mRecord.threadRecords); DbEntity.saveAll(mTaskRecord.threadRecords);
} }
ALog.d(TAG, String.format("保存记录,线程记录数:%s", mRecord.threadRecords.size())); ALog.d(TAG, String.format("保存记录,线程记录数:%s", mTaskRecord.threadRecords.size()));
} }
/** /**

@ -89,4 +89,9 @@ public class TaskRecord extends DbEntity {
* {@link #TYPE_HTTP_FTP}{@link #TYPE_M3U8_VOD} * {@link #TYPE_HTTP_FTP}{@link #TYPE_M3U8_VOD}
*/ */
public int taskType = 0; public int taskType = 0;
/**
* m3u8文件码率
*/
public long bandWidth = 0;
} }

@ -15,9 +15,7 @@
*/ */
package com.arialyy.aria.core.common; package com.arialyy.aria.core.common;
import com.arialyy.aria.orm.ActionPolicy;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.annotation.Foreign;
/** /**
* Created by laoyuyu on 2018/5/8. * Created by laoyuyu on 2018/5/8.
@ -25,7 +23,9 @@ import com.arialyy.aria.orm.annotation.Foreign;
*/ */
public class ThreadRecord extends DbEntity { public class ThreadRecord extends DbEntity {
@Foreign(parent = TaskRecord.class, column = "filePath", onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE) /**
* 任务的文件路径不是当前线程记录的的分块文件路径
*/
public String key; public String key;
/** /**

@ -63,8 +63,8 @@ public class FtpDelegate<TARGET extends AbsTarget> implements IFtpTarget<TARGET>
return mTarget; return mTarget;
} }
@Override public TARGET setProxy(Proxy proxy) { //@Override public TARGET setProxy(Proxy proxy) {
mTarget.getTaskWrapper().asFtp().setProxy(proxy); // mTarget.getTaskWrapper().asFtp().setProxy(proxy);
return mTarget; // return mTarget;
} //}
} }

@ -23,16 +23,23 @@ import java.io.Serializable;
*/ */
public class DownloadConfig extends BaseTaskConfig implements Serializable { public class DownloadConfig extends BaseTaskConfig implements Serializable {
/** /**
* 下载线程数下载线程数不能小于1 注意 1线程下载数改变后新的下载任务才会生效 2如果任务大小小于1m该设置不会生效 * 下载线程数下载线程数不能小于1
* 3从3.4.1开始如果线程数为1文件初始化时将不再预占用对应长度的空间下载多少byte则占多大的空间 对于采用多线程的任务或旧任务依然采用原来的文件空间占用方式 * 注意
* 1线程下载数改变后新的下载任务才会生效
* 2如果任务大小小于1m该设置不会生效
* 3从3.4.1开始如果线程数为1文件初始化时将不再预占用对应长度的空间下载多少byte则占多大的空间
* 对于采用多线程的任务或旧任务依然采用原来的文件空间占用方式
*/ */
int threadNum = 3; int threadNum = 3;
/** /**
* 多线程下载是否使用块下载模式{@code true}使用{@code false}不使用 注意 1使用分块模式在读写性能底下的手机上合并文件需要的时间会更加长 * 多线程下载是否使用块下载模式{@code true}使用{@code false}不使用
* 2优点是使用多线程的块下载初始化时文件初始化时将不会预占用对应长度的空间 3只对新的多线程下载任务有效 4只对多线程的任务有效 * 注意
* 1使用分块模式在读写性能底下的手机上合并文件需要的时间会更加长
* 2优点是使用多线程的块下载初始化时文件初始化时将不会预占用对应长度的空间
* 3只对新的多线程下载任务有效 4只对多线程的任务有效
*/ */
boolean useBlock = false; boolean useBlock = true;
public boolean isUseBlock() { public boolean isUseBlock() {
return useBlock; return useBlock;

@ -76,21 +76,21 @@ public class XMLReader extends DefaultHandler {
ALog.w(TAG, "任务队列数不能小于 1"); ALog.w(TAG, "任务队列数不能小于 1");
maxTaskNum = 2; maxTaskNum = 2;
} }
setField("maxTaskNum", maxTaskNum, getAllTaskType()); setField("maxTaskNum", maxTaskNum, mType);
break; break;
case "reTryNum": //任务重试次数 case "reTryNum": //任务重试次数
setField("reTryNum", checkInt(value) ? Integer.parseInt(value) : 0, getAllTaskType()); setField("reTryNum", checkInt(value) ? Integer.parseInt(value) : 0, mType);
break; break;
case "connectTimeOut": // 连接超时时间 case "connectTimeOut": // 连接超时时间
setField("connectTimeOut", checkInt(value) ? Integer.parseInt(value) : 5 * 1000, setField("connectTimeOut", checkInt(value) ? Integer.parseInt(value) : 5 * 1000,
getAllTaskType()); mType);
break; break;
case "iOTimeOut": //io流超时时间 case "iOTimeOut": //io流超时时间
int iOTimeOut = checkInt(value) ? Integer.parseInt(value) : 10 * 1000; int iOTimeOut = checkInt(value) ? Integer.parseInt(value) : 10 * 1000;
if (iOTimeOut < 10 * 1000) { if (iOTimeOut < 10 * 1000) {
iOTimeOut = 10 * 1000; iOTimeOut = 10 * 1000;
} }
setField("iOTimeOut", iOTimeOut, getAllTaskType()); setField("iOTimeOut", iOTimeOut, mType);
break; break;
case "reTryInterval": //失败重试间隔 case "reTryInterval": //失败重试间隔
int reTryInterval = checkInt(value) ? Integer.parseInt(value) : 2 * 1000; int reTryInterval = checkInt(value) ? Integer.parseInt(value) : 2 * 1000;
@ -98,7 +98,7 @@ public class XMLReader extends DefaultHandler {
if (reTryInterval < 2 * 1000) { if (reTryInterval < 2 * 1000) {
reTryInterval = 2 * 1000; reTryInterval = 2 * 1000;
} }
setField("reTryInterval", reTryInterval, getAllTaskType()); setField("reTryInterval", reTryInterval, mType);
break; break;
case "buffSize": //缓冲大小 case "buffSize": //缓冲大小
int buffSize = checkInt(value) ? Integer.parseInt(value) : 8192; int buffSize = checkInt(value) ? Integer.parseInt(value) : 8192;
@ -107,21 +107,21 @@ public class XMLReader extends DefaultHandler {
buffSize = 2048; buffSize = 2048;
} }
setField("buffSize", buffSize, getAllTaskType()); setField("buffSize", buffSize, mType);
break; break;
case "ca": // ca证书 case "ca": // ca证书
String caName = attributes.getValue("name"); String caName = attributes.getValue("name");
String caPath = attributes.getValue("path"); String caPath = attributes.getValue("path");
setField("caName", caName, getAllTaskType()); setField("caName", caName, mType);
setField("caPath", caPath, getAllTaskType()); setField("caPath", caPath, mType);
break; break;
case "convertSpeed": // 是否转换速度 case "convertSpeed": // 是否转换速度
setField("isConvertSpeed", !checkBoolean(value) || Boolean.parseBoolean(value), setField("isConvertSpeed", !checkBoolean(value) || Boolean.parseBoolean(value),
getAllTaskType()); mType);
break; break;
case "maxSpeed": // 最大速度 case "maxSpeed": // 最大速度
int maxSpeed = checkInt(value) ? Integer.parseInt(value) : 0; int maxSpeed = checkInt(value) ? Integer.parseInt(value) : 0;
setField("maxSpeed", maxSpeed, getAllTaskType()); setField("maxSpeed", maxSpeed, mType);
break; break;
case "queueMod": // 队列类型 case "queueMod": // 队列类型
String mod = "now"; String mod = "now";
@ -129,11 +129,11 @@ public class XMLReader extends DefaultHandler {
"wait"))) { "wait"))) {
mod = value; mod = value;
} }
setField("queueMod", mod, getAllTaskType()); setField("queueMod", mod, mType);
break; break;
case "updateInterval": // 进度更新时间 case "updateInterval": // 进度更新时间
setField("updateInterval", checkLong(value) ? Long.parseLong(value) : 1000, setField("updateInterval", checkLong(value) ? Long.parseLong(value) : 1000,
getAllTaskType()); mType);
break; break;
case "useBlock": // 是否使用分块任务 case "useBlock": // 是否使用分块任务
@ -184,16 +184,7 @@ public class XMLReader extends DefaultHandler {
} }
} }
/** private void setField(String key, Object value, int type) {
* 获取任务类型集合类型有 {@link ConfigType#DOWNLOAD}{@link ConfigType#UPLOAD}{@link ConfigType#D_GROUP}
*/
private int[] getAllTaskType() {
return new int[] {ConfigType.DOWNLOAD, ConfigType.UPLOAD,
ConfigType.D_GROUP};
}
private void setField(String key, Object value, int... types) {
for (int type : types) {
if (type == ConfigType.DOWNLOAD) { if (type == ConfigType.DOWNLOAD) {
setField(DownloadConfig.class, mDownloadConfig, key, value); setField(DownloadConfig.class, mDownloadConfig, key, value);
} else if (type == ConfigType.UPLOAD) { } else if (type == ConfigType.UPLOAD) {
@ -204,7 +195,6 @@ public class XMLReader extends DefaultHandler {
setField(DGroupConfig.class, mDGroupConfig, key, value); setField(DGroupConfig.class, mDGroupConfig, key, value);
} }
} }
}
private void setField(Class clazz, Object target, String key, Object value) { private void setField(Class clazz, Object target, String key, Object value) {
Field field = CommonUtil.getField(clazz, key); Field field = CommonUtil.getField(clazz, key);

@ -19,12 +19,14 @@ import android.os.Handler;
import com.arialyy.aria.core.common.BaseListener; import com.arialyy.aria.core.common.BaseListener;
import com.arialyy.aria.core.common.RecordHandler; import com.arialyy.aria.core.common.RecordHandler;
import com.arialyy.aria.core.inf.AbsTaskWrapper;
import com.arialyy.aria.core.inf.IDownloadListener; import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.TaskSchedulerType; import com.arialyy.aria.core.inf.TaskSchedulerType;
import com.arialyy.aria.core.scheduler.ISchedulers; import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.RecordUtil; import com.arialyy.aria.util.RecordUtil;
import java.io.File;
/** /**
* 下载监听类 * 下载监听类

@ -21,8 +21,8 @@ import android.os.Looper;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.download.downloader.SimpleDownloadUtil; import com.arialyy.aria.core.download.downloader.SimpleDownloadUtil;
import com.arialyy.aria.core.download.m3u8.M3U8LiveDownloadUtil; import com.arialyy.aria.core.download.m3u8.M3U8LiveUtil;
import com.arialyy.aria.core.download.m3u8.M3U8VodDownloadUtil; import com.arialyy.aria.core.download.m3u8.M3U8VodUtil;
import com.arialyy.aria.core.inf.AbsNormalTask; import com.arialyy.aria.core.inf.AbsNormalTask;
import com.arialyy.aria.core.inf.IDownloadListener; import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.core.inf.ITaskWrapper; import com.arialyy.aria.core.inf.ITaskWrapper;
@ -90,9 +90,9 @@ public class DownloadTask extends AbsNormalTask<DTaskWrapper> {
@Override protected synchronized IUtil createUtil() { @Override protected synchronized IUtil createUtil() {
if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_VOD) { if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_VOD) {
return new M3U8VodDownloadUtil(mTaskWrapper, (IDownloadListener) mListener); return new M3U8VodUtil(mTaskWrapper, (IDownloadListener) mListener);
} else if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE) { } else if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_LIVE) {
return new M3U8LiveDownloadUtil(mTaskWrapper, (IDownloadListener) mListener); return new M3U8LiveUtil(mTaskWrapper, (IDownloadListener) mListener);
} else { } else {
return new SimpleDownloadUtil(mTaskWrapper, (IDownloadListener) mListener); return new SimpleDownloadUtil(mTaskWrapper, (IDownloadListener) mListener);
} }

@ -107,8 +107,4 @@ public class FtpDirDownloadTarget extends AbsDGTarget<FtpDirDownloadTarget>
@Override public FtpDirDownloadTarget login(String userName, String password, String account) { @Override public FtpDirDownloadTarget login(String userName, String password, String account) {
return mFtpDelegate.login(userName, password, account); return mFtpDelegate.login(userName, password, account);
} }
@Override public FtpDirDownloadTarget setProxy(Proxy proxy) {
return mFtpDelegate.setProxy(proxy);
}
} }

@ -144,11 +144,6 @@ public class FtpDownloadTarget extends AbsDTarget<FtpDownloadTarget>
return mFtpDelegate.login(userName, password, account); return mFtpDelegate.login(userName, password, account);
} }
@CheckResult
@Override public FtpDownloadTarget setProxy(Proxy proxy) {
return mFtpDelegate.setProxy(proxy);
}
@Override public FtpDownloadTarget updateUrl(String newUrl) { @Override public FtpDownloadTarget updateUrl(String newUrl) {
return mConfigHandler.updateUrl(newUrl); return mConfigHandler.updateUrl(newUrl);
} }

@ -37,9 +37,9 @@ class FtpFileInfoThread extends AbsFtpInfoThread<DownloadEntity, DTaskWrapper> {
@Override protected void handleFile(String remotePath, FTPFile ftpFile) { @Override protected void handleFile(String remotePath, FTPFile ftpFile) {
super.handleFile(remotePath, ftpFile); super.handleFile(remotePath, ftpFile);
if (!CommonUtil.checkSDMemorySpace(mEntity.getDownloadPath(), ftpFile.getSize())) { if (!CommonUtil.checkSDMemorySpace(mEntity.getFilePath(), ftpFile.getSize())) {
mCallback.onFail(mEntity, new AriaIOException(TAG, mCallback.onFail(mEntity, new AriaIOException(TAG,
String.format("获取ftp文件信息失败,内存空间不足, filePath: %s", mEntity.getDownloadPath())), String.format("获取ftp文件信息失败,内存空间不足, filePath: %s", mEntity.getFilePath())),
false); false);
} }
} }

@ -26,6 +26,7 @@ public abstract class BaseM3U8Loader extends AbsFileer<DownloadEntity, DTaskWrap
BaseM3U8Loader(IEventListener listener, DTaskWrapper wrapper) { BaseM3U8Loader(IEventListener listener, DTaskWrapper wrapper) {
super(listener, wrapper); super(listener, wrapper);
mTempFile = new File(wrapper.getEntity().getFilePath());
} }
@Override protected long delayTimer() { @Override protected long delayTimer() {

@ -26,7 +26,7 @@ public interface ITsMergeHandler {
/** /**
* 合并ts文件 * 合并ts文件
* *
* @param keyInfo ts文件加密信息如果ts文件不是加密的该字段为空 * @param keyInfo 信息如果ts文件不是加密的该字段为空
* @param tsPath ts文件列表 * @param tsPath ts文件列表
* @return {@code true} 合并成功 * @return {@code true} 合并成功
*/ */

@ -15,10 +15,13 @@
*/ */
package com.arialyy.aria.core.download.m3u8; package com.arialyy.aria.core.download.m3u8;
import android.os.Parcel;
import android.os.Parcelable;
/** /**
* m3u8加密密钥信息 * m3u8加密密钥信息
*/ */
public class M3U8KeyInfo { public class M3U8KeyInfo implements Parcelable {
/** /**
* 加密key保存地址 * 加密key保存地址
@ -39,4 +42,36 @@ public class M3U8KeyInfo {
* key的iv值 * key的iv值
*/ */
public String iv; public String iv;
@Override public int describeContents() {
return 0;
}
@Override public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.keyPath);
dest.writeString(this.keyUrl);
dest.writeString(this.method);
dest.writeString(this.iv);
}
public M3U8KeyInfo() {
}
protected M3U8KeyInfo(Parcel in) {
this.keyPath = in.readString();
this.keyUrl = in.readString();
this.method = in.readString();
this.iv = in.readString();
}
public static final Parcelable.Creator<M3U8KeyInfo> CREATOR =
new Parcelable.Creator<M3U8KeyInfo>() {
@Override public M3U8KeyInfo createFromParcel(Parcel source) {
return new M3U8KeyInfo(source);
}
@Override public M3U8KeyInfo[] newArray(int size) {
return new M3U8KeyInfo[size];
}
};
} }

@ -41,7 +41,7 @@ import java.util.concurrent.TimeUnit;
* 4对于直播来说是没有停止的停止就代表完成 * 4对于直播来说是没有停止的停止就代表完成
* 5不处理直播切片下载失败的状态 * 5不处理直播切片下载失败的状态
*/ */
public class M3U8LiveDownloadUtil implements IUtil { public class M3U8LiveUtil implements IUtil {
private final String TAG = "M3U8LiveDownloadUtil"; private final String TAG = "M3U8LiveDownloadUtil";
private DTaskWrapper mWrapper; private DTaskWrapper mWrapper;
private IDownloadListener mListener; private IDownloadListener mListener;
@ -52,7 +52,7 @@ public class M3U8LiveDownloadUtil implements IUtil {
private ExecutorService mInfoPool = Executors.newCachedThreadPool(); private ExecutorService mInfoPool = Executors.newCachedThreadPool();
private List<String> mPeerUrls = new ArrayList<>(); private List<String> mPeerUrls = new ArrayList<>();
public M3U8LiveDownloadUtil(DTaskWrapper wrapper, IDownloadListener listener) { public M3U8LiveUtil(DTaskWrapper wrapper, IDownloadListener listener) {
mWrapper = wrapper; mWrapper = wrapper;
mListener = listener; mListener = listener;
mLoader = new M3U8LiveLoader(mListener, mWrapper); mLoader = new M3U8LiveLoader(mListener, mWrapper);

@ -104,16 +104,6 @@ public class M3U8VodLoader extends BaseM3U8Loader {
} }
@Override protected void onStop() {
super.onStop();
//notifyLock();
}
@Override protected void onCancel() {
super.onCancel();
//notifyLock();
}
private void notifyLock() { private void notifyLock() {
try { try {
LOCK.lock(); LOCK.lock();
@ -204,7 +194,7 @@ public class M3U8VodLoader extends BaseM3U8Loader {
ThreadTaskManager.getInstance().removeSingleTaskThread(mTaskWrapper.getKey(), ThreadTaskManager.getInstance().removeSingleTaskThread(mTaskWrapper.getKey(),
(AbsThreadTask) msg.obj); (AbsThreadTask) msg.obj);
if (isStop()) { if (isStop()) {
ALog.d(TAG, "任务停止"); ALog.d(TAG, String.format("vod任务【%s】停止", mTempFile.getName()));
mListener.onStop(mProgress); mListener.onStop(mProgress);
quitLooper(); quitLooper();
} }
@ -214,7 +204,7 @@ public class M3U8VodLoader extends BaseM3U8Loader {
ThreadTaskManager.getInstance().removeSingleTaskThread(mTaskWrapper.getKey(), ThreadTaskManager.getInstance().removeSingleTaskThread(mTaskWrapper.getKey(),
(AbsThreadTask) msg.obj); (AbsThreadTask) msg.obj);
if (isCancel()) { if (isCancel()) {
ALog.d(TAG, "任务取消"); ALog.d(TAG, String.format("vod任务【%s】取消", mTempFile.getName()));
mListener.onCancel(); mListener.onCancel();
quitLooper(); quitLooper();
} }
@ -222,6 +212,7 @@ public class M3U8VodLoader extends BaseM3U8Loader {
case STATE_FAIL: case STATE_FAIL:
mFailNum++; mFailNum++;
if (isFail()) { if (isFail()) {
ALog.d(TAG, String.format("vod任务【%s】失败", mTempFile.getName()));
Bundle b = msg.getData(); Bundle b = msg.getData();
mListener.onFail(b.getBoolean(KEY_RETRY, true), mListener.onFail(b.getBoolean(KEY_RETRY, true),
(BaseException) b.getSerializable(KEY_ERROR_INFO)); (BaseException) b.getSerializable(KEY_ERROR_INFO));
@ -235,7 +226,6 @@ public class M3U8VodLoader extends BaseM3U8Loader {
handlerPercent(); handlerPercent();
notifyLock(); notifyLock();
if (isComplete()) { if (isComplete()) {
ALog.d(TAG, "isComplete, completeNum = " + mCompleteNum);
if (mTaskWrapper.asM3U8().isMergeFile()) { if (mTaskWrapper.asM3U8().isMergeFile()) {
if (mergeFile()) { if (mergeFile()) {
mListener.onComplete(); mListener.onComplete();
@ -274,7 +264,7 @@ public class M3U8VodLoader extends BaseM3U8Loader {
@Override public boolean isFail() { @Override public boolean isFail() {
printInfo("isFail"); printInfo("isFail");
return mStartThreadNum == mStopNum + mFailNum + mCompleteNum + mCancelNum; return mFailNum == mFlagQueue.size();
} }
@Override public boolean isComplete() { @Override public boolean isComplete() {

@ -36,7 +36,7 @@ import java.util.List;
* 3完成所有分片下载后合并ts文件 * 3完成所有分片下载后合并ts文件
* 4删除该隐藏文件夹 * 4删除该隐藏文件夹
*/ */
public class M3U8VodDownloadUtil implements IUtil { public class M3U8VodUtil implements IUtil {
private final String TAG = "M3U8DownloadUtil"; private final String TAG = "M3U8DownloadUtil";
private DTaskWrapper mWrapper; private DTaskWrapper mWrapper;
@ -45,7 +45,7 @@ public class M3U8VodDownloadUtil implements IUtil {
private List<String> mUrls = new ArrayList<>(); private List<String> mUrls = new ArrayList<>();
private M3U8VodLoader mLoader; private M3U8VodLoader mLoader;
public M3U8VodDownloadUtil(DTaskWrapper wrapper, IDownloadListener listener) { public M3U8VodUtil(DTaskWrapper wrapper, IDownloadListener listener) {
mWrapper = wrapper; mWrapper = wrapper;
mListener = listener; mListener = listener;
mLoader = new M3U8VodLoader(mListener, mWrapper); mLoader = new M3U8VodLoader(mListener, mWrapper);

@ -78,7 +78,7 @@ public abstract class AbsTask<TASK_WRAPPER extends AbsTaskWrapper>
ALog.e(TAG, "key 为空"); ALog.e(TAG, "key 为空");
return; return;
} else if (obj == null) { } else if (obj == null) {
ALog.e(TAG, "扩展数据为空"); ALog.w(TAG, "扩展数据为空");
return; return;
} }
mExpand.put(key, obj); mExpand.put(key, obj);

@ -47,11 +47,11 @@ public interface IFtpTarget<TARGET extends ITargetHandler> {
@CheckResult @CheckResult
TARGET login(String userName, String password, String account); TARGET login(String userName, String password, String account);
/** ///**
* 设置代理 // * 设置代理
* // *
* @param proxy {@link Proxy} // * @param proxy {@link Proxy}
*/ // */
@CheckResult //@CheckResult
TARGET setProxy(Proxy proxy); //TARGET setProxy(Proxy proxy);
} }

@ -92,10 +92,6 @@ public class FtpUploadTarget extends AbsUploadTarget<FtpUploadTarget>
return mFtpDelegate.login(userName, password, account); return mFtpDelegate.login(userName, password, account);
} }
@Override public FtpUploadTarget setProxy(Proxy proxy) {
return mFtpDelegate.setProxy(proxy);
}
@Override protected boolean checkEntity() { @Override protected boolean checkEntity() {
return mConfigHandler.checkEntity(); return mConfigHandler.checkEntity();
} }

@ -57,7 +57,7 @@ class DBConfig {
mapping.put("DownloadGroupEntity", DownloadGroupEntity.class); mapping.put("DownloadGroupEntity", DownloadGroupEntity.class);
mapping.put("DownloadEntity", DownloadEntity.class); mapping.put("DownloadEntity", DownloadEntity.class);
mapping.put("UploadEntity", UploadEntity.class); mapping.put("UploadEntity", UploadEntity.class);
mapping.put("TaskRecord", TaskRecord.class);
mapping.put("ThreadRecord", ThreadRecord.class); mapping.put("ThreadRecord", ThreadRecord.class);
mapping.put("TaskRecord", TaskRecord.class);
} }
} }

@ -98,8 +98,8 @@ final class SqlHelper extends SQLiteOpenHelper {
handle314AriaUpdate(db); handle314AriaUpdate(db);
} else if (oldVersion < 45) { } else if (oldVersion < 45) {
handle360AriaUpdate(db); handle360AriaUpdate(db);
} else if (oldVersion < 46) { } else if (oldVersion < 48) {
db.execSQL("UPDATE ThreadRecord SET threadId=0 WHERE threadId=-1"); handle365Update(db);
} else { } else {
handleDbUpdate(db, null, null); handleDbUpdate(db, null, null);
} }
@ -227,12 +227,37 @@ final class SqlHelper extends SQLiteOpenHelper {
} }
db.setTransactionSuccessful(); db.setTransactionSuccessful();
} catch (Exception e) { } catch (Exception e) {
ALog.e(TAG, e); e.printStackTrace();
} finally { } finally {
db.endTransaction(); db.endTransaction();
} }
} }
/**
* 删除重复的repeat数据
*/
private void delRepeatThreadRecord(SQLiteDatabase db) {
String repeatSql =
"DELETE FROM ThreadRecord WHERE (key, threadId, endLocation) "
+ "IN (SELECT key, threadId, endLocation FROM ThreadRecord GROUP BY key, threadId, endLocation "
+ "HAVING COUNT(*) > 1) AND rowid "
+ "NOT IN (SELECT MIN(rowid) FROM ThreadRecord GROUP BY key, threadId, endLocation "
+ "HAVING COUNT(*)> 1)";
ALog.d(TAG, repeatSql);
db.execSQL(repeatSql);
}
/**
* 处理365版本以下的升级
*/
private void handle365Update(SQLiteDatabase db) {
db.execSQL("UPDATE ThreadRecord SET threadId=0 WHERE threadId=-1");
// 执行升级操作
handleDbUpdate(db, null, null);
delRepeatThreadRecord(db);
}
/** /**
* 处理3.6以下版本的数据库升级 * 处理3.6以下版本的数据库升级
*/ */
@ -255,7 +280,10 @@ final class SqlHelper extends SQLiteOpenHelper {
Map<String, String> dGroupNameModify = new HashMap<>(); Map<String, String> dGroupNameModify = new HashMap<>();
dGroupNameModify.put("dGroupName", "dGroupHash"); dGroupNameModify.put("dGroupName", "dGroupHash");
columnMap.put("TaskRecord", dGroupNameModify); columnMap.put("TaskRecord", dGroupNameModify);
// 执行升级操作
handleDbUpdate(db, columnMap, null); handleDbUpdate(db, columnMap, null);
delRepeatThreadRecord(db);
} }
/** /**

@ -20,9 +20,11 @@ package com.arialyy.aria.util;
import android.content.Context; import android.content.Context;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.Build;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.AriaManager;
/** /**
* 跟网络相关的工具类 * 跟网络相关的工具类
@ -52,12 +54,16 @@ public class NetUtils {
/** /**
* 判断网络是否连接 * 判断网络是否连接
*
* @return {@code true} 网络已连接{@code false}网络未连接 * @return {@code true} 网络已连接{@code false}网络未连接
*/ */
public static boolean isConnected(Context context) { public static boolean isConnected(Context context) {
if (!Aria.get(context).getAppConfig().isNetCheck()){ if (!Aria.get(context).getAppConfig().isNetCheck()) {
return true; return true;
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return AriaManager.getInstance(context).isConnectedNet();
}
ConnectivityManager cm = ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo(); NetworkInfo ni = cm.getActiveNetworkInfo();

@ -182,6 +182,9 @@ public class RecordUtil {
if (TextUtils.isEmpty(filePath)) { if (TextUtils.isEmpty(filePath)) {
throw new NullPointerException("删除记录失败,文件路径为空"); throw new NullPointerException("删除记录失败,文件路径为空");
} }
if (!filePath.startsWith("/")) {
throw new IllegalArgumentException(String.format("文件路径错误,filePath:%s", filePath));
}
if (type != RecordHandler.TYPE_DOWNLOAD && type != RecordHandler.TYPE_UPLOAD) { if (type != RecordHandler.TYPE_DOWNLOAD && type != RecordHandler.TYPE_UPLOAD) {
throw new IllegalArgumentException("任务记录类型错误"); throw new IllegalArgumentException("任务记录类型错误");
} }
@ -210,7 +213,8 @@ public class RecordUtil {
if (record.taskType == TaskRecord.TYPE_M3U8_VOD) { // 删除ts分片文件 if (record.taskType == TaskRecord.TYPE_M3U8_VOD) { // 删除ts分片文件
String cacheDir = null; String cacheDir = null;
if (!targetFile.isDirectory()) { if (!targetFile.isDirectory()) {
cacheDir = targetFile.getParent() + "/." + targetFile.getName(); cacheDir = String.format("%s/.%s_%s", targetFile.getParent(), targetFile.getName(),
record.bandWidth);
} }
removeTsCache(record, cacheDir); removeTsCache(record, cacheDir);
} else if (record.isBlock) { // 删除分块文件 } else if (record.isBlock) { // 删除分块文件
@ -235,6 +239,7 @@ public class RecordUtil {
} }
private static void removeRecord(String filePath) { private static void removeRecord(String filePath) {
ALog.i(TAG, "删除任务记录");
DbEntity.deleteData(ThreadRecord.class, "key=?", filePath); DbEntity.deleteData(ThreadRecord.class, "key=?", filePath);
DbEntity.deleteData(TaskRecord.class, "filePath=?", filePath); DbEntity.deleteData(TaskRecord.class, "filePath=?", filePath);
} }

@ -8,6 +8,9 @@
- 修复拦截器可能出现的空指针问题 - 修复拦截器可能出现的空指针问题
- 移除`DownloadGroupEntity`字段`groupHash`的主键约束,`DownloadEntity`字段`groupHash`的外键约束,`TaskRecord`字段`dGroupHash`的外键约束 - 移除`DownloadGroupEntity`字段`groupHash`的主键约束,`DownloadEntity`字段`groupHash`的外键约束,`TaskRecord`字段`dGroupHash`的外键约束
- 优化关联查询的性能 - 优化关联查询的性能
- 修复任务记录删除失败的问题
- 优化网络连接状态获取的逻辑
- 修复配置文件的某些配置失效的问题
+ v_3.6.4 (2019/5/16) + v_3.6.4 (2019/5/16)
- 优化任务接收器的代码结构 - 优化任务接收器的代码结构
- 修复`DbEntity.saveAll()`失败的问题 - 修复`DbEntity.saveAll()`失败的问题

@ -50,8 +50,8 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:${rootProject.ext.kotlin_version}" implementation "org.jetbrains.kotlin:kotlin-stdlib:${rootProject.ext.kotlin_version}"
api project(':Aria') api project(':Aria')
kapt project(':AriaCompiler') kapt project(':AriaCompiler')
// api 'com.arialyy.aria:aria-core:3.6.5_dev_4' // api 'com.arialyy.aria:aria-core:3.6.4'
// kapt 'com.arialyy.aria:aria-compiler:3.6.5_dev_4' // kapt 'com.arialyy.aria:aria-compiler:3.6.4'
// compile 'com.arialyy.aria:aria-core:3.3.14' // compile 'com.arialyy.aria:aria-core:3.3.14'
// annotationProcessor 'com.arialyy.aria:aria-compiler:3.3.14' // annotationProcessor 'com.arialyy.aria:aria-compiler:3.3.14'

@ -9,12 +9,12 @@
<!--设置Aria的日志级别,{@link ALog#LOG_LEVEL_VERBOSE}--> <!--设置Aria的日志级别,{@link ALog#LOG_LEVEL_VERBOSE}-->
<logLevel value="2"/> <logLevel value="2"/>
<!-- 是否检查网络 true: 检查网络,false: 不检查网络--> <!-- 是否检查网络 true: 检查网络,false: 不检查网络-->
<netCheck value="false"/> <netCheck value="true"/>
<!--除非无法使用注解,否则不建议使用广播来接受任务状态,true:使用广播接收任务状态,false:不适用广播接收状态 --> <!--除非无法使用注解,否则不建议使用广播来接受任务状态,true:使用广播接收任务状态,false:不适用广播接收状态 -->
<!-- http://aria.laoyuyu.me/aria_doc/api/use_broadcast.html --> <!-- http://aria.laoyuyu.me/aria_doc/api/use_broadcast.html -->
<useBroadcast value="true"/> <useBroadcast value="true"/>
<!--断网的时候是否重试,true:断网也重试;false:断网不重试,直接走失败的回调--> <!--断网的时候是否重试,true:断网也重试;false:断网不重试,直接走失败的回调-->
<notNetRetry value="true"/> <notNetRetry value="false"/>
</app> </app>

@ -34,9 +34,10 @@ public class HttpDownloadModule extends BaseViewModule {
private final String defUrl = private final String defUrl =
"http://hzdown.muzhiwan.com/2017/05/08/nl.noio.kingdom_59104935e56f0.apk"; "http://hzdown.muzhiwan.com/2017/05/08/nl.noio.kingdom_59104935e56f0.apk";
//"http://202.98.201.103:7000/vrs/TPK/ZTC440402001Z.tpk";
private final String defFilePath = private final String defFilePath =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath() Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()
+ "/test.apk"; + "/ZTC440402001Z.tpk";
private MutableLiveData<DownloadEntity> liveData = new MutableLiveData<>(); private MutableLiveData<DownloadEntity> liveData = new MutableLiveData<>();
private DownloadEntity singDownloadInfo; private DownloadEntity singDownloadInfo;

@ -26,6 +26,7 @@ import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.Toast; import android.widget.Toast;
@ -310,6 +311,10 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
//Aria.download(this).unRegister(); //Aria.download(this).unRegister();
} }
@Override public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
@Override protected void dataCallback(int result, Object data) { @Override protected void dataCallback(int result, Object data) {
super.dataCallback(result, data); super.dataCallback(result, data);
if (result == ModifyUrlDialog.MODIFY_URL_DIALOG_RESULT) { if (result == ModifyUrlDialog.MODIFY_URL_DIALOG_RESULT) {

@ -31,7 +31,9 @@ import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTarget; import com.arialyy.aria.core.download.DownloadTarget;
import com.arialyy.aria.core.download.DownloadTask; import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.download.m3u8.IBandWidthUrlConverter; import com.arialyy.aria.core.download.m3u8.IBandWidthUrlConverter;
import com.arialyy.aria.core.download.m3u8.ITsMergeHandler;
import com.arialyy.aria.core.download.m3u8.IVodTsUrlConverter; import com.arialyy.aria.core.download.m3u8.IVodTsUrlConverter;
import com.arialyy.aria.core.download.m3u8.M3U8KeyInfo;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
@ -201,6 +203,8 @@ public class M3U8VodDownloadActivity extends BaseActivity<ActivityM3u8VodBinding
Toast.LENGTH_SHORT) Toast.LENGTH_SHORT)
.show(); .show();
getBinding().setStateStr(getString(R.string.start)); getBinding().setStateStr(getString(R.string.start));
getBinding().setSpeed("");
Log.d(TAG, "fail");
} }
} }
@ -261,6 +265,11 @@ public class M3U8VodDownloadActivity extends BaseActivity<ActivityM3u8VodBinding
return newUrls; return newUrls;
} }
}) })
.setMergeHandler(new ITsMergeHandler() {
@Override public boolean merge(@Nullable M3U8KeyInfo keyInfo, List<String> tsPath) {
return false;
}
})
.start(); .start();
} }

@ -26,7 +26,7 @@ import com.arialyy.aria.core.upload.uploader.SimpleUploadUtil;
/** /**
* Created by lyy on 2017/2/23. 上传任务 * Created by lyy on 2017/2/23. 上传任务
*/ */
public class UploadTask extends AbsNormalTask<UploadEntity, UTaskWrapper> { public class UploadTask extends AbsNormalTask<UTaskWrapper> {
private UploadTask(UTaskWrapper taskWrapper, Handler outHandler) { private UploadTask(UTaskWrapper taskWrapper, Handler outHandler) {
mTaskWrapper = taskWrapper; mTaskWrapper = taskWrapper;

@ -43,7 +43,7 @@ task clean(type: Delete) {
ext { ext {
userOrg = 'arialyy' userOrg = 'arialyy'
groupId = 'com.arialyy.aria' groupId = 'com.arialyy.aria'
publishVersion = '3.6.5_dev_4' publishVersion = '3.6.5_beta_1'
// publishVersion = '1.0.4' //FTP插件 // publishVersion = '1.0.4' //FTP插件
repoName='maven' repoName='maven'
desc = 'android 下载框架' desc = 'android 下载框架'

Loading…
Cancel
Save