移除`DownloadGroupEntity`字段`groupHash`的主键约束,`DownloadEntity`字段`groupHash`的外键约束,`TaskRecord`字段`dGroupHash`的外键约束
优化关联查询的性能
v3.6.6
laoyuyu 6 years ago
parent b670e3e383
commit 8f8f8fa7d7
  1. 32
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
  2. 44
      Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java
  3. 2
      Aria/src/main/java/com/arialyy/aria/core/common/BaseListener.java
  4. 8
      Aria/src/main/java/com/arialyy/aria/core/common/NormalFileer.java
  5. 8
      Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java
  6. 1
      Aria/src/main/java/com/arialyy/aria/core/common/http/HttpDelegate.java
  7. 16
      Aria/src/main/java/com/arialyy/aria/core/download/AbsGroupConfigHandler.java
  8. 8
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java
  9. 2
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java
  10. 13
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java
  11. 15
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8LiveDelegate.java
  12. 13
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8LiveDownloadUtil.java
  13. 13
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8LiveLoader.java
  14. 13
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8TaskConfig.java
  15. 7
      Aria/src/main/java/com/arialyy/aria/core/download/m3u8/M3U8VodLoader.java
  16. 6
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java
  17. 4
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java
  18. 4
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTask.java
  19. 7
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
  20. 40
      Aria/src/main/java/com/arialyy/aria/core/manager/ThreadTaskManager.java
  21. 3
      Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java
  22. 222
      Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java
  23. 21
      Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
  24. 5
      DEV_LOG.md
  25. 2
      app/src/main/java/com/arialyy/simple/core/download/m3u8/M3U8VodModule.java
  26. 1
      app/src/main/java/com/arialyy/simple/core/download/multi_download/FileListAdapter.java
  27. 3
      app/src/main/java/com/arialyy/simple/core/download/multi_download/MultiTaskActivity.java

@ -15,9 +15,8 @@
*/ */
package com.arialyy.aria.core.common; package com.arialyy.aria.core.common;
import android.content.Context;
import android.os.Looper; import android.os.Looper;
import com.arialyy.aria.core.AriaManager; import android.util.SparseArray;
import com.arialyy.aria.core.inf.AbsNormalEntity; import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskWrapper; import com.arialyy.aria.core.inf.AbsTaskWrapper;
import com.arialyy.aria.core.inf.IEventListener; import com.arialyy.aria.core.inf.IEventListener;
@ -25,8 +24,6 @@ import com.arialyy.aria.core.manager.ThreadTaskManager;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.io.File; import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -40,10 +37,9 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
protected IEventListener mListener; protected IEventListener mListener;
protected TASK_WRAPPER mTaskWrapper; protected TASK_WRAPPER mTaskWrapper;
protected ENTITY mEntity; protected ENTITY mEntity;
protected Context mContext; protected File mTempFile;
protected File mTempFile; //文件
private Map<Integer, AbsThreadTask> mTask = new HashMap<>(); private SparseArray<AbsThreadTask> mTask = new SparseArray<>();
private ScheduledThreadPoolExecutor mTimer; private ScheduledThreadPoolExecutor mTimer;
/** /**
@ -58,7 +54,6 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
mListener = listener; mListener = listener;
mTaskWrapper = wrapper; mTaskWrapper = wrapper;
mEntity = mTaskWrapper.getEntity(); mEntity = mTaskWrapper.getEntity();
mContext = AriaManager.APP;
TAG = CommonUtil.getClassName(getClass()); TAG = CommonUtil.getClassName(getClass());
} }
@ -82,7 +77,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
return mEntity; return mEntity;
} }
public Map<Integer, AbsThreadTask> getTaskList() { public SparseArray<AbsThreadTask> getTaskList() {
return mTask; return mTask;
} }
@ -92,10 +87,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
private void resetState() { private void resetState() {
closeTimer(); closeTimer();
if (mTask != null && mTask.size() != 0) { if (mTask != null && mTask.size() != 0) {
for (AbsThreadTask task : mTask.values()) { for (int i = 0; i < mTask.size(); i++) {
if (task != null) { mTask.valueAt(i).breakTask();
task.breakTask();
}
} }
mTask.clear(); mTask.clear();
} }
@ -152,10 +145,9 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|| mStateManager.isStop() || mStateManager.isStop()
|| mStateManager.isCancel() || mStateManager.isCancel()
|| mStateManager.isFail() || mStateManager.isFail()
|| !isRunning()) { || !isRunning()
if (mStateManager.isComplete() || mStateManager.isFail()) { || isBreak()) {
ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey()); ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey());
}
closeTimer(); closeTimer();
} else if (mStateManager.getCurrentProgress() >= 0) { } else if (mStateManager.getCurrentProgress() >= 0) {
mListener.onProgress(mStateManager.getCurrentProgress()); mListener.onProgress(mStateManager.getCurrentProgress());
@ -209,7 +201,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
closeTimer(); closeTimer();
isCancel = true; isCancel = true;
onCancel(); onCancel();
for (AbsThreadTask task : mTask.values()) { for (int i = 0; i < mTask.size(); i++) {
AbsThreadTask task = mTask.valueAt(i);
if (task != null && !task.isThreadComplete()) { if (task != null && !task.isThreadComplete()) {
task.cancel(); task.cancel();
} }
@ -229,7 +222,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
isStop = true; isStop = true;
onStop(); onStop();
if (mStateManager.isComplete()) return; if (mStateManager.isComplete()) return;
for (AbsThreadTask task : mTask.values()) { for (int i = 0; i < mTask.size(); i++) {
AbsThreadTask task = mTask.valueAt(i);
if (task != null && !task.isThreadComplete()) { if (task != null && !task.isThreadComplete()) {
task.stop(); task.stop();
} }

@ -33,6 +33,7 @@ import com.arialyy.aria.core.manager.ThreadTaskManager;
import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile; import com.arialyy.aria.util.BufferedRandomAccessFile;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.ErrorHelp; import com.arialyy.aria.util.ErrorHelp;
import com.arialyy.aria.util.NetUtils; import com.arialyy.aria.util.NetUtils;
import java.io.File; import java.io.File;
@ -197,6 +198,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
void sendState(int state, @Nullable Bundle bundle) { void sendState(int state, @Nullable Bundle bundle) {
Message msg = mStateHandler.obtainMessage(); Message msg = mStateHandler.obtainMessage();
msg.what = state; msg.what = state;
msg.obj = this;
if (bundle != null) { if (bundle != null) {
msg.setData(bundle); msg.setData(bundle);
} }
@ -242,7 +244,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
blockFile.delete(); blockFile.delete();
ALog.i(TAG, String.format("删除分块【%s】成功", blockFile.getName())); ALog.i(TAG, String.format("删除分块【%s】成功", blockFile.getName()));
} }
retryThis(isBreak()); retryBlockTask(isBreak());
return false; return false;
} }
return true; return true;
@ -316,7 +318,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
* @param subCurrentLocation 当前线程下载进度 * @param subCurrentLocation 当前线程下载进度
* @param ex 异常信息 * @param ex 异常信息
*/ */
protected void fail(final long subCurrentLocation, BaseException ex) { protected void fail(long subCurrentLocation, BaseException ex) {
fail(subCurrentLocation, ex, true); fail(subCurrentLocation, ex, true);
} }
@ -331,10 +333,11 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
} }
if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_VOD) { if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_VOD) {
writeConfig(false, 0); writeConfig(false, 0);
retryM3U8Peer(needRetry);
} else { } else {
if (mTaskWrapper.isSupportBP()) { if (mTaskWrapper.isSupportBP()) {
writeConfig(false, subCurrentLocation); writeConfig(false, subCurrentLocation);
retryThis(needRetry && mConfig.startThreadNum != 1); retryBlockTask(needRetry && mConfig.startThreadNum != 1);
} else { } else {
ALog.e(TAG, String.format("任务【%s】执行失败", getFileName())); ALog.e(TAG, String.format("任务【%s】执行失败", getFileName()));
ErrorHelp.saveError(TAG, "", ALog.getExceptionString(ex)); ErrorHelp.saveError(TAG, "", ALog.getExceptionString(ex));
@ -344,30 +347,53 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
} }
/** /**
* 重试当前线程如果其中一条线程已经下载失败则任务该任务下载失败并且停止该任务的所有线程 * 重试ts分片
*/
private void retryM3U8Peer(boolean needRetry) {
if (!NetUtils.isConnected(AriaManager.APP) && !isNotNetRetry) {
ALog.w(TAG, String.format("任务【%s】重试失败,网络未连接", getFileName()));
sendFailMsg(null);
return;
}
if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected(AriaManager.APP)
|| isNotNetRetry) && !isBreak()) {
ALog.w(TAG, String.format("任务【%s】正在重试", getFileName()));
mFailTimes++;
mConfig.tempFile.delete();
CommonUtil.createFile(mConfig.tempFile.getPath());
ThreadTaskManager.getInstance().retryThread(this);
} else {
sendFailMsg(null);
}
}
/**
* 重试分块线程如果其中一条线程已经下载失败则任务该任务下载失败并且停止该任务的所有线程
* *
* @param needRetry 是否可以重试 * @param needRetry 是否可以重试
*/ */
private void retryThis(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);
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++;
handleRetryRecord(); handleBlockRecord();
ThreadTaskManager.getInstance().retryThread(AbsThreadTask.this); ThreadTaskManager.getInstance().retryThread(this);
} else { } else {
sendFailMsg(null); sendFailMsg(null);
} }
} }
/** /**
* 处理线程重试的记录只有多线程任务才会执行 * 处理线程重试的分块记录只有多线程任务才会执行
* 如果是以前版本{@link BufferedRandomAccessFile}创建的下载那么 record.startLocation不用修改 * 如果是以前版本{@link BufferedRandomAccessFile}创建的下载那么 record.startLocation不用修改
*/ */
private void handleRetryRecord() { private void handleBlockRecord() {
if (mConfig.isBlock) { if (mConfig.isBlock) {
// 默认线程分块长度 // 默认线程分块长度
File temp = mConfig.tempFile; File temp = mConfig.tempFile;

@ -35,7 +35,7 @@ import com.arialyy.aria.util.RecordUtil;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
public abstract class BaseListener<ENTITY extends AbsEntity, TASK_WRAPPER extends AbsTaskWrapper<ENTITY>, public abstract class BaseListener<ENTITY extends AbsEntity, TASK_WRAPPER extends AbsTaskWrapper<ENTITY>,
TASK extends AbsTask<ENTITY, TASK_WRAPPER>> TASK extends AbsTask<TASK_WRAPPER>>
implements IEventListener { implements IEventListener {
protected static String TAG; protected static String TAG;
private static final int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度 private static final int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度

@ -55,7 +55,8 @@ public abstract class NormalFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER
*/ */
@Override @Override
public void setMaxSpeed(int maxSpeed) { public void setMaxSpeed(int maxSpeed) {
for (AbsThreadTask task : getTaskList().values()) { for (int i = 0; i < getTaskList().size(); i++) {
AbsThreadTask task = getTaskList().valueAt(i);
if (task != null && mStartThreadNum > 0) { if (task != null && mStartThreadNum > 0) {
task.setMaxSpeed(maxSpeed / mStartThreadNum); task.setMaxSpeed(maxSpeed / mStartThreadNum);
} }
@ -168,8 +169,9 @@ public abstract class NormalFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER
} else { } else {
mListener.onStart(mStateManager.getCurrentProgress()); mListener.onStart(mStateManager.getCurrentProgress());
} }
for (AbsThreadTask task : getTaskList().values()) {
ThreadTaskManager.getInstance().startThread(mTaskWrapper.getKey(), task); for (int i = 0; i < getTaskList().size(); i++) {
ThreadTaskManager.getInstance().startThread(mTaskWrapper.getKey(), getTaskList().valueAt(i));
} }
} }

@ -15,13 +15,10 @@
*/ */
package com.arialyy.aria.core.common; package com.arialyy.aria.core.common;
import com.arialyy.aria.core.download.DownloadGroupEntity;
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;
import com.arialyy.aria.orm.annotation.Ignore; import com.arialyy.aria.orm.annotation.Ignore;
import com.arialyy.aria.orm.annotation.NoNull; import com.arialyy.aria.orm.annotation.NoNull;
import com.arialyy.aria.orm.annotation.Primary; import com.arialyy.aria.orm.annotation.Unique;
import java.util.List; import java.util.List;
/** /**
@ -44,7 +41,7 @@ public class TaskRecord extends DbEntity {
/** /**
* 任务文件路径 * 任务文件路径
*/ */
@Primary @Unique
public String filePath; public String filePath;
/** /**
@ -67,7 +64,6 @@ public class TaskRecord extends DbEntity {
/** /**
* 下载任务组名 * 下载任务组名
*/ */
@Foreign(parent = DownloadGroupEntity.class, column = "groupHash", onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
public String dGroupHash; public String dGroupHash;
/** /**

@ -25,7 +25,6 @@ import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.AbsTaskWrapper; import com.arialyy.aria.core.inf.AbsTaskWrapper;
import com.arialyy.aria.core.inf.IHttpFileLenAdapter; import com.arialyy.aria.core.inf.IHttpFileLenAdapter;
import com.arialyy.aria.core.inf.IHttpHeaderDelegate; import com.arialyy.aria.core.inf.IHttpHeaderDelegate;
import com.arialyy.aria.core.inf.ITargetHandler;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import java.net.Proxy; import java.net.Proxy;
import java.util.Collection; import java.util.Collection;

@ -78,17 +78,15 @@ abstract class AbsGroupConfigHandler<TARGET extends AbsDGTarget> implements IGro
ALog.d(TAG, String.format("修改新路径为:%s", newDirPath)); ALog.d(TAG, String.format("修改新路径为:%s", newDirPath));
List<DTaskWrapper> subTasks = mWrapper.getSubTaskWrapper(); List<DTaskWrapper> subTasks = mWrapper.getSubTaskWrapper();
if (subTasks != null && !subTasks.isEmpty()) { if (subTasks != null && !subTasks.isEmpty()) {
List<DownloadEntity> des = new ArrayList<>();
for (DTaskWrapper dte : subTasks) { for (DTaskWrapper dte : subTasks) {
DownloadEntity de = dte.getEntity(); DownloadEntity de = dte.getEntity();
String oldPath = de.getDownloadPath(); String oldPath = de.getFilePath();
String newPath = newDirPath + "/" + de.getFileName(); String newPath = newDirPath + "/" + de.getFileName();
File file = new File(oldPath); File file = new File(oldPath);
if (file.exists()) { if (file.exists()) {
file.renameTo(new File(newPath)); file.renameTo(new File(newPath));
} }
de.setDownloadPath(newPath); de.setFilePath(newPath);
des.add(de);
} }
} }
} }
@ -103,12 +101,18 @@ abstract class AbsGroupConfigHandler<TARGET extends AbsDGTarget> implements IGro
ALog.e(TAG, "文件夹路径不能为null"); ALog.e(TAG, "文件夹路径不能为null");
return false; return false;
} else if (!mDirPathTemp.startsWith("/")) { } else if (!mDirPathTemp.startsWith("/")) {
ALog.e(TAG, "文件夹路径【" + mDirPathTemp + "】错误"); ALog.e(TAG, String.format("文件夹路径【%s】错误", mDirPathTemp));
return false; return false;
} }
File file = new File(mDirPathTemp); File file = new File(mDirPathTemp);
if (file.isFile()) { if (file.isFile()) {
ALog.e(TAG, "路径【" + mDirPathTemp + "】是文件,请设置文件夹路径"); ALog.e(TAG, String.format("路径【%s】是文件,请设置文件夹路径", mDirPathTemp));
return false;
}
if ((getEntity().getDirPath() == null || !getEntity().getDirPath().equals(mDirPathTemp))
&& DbEntity.checkDataExist(DownloadGroupEntity.class, "dirPath=?", mDirPathTemp)) {
ALog.e(TAG, String.format("文件夹路径【%s】已被其它任务占用,请重新设置文件夹路径", mDirPathTemp));
return false; return false;
} }

@ -21,9 +21,7 @@ import android.os.Parcelable;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsNormalEntity; import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskWrapper; import com.arialyy.aria.core.inf.AbsTaskWrapper;
import com.arialyy.aria.orm.ActionPolicy; import com.arialyy.aria.orm.annotation.Unique;
import com.arialyy.aria.orm.annotation.Foreign;
import com.arialyy.aria.orm.annotation.Primary;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
/** /**
@ -31,13 +29,11 @@ import com.arialyy.aria.util.CommonUtil;
* 下载实体 * 下载实体
*/ */
public class DownloadEntity extends AbsNormalEntity implements Parcelable { public class DownloadEntity extends AbsNormalEntity implements Parcelable {
@Primary private String downloadPath; //保存路径 @Unique private String downloadPath; //保存路径
/** /**
* 所属任务组 * 所属任务组
*/ */
@Foreign(parent = DownloadGroupEntity.class, column = "groupHash",
onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
private String groupHash; private String groupHash;
/** /**

@ -32,7 +32,7 @@ import com.arialyy.aria.util.CheckUtil;
* Created by AriaL on 2017/6/27. * Created by AriaL on 2017/6/27.
* 任务组任务 * 任务组任务
*/ */
public class DownloadGroupTask extends AbsGroupTask<DownloadGroupEntity, DGTaskWrapper> { public class DownloadGroupTask extends AbsGroupTask<DGTaskWrapper> {
private DownloadGroupTask(DGTaskWrapper taskWrapper, Handler outHandler) { private DownloadGroupTask(DGTaskWrapper taskWrapper, Handler outHandler) {
mTaskWrapper = taskWrapper; mTaskWrapper = taskWrapper;

@ -32,7 +32,7 @@ import com.arialyy.aria.core.scheduler.ISchedulers;
* Created by lyy on 2016/8/11. * Created by lyy on 2016/8/11.
* 下载任务类 * 下载任务类
*/ */
public class DownloadTask extends AbsNormalTask<DownloadEntity, DTaskWrapper> { public class DownloadTask extends AbsNormalTask<DTaskWrapper> {
public static final String TAG = "DownloadTask"; public static final String TAG = "DownloadTask";
private DownloadTask(DTaskWrapper taskWrapper, Handler outHandler) { private DownloadTask(DTaskWrapper taskWrapper, Handler outHandler) {
@ -40,7 +40,6 @@ public class DownloadTask extends AbsNormalTask<DownloadEntity, DTaskWrapper> {
mOutHandler = outHandler; mOutHandler = outHandler;
mContext = AriaManager.APP; mContext = AriaManager.APP;
mListener = new BaseDListener(this, mOutHandler); mListener = new BaseDListener(this, mOutHandler);
mEntity = taskWrapper.getEntity();
} }
/** /**
@ -57,7 +56,7 @@ public class DownloadTask extends AbsNormalTask<DownloadEntity, DTaskWrapper> {
* 获取文件保存路径 * 获取文件保存路径
*/ */
public String getFilePath() { public String getFilePath() {
return mEntity.getFilePath(); return mTaskWrapper.getEntity().getFilePath();
} }
public DownloadEntity getEntity() { public DownloadEntity getEntity() {
@ -70,7 +69,7 @@ public class DownloadTask extends AbsNormalTask<DownloadEntity, DTaskWrapper> {
* @see DownloadTask#getKey() * @see DownloadTask#getKey()
*/ */
@Deprecated public String getDownloadUrl() { @Deprecated public String getDownloadUrl() {
return mEntity.getUrl(); return mTaskWrapper.getEntity().getUrl();
} }
@Override public int getTaskType() { @Override public int getTaskType() {
@ -78,15 +77,15 @@ public class DownloadTask extends AbsNormalTask<DownloadEntity, DTaskWrapper> {
} }
@Override public String getKey() { @Override public String getKey() {
return mEntity.getUrl(); return mTaskWrapper.getEntity().getUrl();
} }
public DownloadEntity getDownloadEntity() { public DownloadEntity getDownloadEntity() {
return mEntity; return mTaskWrapper.getEntity();
} }
@Override public String getTaskName() { @Override public String getTaskName() {
return mEntity.getFileName(); return mTaskWrapper.getEntity().getFileName();
} }
@Override protected synchronized IUtil createUtil() { @Override protected synchronized IUtil createUtil() {

@ -19,6 +19,7 @@ import com.arialyy.aria.core.common.BaseDelegate;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.inf.AbsTarget; import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.AbsTaskWrapper; import com.arialyy.aria.core.inf.AbsTaskWrapper;
import com.arialyy.aria.util.ALog;
/** /**
* m3u8直播参数设置 * m3u8直播参数设置
@ -40,4 +41,18 @@ public class M3U8LiveDelegate<TARGET extends AbsTarget> extends BaseDelegate<TAR
((DTaskWrapper) mTarget.getTaskWrapper()).asM3U8().setLiveTsUrlConverter(converter); ((DTaskWrapper) mTarget.getTaskWrapper()).asM3U8().setLiveTsUrlConverter(converter);
return this; return this;
} }
/**
* 设置直播的m3u8文件更新间隔默认10000微秒
*
* @param interval 更新间隔单位微秒
*/
public M3U8LiveDelegate setM3U8FileUpdateInterval(long interval) {
if (interval <= 1) {
ALog.e(TAG, "间隔时间错误");
return this;
}
((DTaskWrapper) mTarget.getTaskWrapper()).asM3U8().setLiveUpdateInterval(interval);
return this;
}
} }

@ -22,10 +22,11 @@ import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.IDownloadListener; import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.core.manager.ThreadTaskManager;
import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.exception.BaseException;
import com.arialyy.aria.exception.M3U8Exception; import com.arialyy.aria.exception.M3U8Exception;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
@ -42,7 +43,6 @@ import java.util.concurrent.TimeUnit;
*/ */
public class M3U8LiveDownloadUtil implements IUtil { public class M3U8LiveDownloadUtil implements IUtil {
private final String TAG = "M3U8LiveDownloadUtil"; private final String TAG = "M3U8LiveDownloadUtil";
private DTaskWrapper mWrapper; private DTaskWrapper mWrapper;
private IDownloadListener mListener; private IDownloadListener mListener;
private boolean isStop = false, isCancel = false; private boolean isStop = false, isCancel = false;
@ -50,6 +50,7 @@ public class M3U8LiveDownloadUtil implements IUtil {
private M3U8InfoThread mInfoThread; private M3U8InfoThread mInfoThread;
private ScheduledThreadPoolExecutor mTimer; private ScheduledThreadPoolExecutor mTimer;
private ExecutorService mInfoPool = Executors.newCachedThreadPool(); private ExecutorService mInfoPool = Executors.newCachedThreadPool();
private List<String> mPeerUrls = new ArrayList<>();
public M3U8LiveDownloadUtil(DTaskWrapper wrapper, IDownloadListener listener) { public M3U8LiveDownloadUtil(DTaskWrapper wrapper, IDownloadListener listener) {
mWrapper = wrapper; mWrapper = wrapper;
@ -86,6 +87,7 @@ public class M3U8LiveDownloadUtil implements IUtil {
*/ */
@Override public void stop() { @Override public void stop() {
isStop = true; isStop = true;
mLoader.stop();
handleComplete(); handleComplete();
} }
@ -122,7 +124,7 @@ public class M3U8LiveDownloadUtil implements IUtil {
mInfoThread = (M3U8InfoThread) getLiveInfo(); mInfoThread = (M3U8InfoThread) getLiveInfo();
mInfoPool.execute(mInfoThread); mInfoPool.execute(mInfoThread);
} }
}, 0, 1000, TimeUnit.MILLISECONDS); }, 0, mWrapper.asM3U8().getLiveUpdateInterval(), TimeUnit.MILLISECONDS);
} }
private void closeTimer() { private void closeTimer() {
@ -150,6 +152,10 @@ public class M3U8LiveDownloadUtil implements IUtil {
}); });
infoThread.setOnGetPeerCallback(new M3U8InfoThread.OnGetLivePeerCallback() { infoThread.setOnGetPeerCallback(new M3U8InfoThread.OnGetLivePeerCallback() {
@Override public void onGetPeer(String url) { @Override public void onGetPeer(String url) {
if (mPeerUrls.contains(url)) {
return;
}
mPeerUrls.add(url);
ILiveTsUrlConverter converter = mWrapper.asM3U8().getLiveTsUrlConverter(); ILiveTsUrlConverter converter = mWrapper.asM3U8().getLiveTsUrlConverter();
if (converter != null) { if (converter != null) {
if (TextUtils.isEmpty(mWrapper.asM3U8().getBandWidthUrl())) { if (TextUtils.isEmpty(mWrapper.asM3U8().getBandWidthUrl())) {
@ -162,7 +168,6 @@ public class M3U8LiveDownloadUtil implements IUtil {
failDownload(new M3U8Exception(TAG, String.format("ts地址错误,url:%s", url)), false); failDownload(new M3U8Exception(TAG, String.format("ts地址错误,url:%s", url)), false);
return; return;
} }
//todo url 需要去重
mLoader.offerPeer(url); mLoader.offerPeer(url);
} }
}); });

@ -100,7 +100,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
} }
@Override protected void setMaxSpeed(int maxSpeed) { @Override protected void setMaxSpeed(int maxSpeed) {
// TODO: 2019-06-06 不支持 // TODO: 2019-06-06 不支持
} }
private void notifyLock() { private void notifyLock() {
@ -199,7 +199,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
} }
/** /**
* M3U8线程状态管理 * M3U8线程状态管理直播不处理停止状态删除失败的状态
*/ */
private class LiveStateManager implements IThreadState { private class LiveStateManager implements IThreadState {
private final String TAG = "M3U8ThreadStateManager"; private final String TAG = "M3U8ThreadStateManager";
@ -208,8 +208,6 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
* 任务状态回调 * 任务状态回调
*/ */
private IEventListener mListener; private IEventListener mListener;
private int mCancelNum = 0; // 已经取消的线程的数
private int mStopNum = 0; // 已经停止的线程数
private long mProgress; //当前总进度 private long mProgress; //当前总进度
private Looper mLooper; private Looper mLooper;
@ -232,7 +230,6 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
@Override public boolean handleMessage(Message msg) { @Override public boolean handleMessage(Message msg) {
switch (msg.what) { switch (msg.what) {
case STATE_STOP: case STATE_STOP:
mStopNum++;
if (isStop()) { if (isStop()) {
ALog.d(TAG, "任务停止"); ALog.d(TAG, "任务停止");
mListener.onStop(mProgress); mListener.onStop(mProgress);
@ -240,7 +237,6 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
} }
break; break;
case STATE_CANCEL: case STATE_CANCEL:
mCancelNum++;
if (isCancel()) { if (isCancel()) {
ALog.d(TAG, "任务取消"); ALog.d(TAG, "任务取消");
mListener.onCancel(); mListener.onCancel();
@ -258,23 +254,18 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
} }
@Override public boolean isStop() { @Override public boolean isStop() {
// 某些服务器后一次性发送多个ts地址,所以不能简单使用mStopNum == mFlagQueue.size();判断状态
//return mStopNum == mFlagQueue.size();
return false; return false;
} }
@Override public boolean isFail() { @Override public boolean isFail() {
// 直播下载不处理失败的切片
return false; return false;
} }
@Override public boolean isComplete() { @Override public boolean isComplete() {
// 直播不处理完成
return false; return false;
} }
@Override public boolean isCancel() { @Override public boolean isCancel() {
//return mCancelNum == mFlagQueue.size();
return false; return false;
} }

@ -82,6 +82,19 @@ public class M3U8TaskConfig {
*/ */
private ILiveTsUrlConverter liveTsUrlConverter; private ILiveTsUrlConverter liveTsUrlConverter;
/**
* 直播的m3u8文件更新间隔
*/
private long liveUpdateInterval = 10 * 1000;
public long getLiveUpdateInterval() {
return liveUpdateInterval;
}
public void setLiveUpdateInterval(long liveUpdateInterval) {
this.liveUpdateInterval = liveUpdateInterval;
}
public ILiveTsUrlConverter getLiveTsUrlConverter() { public ILiveTsUrlConverter getLiveTsUrlConverter() {
return liveTsUrlConverter; return liveTsUrlConverter;
} }

@ -19,6 +19,7 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.common.IThreadState; import com.arialyy.aria.core.common.IThreadState;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.common.TaskRecord; import com.arialyy.aria.core.common.TaskRecord;
@ -200,6 +201,8 @@ public class M3U8VodLoader extends BaseM3U8Loader {
switch (msg.what) { switch (msg.what) {
case STATE_STOP: case STATE_STOP:
mStopNum++; mStopNum++;
ThreadTaskManager.getInstance().removeSingleTaskThread(mTaskWrapper.getKey(),
(AbsThreadTask) msg.obj);
if (isStop()) { if (isStop()) {
ALog.d(TAG, "任务停止"); ALog.d(TAG, "任务停止");
mListener.onStop(mProgress); mListener.onStop(mProgress);
@ -208,6 +211,8 @@ public class M3U8VodLoader extends BaseM3U8Loader {
break; break;
case STATE_CANCEL: case STATE_CANCEL:
mCancelNum++; mCancelNum++;
ThreadTaskManager.getInstance().removeSingleTaskThread(mTaskWrapper.getKey(),
(AbsThreadTask) msg.obj);
if (isCancel()) { if (isCancel()) {
ALog.d(TAG, "任务取消"); ALog.d(TAG, "任务取消");
mListener.onCancel(); mListener.onCancel();
@ -225,6 +230,8 @@ public class M3U8VodLoader extends BaseM3U8Loader {
break; break;
case STATE_COMPLETE: case STATE_COMPLETE:
mCompleteNum++; mCompleteNum++;
ThreadTaskManager.getInstance().removeSingleTaskThread(mTaskWrapper.getKey(),
(AbsThreadTask) msg.obj);
handlerPercent(); handlerPercent();
notifyLock(); notifyLock();
if (isComplete()) { if (isComplete()) {

@ -17,7 +17,7 @@ package com.arialyy.aria.core.inf;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import com.arialyy.aria.orm.annotation.Primary; import com.arialyy.aria.orm.annotation.Unique;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -28,7 +28,7 @@ public abstract class AbsGroupEntity extends AbsEntity implements Parcelable {
/** /**
* 组名组名为任务地址相加的url的Md5 * 组名组名为任务地址相加的url的Md5
*/ */
@Primary protected String groupHash; @Unique protected String groupHash;
/** /**
* 任务组别名 * 任务组别名
@ -38,7 +38,7 @@ public abstract class AbsGroupEntity extends AbsEntity implements Parcelable {
/** /**
* 任务组下载文件的文件夹地址 * 任务组下载文件的文件夹地址
*/ */
private String dirPath; @Unique private String dirPath;
/** /**
* 子任务url地址 * 子任务url地址

@ -21,8 +21,8 @@ import com.arialyy.aria.core.download.group.AbsGroupUtil;
* Created by AriaL on 2017/6/29. * Created by AriaL on 2017/6/29.
* 任务组任务抽象类 * 任务组任务抽象类
*/ */
public abstract class AbsGroupTask<ENTITY extends AbsEntity, TASK_ENTITY extends AbsGroupTaskWrapper> public abstract class AbsGroupTask<TASK_ENTITY extends AbsGroupTaskWrapper>
extends AbsTask<ENTITY, TASK_ENTITY> { extends AbsTask<TASK_ENTITY> {
@Override public String getKey() { @Override public String getKey() {
return mTaskWrapper.getEntity().getKey(); return mTaskWrapper.getEntity().getKey();

@ -18,8 +18,8 @@ package com.arialyy.aria.core.inf;
/** /**
* Created by lyy on 2017/6/3. * Created by lyy on 2017/6/3.
*/ */
public abstract class AbsNormalTask<ENTITY extends AbsEntity, TASK_WRAPPER extends AbsTaskWrapper> public abstract class AbsNormalTask<TASK_WRAPPER extends AbsTaskWrapper>
extends AbsTask<ENTITY, TASK_WRAPPER> { extends AbsTask<TASK_WRAPPER> {
/** /**
* 最高优先级命令最高优先级命令有以下属性 * 最高优先级命令最高优先级命令有以下属性

@ -27,7 +27,7 @@ import java.util.Map;
/** /**
* Created by AriaL on 2017/6/29. * Created by AriaL on 2017/6/29.
*/ */
public abstract class AbsTask<ENTITY extends AbsEntity, TASK_WRAPPER extends AbsTaskWrapper> public abstract class AbsTask<TASK_WRAPPER extends AbsTaskWrapper>
implements ITask<TASK_WRAPPER> { implements ITask<TASK_WRAPPER> {
public static final String ERROR_INFO_KEY = "ERROR_INFO_KEY"; public static final String ERROR_INFO_KEY = "ERROR_INFO_KEY";
@ -51,7 +51,6 @@ public abstract class AbsTask<ENTITY extends AbsEntity, TASK_WRAPPER extends Abs
@TaskSchedulerType @TaskSchedulerType
private int mSchedulerType = TaskSchedulerType.TYPE_DEFAULT; private int mSchedulerType = TaskSchedulerType.TYPE_DEFAULT;
protected IEventListener mListener; protected IEventListener mListener;
protected ENTITY mEntity;
protected String TAG; protected String TAG;
protected AbsTask() { protected AbsTask() {
@ -165,7 +164,7 @@ public abstract class AbsTask<ENTITY extends AbsEntity, TASK_WRAPPER extends Abs
* @return 返回百分比进度如果文件长度为0返回0 * @return 返回百分比进度如果文件长度为0返回0
*/ */
public int getPercent() { public int getPercent() {
return mEntity.getPercent(); return mTaskWrapper.getEntity().getPercent();
} }
/** /**
@ -220,7 +219,7 @@ public abstract class AbsTask<ENTITY extends AbsEntity, TASK_WRAPPER extends Abs
getUtil().stop(); getUtil().stop();
} else { } else {
ALog.d(TAG, "下载任务未执行"); ALog.d(TAG, "下载任务未执行");
mListener.onStop(mEntity.getCurrentProgress()); mListener.onStop(mTaskWrapper.getEntity().getCurrentProgress());
} }
} }

@ -100,7 +100,6 @@ public class ThreadTaskManager {
*/ */
public void removeTaskThread(String key) { public void removeTaskThread(String key) {
try { try {
LOCK.tryLock(2, TimeUnit.SECONDS); LOCK.tryLock(2, TimeUnit.SECONDS);
if (mExePool.isShutdown()) { if (mExePool.isShutdown()) {
ALog.e(TAG, "线程池已经关闭"); ALog.e(TAG, "线程池已经关闭");
@ -125,6 +124,45 @@ public class ThreadTaskManager {
} }
} }
/**
* 删除单个线程任务
*
* @param key 任务的key
* @param task 线程任务
*/
public void removeSingleTaskThread(String key, AbsThreadTask task) {
try {
LOCK.tryLock(2, TimeUnit.SECONDS);
if (mExePool.isShutdown()) {
ALog.e(TAG, "线程池已经关闭");
return;
}
if (task == null) {
ALog.e(TAG, "线程任务为空");
return;
}
key = getKey(key);
Set<FutureContainer> temp = mThreadTasks.get(key);
if (temp != null && temp.size() > 0) {
FutureContainer tempC = null;
for (FutureContainer container : temp) {
if (container.threadTask == task) {
tempC = container;
break;
}
}
if (tempC != null) {
task.setInterrupted(true);
temp.remove(tempC);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
LOCK.unlock();
}
}
/** /**
* 重试线程任务 * 重试线程任务
* *

@ -25,6 +25,7 @@ import com.arialyy.aria.core.download.DTaskWrapper;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UTaskWrapper; import com.arialyy.aria.core.upload.UTaskWrapper;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
/** /**
@ -34,7 +35,7 @@ import java.util.Map;
class DBConfig { class DBConfig {
/*adb pull /mnt/sdcard/Android/data/com.arialyy.simple/files/DB/AriaLyyDb d:/db*/ /*adb pull /mnt/sdcard/Android/data/com.arialyy.simple/files/DB/AriaLyyDb d:/db*/
static boolean DEBUG = false; static boolean DEBUG = false;
static Map<String, Class> mapping = new HashMap<>(); static Map<String, Class> mapping = new LinkedHashMap<>();
static String DB_NAME; static String DB_NAME;
static int VERSION = 48; static int VERSION = 48;

@ -15,11 +15,11 @@
*/ */
package com.arialyy.aria.orm; package com.arialyy.aria.orm;
import android.annotation.TargetApi; import android.annotation.SuppressLint;
import android.database.Cursor; import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.SparseArray;
import com.arialyy.aria.orm.annotation.Many; import com.arialyy.aria.orm.annotation.Many;
import com.arialyy.aria.orm.annotation.One; import com.arialyy.aria.orm.annotation.One;
import com.arialyy.aria.orm.annotation.Wrapper; import com.arialyy.aria.orm.annotation.Wrapper;
@ -29,9 +29,8 @@ import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.LinkedHashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -127,11 +126,11 @@ class DelegateFind extends AbsDelegate {
* @param page 当前页 * @param page 当前页
* @param num 一页的数量 * @param num 一页的数量
*/ */
private <T extends AbsDbWrapper> List<T> exeRelationSql(SQLiteDatabase db, Class<T> clazz, private <T extends AbsDbWrapper> List<T> exeRelationSql(SQLiteDatabase db, Class<T> wrapperClazz,
int page, int num, String... expression) { int page, int num, String... expression) {
db = checkDb(db); db = checkDb(db);
if (SqlUtil.isWrapper(clazz)) { if (SqlUtil.isWrapper(wrapperClazz)) {
Field[] om = getOneAndManyField(clazz); Field[] om = getOneAndManyField(wrapperClazz);
if (om == null) { if (om == null) {
return null; return null;
} }
@ -145,8 +144,6 @@ class DelegateFind extends AbsDelegate {
final String cTableName = childClazz.getSimpleName(); final String cTableName = childClazz.getSimpleName();
List<Field> pColumn = SqlUtil.getAllNotIgnoreField(parentClazz); List<Field> pColumn = SqlUtil.getAllNotIgnoreField(parentClazz);
List<Field> cColumn = SqlUtil.getAllNotIgnoreField(childClazz); List<Field> cColumn = SqlUtil.getAllNotIgnoreField(childClazz);
List<String> pColumnAlias = new ArrayList<>();
List<String> cColumnAlias = new ArrayList<>();
StringBuilder pSb = new StringBuilder(); StringBuilder pSb = new StringBuilder();
StringBuilder cSb = new StringBuilder(); StringBuilder cSb = new StringBuilder();
@ -154,7 +151,6 @@ class DelegateFind extends AbsDelegate {
pSb.append(pTableName.concat(".rowid AS ").concat(PARENT_COLUMN_ALIAS).concat("rowid,")); pSb.append(pTableName.concat(".rowid AS ").concat(PARENT_COLUMN_ALIAS).concat("rowid,"));
for (Field f : pColumn) { for (Field f : pColumn) {
String temp = PARENT_COLUMN_ALIAS.concat(f.getName()); String temp = PARENT_COLUMN_ALIAS.concat(f.getName());
pColumnAlias.add(temp);
pSb.append(pTableName.concat(".").concat(f.getName())) pSb.append(pTableName.concat(".").concat(f.getName()))
.append(" AS ") .append(" AS ")
.append(temp) .append(temp)
@ -166,7 +162,6 @@ class DelegateFind extends AbsDelegate {
pSb.append(cTableName.concat(".rowid AS ").concat(CHILD_COLUMN_ALIAS).concat("rowid,")); pSb.append(cTableName.concat(".rowid AS ").concat(CHILD_COLUMN_ALIAS).concat("rowid,"));
for (Field f : cColumn) { for (Field f : cColumn) {
String temp = CHILD_COLUMN_ALIAS.concat(f.getName()); String temp = CHILD_COLUMN_ALIAS.concat(f.getName());
cColumnAlias.add(temp);
cSb.append(cTableName.concat(".").concat(f.getName())) cSb.append(cTableName.concat(".").concat(f.getName()))
.append(" AS ") .append(" AS ")
.append(temp) .append(temp)
@ -223,8 +218,7 @@ class DelegateFind extends AbsDelegate {
} }
Cursor cursor = db.rawQuery(sql, null); Cursor cursor = db.rawQuery(sql, null);
List<T> data = List<T> data =
(List<T>) newInstanceEntity(clazz, parentClazz, childClazz, cursor, pColumn, cColumn, newInstanceEntity(wrapperClazz, parentClazz, childClazz, cursor, pColumn, cColumn);
pColumnAlias, cColumnAlias);
closeCursor(cursor); closeCursor(cursor);
return data; return data;
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
@ -242,139 +236,84 @@ class DelegateFind extends AbsDelegate {
* *
* @param pColumn 父表的所有字段 * @param pColumn 父表的所有字段
* @param cColumn 字表的所有字段 * @param cColumn 字表的所有字段
* @param pColumnAlias 关联查询父表别名
* @param cColumnAlias 关联查询子表别名
*/ */
private synchronized <T extends AbsDbWrapper, P extends DbEntity, C extends DbEntity> List<T> newInstanceEntity( private synchronized <T extends AbsDbWrapper, P extends DbEntity, C extends DbEntity> List<T> newInstanceEntity(
Class<T> clazz, Class<P> parent, Class<T> wrapperClazz, Class<P> parentClazz,
Class<C> child, Class<C> childClazz,
Cursor cursor, Cursor cursor,
List<Field> pColumn, List<Field> cColumn, List<Field> pColumn, List<Field> cColumn) {
List<String> pColumnAlias, List<String> cColumnAlias) { List<T> wrappers = new ArrayList<>();
try { SparseArray<List<DbEntity>> childs = new SparseArray<>(); // 所有子表数据
String parentPrimary = ""; //父表主键别名 SparseArray<DbEntity> parents = new SparseArray<>(); // 所有父表数据
for (Field f : pColumn) {
if (SqlUtil.isPrimary(f)) {
parentPrimary = PARENT_COLUMN_ALIAS.concat(f.getName());
break;
}
}
List<T> wrappers = new ArrayList<>();
Map<Object, P> tempParent = new LinkedHashMap<>(); // 所有父表元素,key为父表主键的值
Map<Object, List<C>> tempChild = new LinkedHashMap<>(); // 所有的字表元素,key为父表主键的值
Object old = null; try {
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
//创建父实体 int pRowId = cursor.getInt(cursor.getColumnIndex(PARENT_COLUMN_ALIAS.concat("rowid")));
Object ppValue = setPPValue(parentPrimary, cursor); if (childs.get(pRowId) == null) {
if (old == null || ppValue != old) { //当主键不同时,表示是不同的父表数据 childs.put(pRowId, new ArrayList<DbEntity>());
old = ppValue; parents.put(pRowId, createParent(pRowId, parentClazz, pColumn, cursor));
if (tempParent.get(old) == null) {
P pEntity = parent.newInstance();
String pPrimaryName = "";
for (int i = 0, len = pColumnAlias.size(); i < len; i++) {
Field pField = pColumn.get(i);
pField.setAccessible(true);
Class<?> type = pField.getType();
int column = cursor.getColumnIndex(pColumnAlias.get(i));
if (column == -1) continue;
setFieldValue(type, pField, column, cursor, pEntity);
if (SqlUtil.isPrimary(pField) && (type == int.class || type == Integer.class)) {
pPrimaryName = pField.getName();
}
}
//当设置了主键,而且主键的类型为integer时,查询RowID等于主键
pEntity.rowID = cursor.getInt(
cursor.getColumnIndex(
TextUtils.isEmpty(pPrimaryName) ? PARENT_COLUMN_ALIAS.concat("rowid")
: pPrimaryName));
tempParent.put(ppValue, pEntity);
}
}
// 创建子实体
C cEntity = child.newInstance();
String cPrimaryName = "";
for (int i = 0, len = cColumnAlias.size(); i < len; i++) {
Field cField = cColumn.get(i);
cField.setAccessible(true);
Class<?> type = cField.getType();
int column = cursor.getColumnIndex(cColumnAlias.get(i));
if (column == -1) continue;
setFieldValue(type, cField, column, cursor, cEntity);
if (SqlUtil.isPrimary(cField) && (type == int.class || type == Integer.class)) {
cPrimaryName = cField.getName();
}
} }
//当设置了主键,而且主键的类型为integer时,查询RowID等于主键 childs.get(pRowId).add(createChild(childClazz, cColumn, cursor));
cEntity.rowID = cursor.getInt(
cursor.getColumnIndex(
TextUtils.isEmpty(cPrimaryName) ? CHILD_COLUMN_ALIAS.concat("rowid")
: cPrimaryName));
if (tempChild.get(old) == null) {
tempChild.put(old, new ArrayList<C>());
}
tempChild.get(old).add(cEntity);
} }
List<Field> wFields = SqlUtil.getAllNotIgnoreField(clazz); List<Field> wFields = SqlUtil.getAllNotIgnoreField(wrapperClazz);
if (wFields != null && !wFields.isEmpty()) { if (wFields == null || wFields.isEmpty()) {
Set<Object> pKeys = tempParent.keySet(); return null;
for (Object pk : pKeys) { }
T wrapper = clazz.newInstance(); for (int i = 0; i < parents.size(); i++) {
P p = tempParent.get(pk); int pRowId = parents.keyAt(i);
boolean isPSet = false, isCSet = false; T wrapper = wrapperClazz.newInstance();
for (Field f : wFields) { boolean isPSet = false, isCSet = false; // 保证One 或 Many 只设置一次
if (!isPSet && f.getAnnotation(One.class) != null) { for (Field f : wFields) {
f.set(wrapper, p); if (!isPSet && f.getAnnotation(One.class) != null) {
isPSet = true; f.set(wrapper, parents.get(pRowId));
} isPSet = true;
if (!isCSet && f.getAnnotation(Many.class) != null) { }
f.set(wrapper, tempChild.get(pk)); if (!isCSet && f.getAnnotation(Many.class) != null) {
isCSet = true; f.set(wrapper, childs.get(pRowId));
} isCSet = true;
} }
wrapper.handleConvert(); //处理下转换
wrappers.add(wrapper);
} }
wrapper.handleConvert(); //处理下转换
wrappers.add(wrapper);
} }
return wrappers; } catch (Exception e) {
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace(); e.printStackTrace();
} }
return null;
return wrappers;
} }
/** /**
* 获取父表主键数据 * 创建子对象
*
* @param parentPrimary 父表主键别名
*/ */
@TargetApi(Build.VERSION_CODES.HONEYCOMB) private Object setPPValue(String parentPrimary, private <T extends DbEntity> T createChild(Class<T> childClazz, List<Field> cColumn,
Cursor cursor) { Cursor cursor)
Object ppValue = null; throws InstantiationException, IllegalAccessException {
int ppColumn = cursor.getColumnIndex(parentPrimary); //父表主键所在的列 T child = childClazz.newInstance();
int type = cursor.getType(ppColumn); child.rowID = cursor.getInt(cursor.getColumnIndex(CHILD_COLUMN_ALIAS.concat("rowid")));
switch (type) { for (Field field : cColumn) {
case Cursor.FIELD_TYPE_INTEGER: field.setAccessible(true);
ppValue = cursor.getLong(ppColumn); int columnIndex = cursor.getColumnIndex(CHILD_COLUMN_ALIAS.concat(field.getName()));
break; setFieldValue(field.getType(), field, columnIndex, cursor, child);
case Cursor.FIELD_TYPE_FLOAT:
ppValue = cursor.getFloat(ppColumn);
break;
case Cursor.FIELD_TYPE_STRING:
ppValue = cursor.getString(ppColumn);
break;
} }
return ppValue; return child;
}
/**
* 创建父对象
*/
private <T extends DbEntity> T createParent(int rowId, Class<T> parentClazz, List<Field> pColumn,
Cursor cursor)
throws InstantiationException, IllegalAccessException {
T parent = parentClazz.newInstance();
parent.rowID = rowId;
for (Field field : pColumn) {
field.setAccessible(true);
int columnIndex = cursor.getColumnIndex(PARENT_COLUMN_ALIAS.concat(field.getName()));
setFieldValue(field.getType(), field, columnIndex, cursor, parent);
}
return parent;
} }
/** /**
@ -467,9 +406,9 @@ class DelegateFind extends AbsDelegate {
String sql, String[] selectionArgs) { String sql, String[] selectionArgs) {
String[] temp = new String[selectionArgs.length]; String[] temp = new String[selectionArgs.length];
int i = 0; int i = 0;
for (String arg : selectionArgs){ for (String arg : selectionArgs) {
temp[i] = encodeStr(arg); temp[i] = encodeStr(arg);
i ++; i++;
} }
Cursor cursor = db.rawQuery(sql, temp); Cursor cursor = db.rawQuery(sql, temp);
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; List<T> data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
@ -525,43 +464,44 @@ class DelegateFind extends AbsDelegate {
* *
* @throws IllegalAccessException * @throws IllegalAccessException
*/ */
private void setFieldValue(Class type, Field field, int column, Cursor cursor, Object entity) private void setFieldValue(Class type, Field field, int columnIndex, Cursor cursor,
DbEntity entity)
throws IllegalAccessException { throws IllegalAccessException {
if (cursor == null || cursor.isClosed()) { if (cursor == null || cursor.isClosed()) {
ALog.e(TAG, "cursor没有初始化"); ALog.e(TAG, "cursor没有初始化");
return; return;
} }
if (type == String.class) { if (type == String.class) {
String temp = cursor.getString(column); String temp = cursor.getString(columnIndex);
if (!TextUtils.isEmpty(temp)) { if (!TextUtils.isEmpty(temp)) {
field.set(entity, URLDecoder.decode(temp)); field.set(entity, URLDecoder.decode(temp));
} }
} else if (type == int.class || type == Integer.class) { } else if (type == int.class || type == Integer.class) {
field.setInt(entity, cursor.getInt(column)); field.setInt(entity, cursor.getInt(columnIndex));
} else if (type == float.class || type == Float.class) { } else if (type == float.class || type == Float.class) {
field.setFloat(entity, cursor.getFloat(column)); field.setFloat(entity, cursor.getFloat(columnIndex));
} else if (type == double.class || type == Double.class) { } else if (type == double.class || type == Double.class) {
field.setDouble(entity, cursor.getDouble(column)); field.setDouble(entity, cursor.getDouble(columnIndex));
} else if (type == long.class || type == Long.class) { } else if (type == long.class || type == Long.class) {
field.setLong(entity, cursor.getLong(column)); field.setLong(entity, cursor.getLong(columnIndex));
} else if (type == boolean.class || type == Boolean.class) { } else if (type == boolean.class || type == Boolean.class) {
String temp = cursor.getString(column); String temp = cursor.getString(columnIndex);
if (TextUtils.isEmpty(temp)) { if (TextUtils.isEmpty(temp)) {
field.setBoolean(entity, false); field.setBoolean(entity, false);
} else { } else {
field.setBoolean(entity, !temp.equalsIgnoreCase("false")); field.setBoolean(entity, !temp.equalsIgnoreCase("false"));
} }
} else if (type == java.util.Date.class || type == java.sql.Date.class) { } else if (type == java.util.Date.class || type == java.sql.Date.class) {
field.set(entity, new Date(URLDecoder.decode(cursor.getString(column)))); field.set(entity, new Date(URLDecoder.decode(cursor.getString(columnIndex))));
} else if (type == byte[].class) { } else if (type == byte[].class) {
field.set(entity, cursor.getBlob(column)); field.set(entity, cursor.getBlob(columnIndex));
} else if (type == Map.class) { } else if (type == Map.class) {
String temp = cursor.getString(column); String temp = cursor.getString(columnIndex);
if (!TextUtils.isEmpty(temp)) { if (!TextUtils.isEmpty(temp)) {
field.set(entity, SqlUtil.str2Map(URLDecoder.decode(temp))); field.set(entity, SqlUtil.str2Map(URLDecoder.decode(temp)));
} }
} else if (type == List.class) { } else if (type == List.class) {
String value = cursor.getString(column); String value = cursor.getString(columnIndex);
if (!TextUtils.isEmpty(value)) { if (!TextUtils.isEmpty(value)) {
field.set(entity, SqlUtil.str2List(URLDecoder.decode(value), field)); field.set(entity, SqlUtil.str2List(URLDecoder.decode(value), field));
} }

@ -141,7 +141,7 @@ final class SqlHelper extends SQLiteOpenHelper {
} }
/** /**
* 处理数据库升级该段代码无法修改表字段 * 处理数据库升级
* *
* @param modifyColumns 需要修改的表字段的映射key为表名 * @param modifyColumns 需要修改的表字段的映射key为表名
* value{@code Map<String, String>}中的Map的key为老字段名称value为该老字段对应的新字段名称 * value{@code Map<String, String>}中的Map的key为老字段名称value为该老字段对应的新字段名称
@ -176,8 +176,9 @@ final class SqlHelper extends SQLiteOpenHelper {
long count = cursor.getLong(0); long count = cursor.getLong(0);
cursor.close(); cursor.close();
// 复制数据
if (count > 0) { if (count > 0) {
// 获取所有字段名称 // 获取旧表的所有字段名称
Cursor columnC = Cursor columnC =
db.rawQuery(String.format("PRAGMA table_info(%s_temp)", tableName), null); db.rawQuery(String.format("PRAGMA table_info(%s_temp)", tableName), null);
StringBuilder params = new StringBuilder(); StringBuilder params = new StringBuilder();
@ -243,11 +244,17 @@ final class SqlHelper extends SQLiteOpenHelper {
mDelegate.dropTable(db, taskTable); mDelegate.dropTable(db, taskTable);
} }
} }
Map<String, Map<String, String>> columnMap = new HashMap<>(); Map<String, Map<String, String>> columnMap = new HashMap<>();
Map<String, String> map = new HashMap<>(); // 处理DownloadEntity、DownloadGroupEntity的 groupName字段名的修改
map.put("groupName", "groupHash"); Map<String, String> groupNameModify = new HashMap<>();
columnMap.put("DownloadEntity", map); groupNameModify.put("groupName", "groupHash");
columnMap.put("DownloadGroupEntity", map); columnMap.put("DownloadEntity", groupNameModify);
columnMap.put("DownloadGroupEntity", groupNameModify);
// 处理TaskRecord的dGroupName字段名的修改
Map<String, String> dGroupNameModify = new HashMap<>();
dGroupNameModify.put("dGroupName", "dGroupHash");
columnMap.put("TaskRecord", dGroupNameModify);
handleDbUpdate(db, columnMap, null); handleDbUpdate(db, columnMap, null);
} }
@ -263,7 +270,7 @@ final class SqlHelper extends SQLiteOpenHelper {
} }
} }
//删除所有主键为null和逐渐重复的数据 //删除所有主键为null和主键重复的数据
String[] tables = new String[] { "DownloadEntity", "DownloadGroupEntity" }; String[] tables = new String[] { "DownloadEntity", "DownloadGroupEntity" };
String[] keys = new String[] { "downloadPath", "groupName" }; String[] keys = new String[] { "downloadPath", "groupName" };
int i = 0; int i = 0;

@ -3,6 +3,11 @@
- fix bug https://github.com/AriaLyy/Aria/issues/403 - fix bug https://github.com/AriaLyy/Aria/issues/403
- 新增ftp上传拦截器 https://github.com/AriaLyy/Aria/issues/402 - 新增ftp上传拦截器 https://github.com/AriaLyy/Aria/issues/402
- 重构线程任务模块 - 重构线程任务模块
- 修复一个低版本数据库升级的问题 https://github.com/AriaLyy/Aria/issues/407
- 新增遵循m3u8协议的文件下载
- 修复拦截器可能出现的空指针问题
- 移除`DownloadGroupEntity`字段`groupHash`的主键约束,`DownloadEntity`字段`groupHash`的外键约束,`TaskRecord`字段`dGroupHash`的外键约束
- 优化关联查询的性能
+ v_3.6.4 (2019/5/16) + v_3.6.4 (2019/5/16)
- 优化任务接收器的代码结构 - 优化任务接收器的代码结构
- 修复`DbEntity.saveAll()`失败的问题 - 修复`DbEntity.saveAll()`失败的问题

@ -34,7 +34,7 @@ public class M3U8VodModule extends BaseViewModule {
// m3u8测试集合:http://www.voidcn.com/article/p-snaliarm-ct.html // m3u8测试集合:http://www.voidcn.com/article/p-snaliarm-ct.html
//private final String defUrl = "https://www.gaoya123.cn/2019/1557993797897.m3u8"; //private final String defUrl = "https://www.gaoya123.cn/2019/1557993797897.m3u8";
// 多码率地址: // 多码率地址:
private final String defUrl = "http://ivi.bupt.edu.cn/hls/cctv6hd.m3u8"; private final String defUrl = "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8";
private final String filePath = private final String filePath =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath() Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()
+ "/1557993797897.ts"; + "/1557993797897.ts";

@ -73,6 +73,7 @@ final class FileListAdapter extends AbsRVAdapter<FileListEntity, FileListAdapter
.setSubFileName(Arrays.asList(item.names)) .setSubFileName(Arrays.asList(item.names))
.setDirPath(item.downloadPath) .setDirPath(item.downloadPath)
.setGroupAlias(item.name) .setGroupAlias(item.name)
.unknownSize()
.start(); .start();
} else { } else {
Aria.download(getContext()) Aria.download(getContext())

@ -136,6 +136,9 @@ public class MultiTaskActivity extends BaseActivity<ActivityMultiBinding> {
} }
@DownloadGroup.onTaskFail void groupTaskFail(DownloadGroupTask task) { @DownloadGroup.onTaskFail void groupTaskFail(DownloadGroupTask task) {
if (task == null){
return;
}
mAdapter.updateBtState(task.getKey(), true); mAdapter.updateBtState(task.getKey(), true);
Log.d(TAG, String.format("group【%s】fail", task.getTaskName())); Log.d(TAG, String.format("group【%s】fail", task.getTaskName()));
} }

Loading…
Cancel
Save