移除`DownloadGroupEntity`字段`groupHash`的主键约束,`DownloadEntity`字段`groupHash`的外键约束,`TaskRecord`字段`dGroupHash`的外键约束 优化关联查询的性能
This commit is contained in:
@@ -15,9 +15,8 @@
|
||||
*/
|
||||
package com.arialyy.aria.core.common;
|
||||
|
||||
import android.content.Context;
|
||||
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.AbsTaskWrapper;
|
||||
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.CommonUtil;
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -40,10 +37,9 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
protected IEventListener mListener;
|
||||
protected TASK_WRAPPER mTaskWrapper;
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -58,7 +54,6 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
mListener = listener;
|
||||
mTaskWrapper = wrapper;
|
||||
mEntity = mTaskWrapper.getEntity();
|
||||
mContext = AriaManager.APP;
|
||||
TAG = CommonUtil.getClassName(getClass());
|
||||
}
|
||||
|
||||
@@ -82,7 +77,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
return mEntity;
|
||||
}
|
||||
|
||||
public Map<Integer, AbsThreadTask> getTaskList() {
|
||||
public SparseArray<AbsThreadTask> getTaskList() {
|
||||
return mTask;
|
||||
}
|
||||
|
||||
@@ -92,10 +87,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
private void resetState() {
|
||||
closeTimer();
|
||||
if (mTask != null && mTask.size() != 0) {
|
||||
for (AbsThreadTask task : mTask.values()) {
|
||||
if (task != null) {
|
||||
task.breakTask();
|
||||
}
|
||||
for (int i = 0; i < mTask.size(); i++) {
|
||||
mTask.valueAt(i).breakTask();
|
||||
}
|
||||
mTask.clear();
|
||||
}
|
||||
@@ -152,10 +145,9 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
|| mStateManager.isStop()
|
||||
|| mStateManager.isCancel()
|
||||
|| mStateManager.isFail()
|
||||
|| !isRunning()) {
|
||||
if (mStateManager.isComplete() || mStateManager.isFail()) {
|
||||
ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey());
|
||||
}
|
||||
|| !isRunning()
|
||||
|| isBreak()) {
|
||||
ThreadTaskManager.getInstance().removeTaskThread(mTaskWrapper.getKey());
|
||||
closeTimer();
|
||||
} else if (mStateManager.getCurrentProgress() >= 0) {
|
||||
mListener.onProgress(mStateManager.getCurrentProgress());
|
||||
@@ -209,7 +201,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
closeTimer();
|
||||
isCancel = true;
|
||||
onCancel();
|
||||
for (AbsThreadTask task : mTask.values()) {
|
||||
for (int i = 0; i < mTask.size(); i++) {
|
||||
AbsThreadTask task = mTask.valueAt(i);
|
||||
if (task != null && !task.isThreadComplete()) {
|
||||
task.cancel();
|
||||
}
|
||||
@@ -229,7 +222,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER ext
|
||||
isStop = true;
|
||||
onStop();
|
||||
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()) {
|
||||
task.stop();
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.arialyy.aria.core.manager.ThreadTaskManager;
|
||||
import com.arialyy.aria.exception.BaseException;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.ErrorHelp;
|
||||
import com.arialyy.aria.util.NetUtils;
|
||||
import java.io.File;
|
||||
@@ -197,6 +198,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
|
||||
void sendState(int state, @Nullable Bundle bundle) {
|
||||
Message msg = mStateHandler.obtainMessage();
|
||||
msg.what = state;
|
||||
msg.obj = this;
|
||||
if (bundle != null) {
|
||||
msg.setData(bundle);
|
||||
}
|
||||
@@ -242,7 +244,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
|
||||
blockFile.delete();
|
||||
ALog.i(TAG, String.format("删除分块【%s】成功", blockFile.getName()));
|
||||
}
|
||||
retryThis(isBreak());
|
||||
retryBlockTask(isBreak());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -316,7 +318,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
|
||||
* @param subCurrentLocation 当前线程下载进度
|
||||
* @param ex 异常信息
|
||||
*/
|
||||
protected void fail(final long subCurrentLocation, BaseException ex) {
|
||||
protected void fail(long subCurrentLocation, BaseException ex) {
|
||||
fail(subCurrentLocation, ex, true);
|
||||
}
|
||||
|
||||
@@ -331,10 +333,11 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
|
||||
}
|
||||
if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_VOD) {
|
||||
writeConfig(false, 0);
|
||||
retryM3U8Peer(needRetry);
|
||||
} else {
|
||||
if (mTaskWrapper.isSupportBP()) {
|
||||
writeConfig(false, subCurrentLocation);
|
||||
retryThis(needRetry && mConfig.startThreadNum != 1);
|
||||
retryBlockTask(needRetry && mConfig.startThreadNum != 1);
|
||||
} else {
|
||||
ALog.e(TAG, String.format("任务【%s】执行失败", getFileName()));
|
||||
ErrorHelp.saveError(TAG, "", ALog.getExceptionString(ex));
|
||||
@@ -344,30 +347,53 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_WRAPPER
|
||||
}
|
||||
|
||||
/**
|
||||
* 重试当前线程,如果其中一条线程已经下载失败,则任务该任务下载失败,并且停止该任务的所有线程
|
||||
*
|
||||
* @param needRetry 是否可以重试
|
||||
* 重试ts分片
|
||||
*/
|
||||
private void retryThis(boolean needRetry) {
|
||||
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++;
|
||||
handleRetryRecord();
|
||||
ThreadTaskManager.getInstance().retryThread(AbsThreadTask.this);
|
||||
mConfig.tempFile.delete();
|
||||
CommonUtil.createFile(mConfig.tempFile.getPath());
|
||||
ThreadTaskManager.getInstance().retryThread(this);
|
||||
} else {
|
||||
sendFailMsg(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理线程重试的记录,只有多线程任务才会执行
|
||||
* 重试分块线程,如果其中一条线程已经下载失败,则任务该任务下载失败,并且停止该任务的所有线程
|
||||
*
|
||||
* @param needRetry 是否可以重试
|
||||
*/
|
||||
private void retryBlockTask(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++;
|
||||
handleBlockRecord();
|
||||
ThreadTaskManager.getInstance().retryThread(this);
|
||||
} else {
|
||||
sendFailMsg(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理线程重试的分块记录,只有多线程任务才会执行
|
||||
* 如果是以前版本{@link BufferedRandomAccessFile}创建的下载,那么 record.startLocation不用修改
|
||||
*/
|
||||
private void handleRetryRecord() {
|
||||
private void handleBlockRecord() {
|
||||
if (mConfig.isBlock) {
|
||||
// 默认线程分块长度
|
||||
File temp = mConfig.tempFile;
|
||||
|
||||
@@ -35,7 +35,7 @@ import com.arialyy.aria.util.RecordUtil;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
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 {
|
||||
protected static String TAG;
|
||||
private static final int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度
|
||||
|
||||
@@ -55,7 +55,8 @@ public abstract class NormalFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER
|
||||
*/
|
||||
@Override
|
||||
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) {
|
||||
task.setMaxSpeed(maxSpeed / mStartThreadNum);
|
||||
}
|
||||
@@ -168,8 +169,9 @@ public abstract class NormalFileer<ENTITY extends AbsNormalEntity, TASK_WRAPPER
|
||||
} else {
|
||||
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;
|
||||
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.orm.ActionPolicy;
|
||||
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.NoNull;
|
||||
import com.arialyy.aria.orm.annotation.Primary;
|
||||
import com.arialyy.aria.orm.annotation.Unique;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -44,7 +41,7 @@ public class TaskRecord extends DbEntity {
|
||||
/**
|
||||
* 任务文件路径
|
||||
*/
|
||||
@Primary
|
||||
@Unique
|
||||
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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.arialyy.aria.core.inf.AbsTarget;
|
||||
import com.arialyy.aria.core.inf.AbsTaskWrapper;
|
||||
import com.arialyy.aria.core.inf.IHttpFileLenAdapter;
|
||||
import com.arialyy.aria.core.inf.IHttpHeaderDelegate;
|
||||
import com.arialyy.aria.core.inf.ITargetHandler;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import java.net.Proxy;
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -78,17 +78,15 @@ abstract class AbsGroupConfigHandler<TARGET extends AbsDGTarget> implements IGro
|
||||
ALog.d(TAG, String.format("修改新路径为:%s", newDirPath));
|
||||
List<DTaskWrapper> subTasks = mWrapper.getSubTaskWrapper();
|
||||
if (subTasks != null && !subTasks.isEmpty()) {
|
||||
List<DownloadEntity> des = new ArrayList<>();
|
||||
for (DTaskWrapper dte : subTasks) {
|
||||
DownloadEntity de = dte.getEntity();
|
||||
String oldPath = de.getDownloadPath();
|
||||
String oldPath = de.getFilePath();
|
||||
String newPath = newDirPath + "/" + de.getFileName();
|
||||
File file = new File(oldPath);
|
||||
if (file.exists()) {
|
||||
file.renameTo(new File(newPath));
|
||||
}
|
||||
de.setDownloadPath(newPath);
|
||||
des.add(de);
|
||||
de.setFilePath(newPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,12 +101,18 @@ abstract class AbsGroupConfigHandler<TARGET extends AbsDGTarget> implements IGro
|
||||
ALog.e(TAG, "文件夹路径不能为null");
|
||||
return false;
|
||||
} else if (!mDirPathTemp.startsWith("/")) {
|
||||
ALog.e(TAG, "文件夹路径【" + mDirPathTemp + "】错误");
|
||||
ALog.e(TAG, String.format("文件夹路径【%s】错误", mDirPathTemp));
|
||||
return false;
|
||||
}
|
||||
File file = new File(mDirPathTemp);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,7 @@ import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.inf.AbsNormalEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTaskWrapper;
|
||||
import com.arialyy.aria.orm.ActionPolicy;
|
||||
import com.arialyy.aria.orm.annotation.Foreign;
|
||||
import com.arialyy.aria.orm.annotation.Primary;
|
||||
import com.arialyy.aria.orm.annotation.Unique;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
|
||||
/**
|
||||
@@ -31,13 +29,11 @@ import com.arialyy.aria.util.CommonUtil;
|
||||
* 下载实体
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,7 +32,7 @@ import com.arialyy.aria.util.CheckUtil;
|
||||
* 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) {
|
||||
mTaskWrapper = taskWrapper;
|
||||
|
||||
@@ -32,7 +32,7 @@ import com.arialyy.aria.core.scheduler.ISchedulers;
|
||||
* 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";
|
||||
|
||||
private DownloadTask(DTaskWrapper taskWrapper, Handler outHandler) {
|
||||
@@ -40,7 +40,6 @@ public class DownloadTask extends AbsNormalTask<DownloadEntity, DTaskWrapper> {
|
||||
mOutHandler = outHandler;
|
||||
mContext = AriaManager.APP;
|
||||
mListener = new BaseDListener(this, mOutHandler);
|
||||
mEntity = taskWrapper.getEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,7 +56,7 @@ public class DownloadTask extends AbsNormalTask<DownloadEntity, DTaskWrapper> {
|
||||
* 获取文件保存路径
|
||||
*/
|
||||
public String getFilePath() {
|
||||
return mEntity.getFilePath();
|
||||
return mTaskWrapper.getEntity().getFilePath();
|
||||
}
|
||||
|
||||
public DownloadEntity getEntity() {
|
||||
@@ -70,7 +69,7 @@ public class DownloadTask extends AbsNormalTask<DownloadEntity, DTaskWrapper> {
|
||||
* @see DownloadTask#getKey()
|
||||
*/
|
||||
@Deprecated public String getDownloadUrl() {
|
||||
return mEntity.getUrl();
|
||||
return mTaskWrapper.getEntity().getUrl();
|
||||
}
|
||||
|
||||
@Override public int getTaskType() {
|
||||
@@ -78,15 +77,15 @@ public class DownloadTask extends AbsNormalTask<DownloadEntity, DTaskWrapper> {
|
||||
}
|
||||
|
||||
@Override public String getKey() {
|
||||
return mEntity.getUrl();
|
||||
return mTaskWrapper.getEntity().getUrl();
|
||||
}
|
||||
|
||||
public DownloadEntity getDownloadEntity() {
|
||||
return mEntity;
|
||||
return mTaskWrapper.getEntity();
|
||||
}
|
||||
|
||||
@Override public String getTaskName() {
|
||||
return mEntity.getFileName();
|
||||
return mTaskWrapper.getEntity().getFileName();
|
||||
}
|
||||
|
||||
@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.inf.AbsTarget;
|
||||
import com.arialyy.aria.core.inf.AbsTaskWrapper;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
|
||||
/**
|
||||
* m3u8直播参数设置
|
||||
@@ -40,4 +41,18 @@ public class M3U8LiveDelegate<TARGET extends AbsTarget> extends BaseDelegate<TAR
|
||||
((DTaskWrapper) mTarget.getTaskWrapper()).asM3U8().setLiveTsUrlConverter(converter);
|
||||
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.inf.AbsEntity;
|
||||
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.M3U8Exception;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
@@ -42,7 +43,6 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
public class M3U8LiveDownloadUtil implements IUtil {
|
||||
private final String TAG = "M3U8LiveDownloadUtil";
|
||||
|
||||
private DTaskWrapper mWrapper;
|
||||
private IDownloadListener mListener;
|
||||
private boolean isStop = false, isCancel = false;
|
||||
@@ -50,6 +50,7 @@ public class M3U8LiveDownloadUtil implements IUtil {
|
||||
private M3U8InfoThread mInfoThread;
|
||||
private ScheduledThreadPoolExecutor mTimer;
|
||||
private ExecutorService mInfoPool = Executors.newCachedThreadPool();
|
||||
private List<String> mPeerUrls = new ArrayList<>();
|
||||
|
||||
public M3U8LiveDownloadUtil(DTaskWrapper wrapper, IDownloadListener listener) {
|
||||
mWrapper = wrapper;
|
||||
@@ -86,6 +87,7 @@ public class M3U8LiveDownloadUtil implements IUtil {
|
||||
*/
|
||||
@Override public void stop() {
|
||||
isStop = true;
|
||||
mLoader.stop();
|
||||
handleComplete();
|
||||
}
|
||||
|
||||
@@ -122,7 +124,7 @@ public class M3U8LiveDownloadUtil implements IUtil {
|
||||
mInfoThread = (M3U8InfoThread) getLiveInfo();
|
||||
mInfoPool.execute(mInfoThread);
|
||||
}
|
||||
}, 0, 1000, TimeUnit.MILLISECONDS);
|
||||
}, 0, mWrapper.asM3U8().getLiveUpdateInterval(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void closeTimer() {
|
||||
@@ -150,6 +152,10 @@ public class M3U8LiveDownloadUtil implements IUtil {
|
||||
});
|
||||
infoThread.setOnGetPeerCallback(new M3U8InfoThread.OnGetLivePeerCallback() {
|
||||
@Override public void onGetPeer(String url) {
|
||||
if (mPeerUrls.contains(url)) {
|
||||
return;
|
||||
}
|
||||
mPeerUrls.add(url);
|
||||
ILiveTsUrlConverter converter = mWrapper.asM3U8().getLiveTsUrlConverter();
|
||||
if (converter != null) {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
//todo url 需要去重
|
||||
mLoader.offerPeer(url);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -100,7 +100,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
}
|
||||
|
||||
@Override protected void setMaxSpeed(int maxSpeed) {
|
||||
// TODO: 2019-06-06 展不支持
|
||||
// TODO: 2019-06-06 暂不支持
|
||||
}
|
||||
|
||||
private void notifyLock() {
|
||||
@@ -199,7 +199,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
}
|
||||
|
||||
/**
|
||||
* M3U8线程状态管理
|
||||
* M3U8线程状态管理,直播不处理停止状态、删除、失败的状态
|
||||
*/
|
||||
private class LiveStateManager implements IThreadState {
|
||||
private final String TAG = "M3U8ThreadStateManager";
|
||||
@@ -208,8 +208,6 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
* 任务状态回调
|
||||
*/
|
||||
private IEventListener mListener;
|
||||
private int mCancelNum = 0; // 已经取消的线程的数
|
||||
private int mStopNum = 0; // 已经停止的线程数
|
||||
private long mProgress; //当前总进度
|
||||
private Looper mLooper;
|
||||
|
||||
@@ -232,7 +230,6 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
@Override public boolean handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case STATE_STOP:
|
||||
mStopNum++;
|
||||
if (isStop()) {
|
||||
ALog.d(TAG, "任务停止");
|
||||
mListener.onStop(mProgress);
|
||||
@@ -240,7 +237,6 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
}
|
||||
break;
|
||||
case STATE_CANCEL:
|
||||
mCancelNum++;
|
||||
if (isCancel()) {
|
||||
ALog.d(TAG, "任务取消");
|
||||
mListener.onCancel();
|
||||
@@ -258,23 +254,18 @@ public class M3U8LiveLoader extends BaseM3U8Loader {
|
||||
}
|
||||
|
||||
@Override public boolean isStop() {
|
||||
// 某些服务器后一次性发送多个ts地址,所以不能简单使用mStopNum == mFlagQueue.size();判断状态
|
||||
//return mStopNum == mFlagQueue.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean isFail() {
|
||||
// 直播下载不处理失败的切片
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean isComplete() {
|
||||
// 直播不处理完成
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean isCancel() {
|
||||
//return mCancelNum == mFlagQueue.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,19 @@ public class M3U8TaskConfig {
|
||||
*/
|
||||
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() {
|
||||
return liveTsUrlConverter;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import com.arialyy.aria.core.common.AbsThreadTask;
|
||||
import com.arialyy.aria.core.common.IThreadState;
|
||||
import com.arialyy.aria.core.common.SubThreadConfig;
|
||||
import com.arialyy.aria.core.common.TaskRecord;
|
||||
@@ -200,6 +201,8 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
switch (msg.what) {
|
||||
case STATE_STOP:
|
||||
mStopNum++;
|
||||
ThreadTaskManager.getInstance().removeSingleTaskThread(mTaskWrapper.getKey(),
|
||||
(AbsThreadTask) msg.obj);
|
||||
if (isStop()) {
|
||||
ALog.d(TAG, "任务停止");
|
||||
mListener.onStop(mProgress);
|
||||
@@ -208,6 +211,8 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
break;
|
||||
case STATE_CANCEL:
|
||||
mCancelNum++;
|
||||
ThreadTaskManager.getInstance().removeSingleTaskThread(mTaskWrapper.getKey(),
|
||||
(AbsThreadTask) msg.obj);
|
||||
if (isCancel()) {
|
||||
ALog.d(TAG, "任务取消");
|
||||
mListener.onCancel();
|
||||
@@ -225,6 +230,8 @@ public class M3U8VodLoader extends BaseM3U8Loader {
|
||||
break;
|
||||
case STATE_COMPLETE:
|
||||
mCompleteNum++;
|
||||
ThreadTaskManager.getInstance().removeSingleTaskThread(mTaskWrapper.getKey(),
|
||||
(AbsThreadTask) msg.obj);
|
||||
handlerPercent();
|
||||
notifyLock();
|
||||
if (isComplete()) {
|
||||
|
||||
@@ -17,7 +17,7 @@ package com.arialyy.aria.core.inf;
|
||||
|
||||
import android.os.Parcel;
|
||||
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.List;
|
||||
|
||||
@@ -28,7 +28,7 @@ public abstract class AbsGroupEntity extends AbsEntity implements Parcelable {
|
||||
/**
|
||||
* 组名,组名为任务地址相加的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地址
|
||||
|
||||
@@ -21,8 +21,8 @@ import com.arialyy.aria.core.download.group.AbsGroupUtil;
|
||||
* Created by AriaL on 2017/6/29.
|
||||
* 任务组任务抽象类
|
||||
*/
|
||||
public abstract class AbsGroupTask<ENTITY extends AbsEntity, TASK_ENTITY extends AbsGroupTaskWrapper>
|
||||
extends AbsTask<ENTITY, TASK_ENTITY> {
|
||||
public abstract class AbsGroupTask<TASK_ENTITY extends AbsGroupTaskWrapper>
|
||||
extends AbsTask<TASK_ENTITY> {
|
||||
|
||||
@Override public String getKey() {
|
||||
return mTaskWrapper.getEntity().getKey();
|
||||
|
||||
@@ -18,8 +18,8 @@ package com.arialyy.aria.core.inf;
|
||||
/**
|
||||
* Created by lyy on 2017/6/3.
|
||||
*/
|
||||
public abstract class AbsNormalTask<ENTITY extends AbsEntity, TASK_WRAPPER extends AbsTaskWrapper>
|
||||
extends AbsTask<ENTITY, TASK_WRAPPER> {
|
||||
public abstract class AbsNormalTask<TASK_WRAPPER extends AbsTaskWrapper>
|
||||
extends AbsTask<TASK_WRAPPER> {
|
||||
|
||||
/**
|
||||
* 最高优先级命令,最高优先级命令有以下属性
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.Map;
|
||||
/**
|
||||
* 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> {
|
||||
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
|
||||
private int mSchedulerType = TaskSchedulerType.TYPE_DEFAULT;
|
||||
protected IEventListener mListener;
|
||||
protected ENTITY mEntity;
|
||||
protected String TAG;
|
||||
|
||||
protected AbsTask() {
|
||||
@@ -165,7 +164,7 @@ public abstract class AbsTask<ENTITY extends AbsEntity, TASK_WRAPPER extends Abs
|
||||
* @return 返回百分比进度,如果文件长度为0,返回0
|
||||
*/
|
||||
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();
|
||||
} else {
|
||||
ALog.d(TAG, "下载任务未执行");
|
||||
mListener.onStop(mEntity.getCurrentProgress());
|
||||
mListener.onStop(mTaskWrapper.getEntity().getCurrentProgress());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,6 @@ public class ThreadTaskManager {
|
||||
*/
|
||||
public void removeTaskThread(String key) {
|
||||
try {
|
||||
|
||||
LOCK.tryLock(2, TimeUnit.SECONDS);
|
||||
if (mExePool.isShutdown()) {
|
||||
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.UTaskWrapper;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -34,7 +35,7 @@ import java.util.Map;
|
||||
class DBConfig {
|
||||
/*adb pull /mnt/sdcard/Android/data/com.arialyy.simple/files/DB/AriaLyyDb d:/db*/
|
||||
static boolean DEBUG = false;
|
||||
static Map<String, Class> mapping = new HashMap<>();
|
||||
static Map<String, Class> mapping = new LinkedHashMap<>();
|
||||
static String DB_NAME;
|
||||
static int VERSION = 48;
|
||||
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.SparseArray;
|
||||
import com.arialyy.aria.orm.annotation.Many;
|
||||
import com.arialyy.aria.orm.annotation.One;
|
||||
import com.arialyy.aria.orm.annotation.Wrapper;
|
||||
@@ -29,9 +29,8 @@ import com.arialyy.aria.util.CommonUtil;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -127,11 +126,11 @@ class DelegateFind extends AbsDelegate {
|
||||
* @param page 当前页
|
||||
* @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) {
|
||||
db = checkDb(db);
|
||||
if (SqlUtil.isWrapper(clazz)) {
|
||||
Field[] om = getOneAndManyField(clazz);
|
||||
if (SqlUtil.isWrapper(wrapperClazz)) {
|
||||
Field[] om = getOneAndManyField(wrapperClazz);
|
||||
if (om == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -145,8 +144,6 @@ class DelegateFind extends AbsDelegate {
|
||||
final String cTableName = childClazz.getSimpleName();
|
||||
List<Field> pColumn = SqlUtil.getAllNotIgnoreField(parentClazz);
|
||||
List<Field> cColumn = SqlUtil.getAllNotIgnoreField(childClazz);
|
||||
List<String> pColumnAlias = new ArrayList<>();
|
||||
List<String> cColumnAlias = new ArrayList<>();
|
||||
StringBuilder pSb = 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,"));
|
||||
for (Field f : pColumn) {
|
||||
String temp = PARENT_COLUMN_ALIAS.concat(f.getName());
|
||||
pColumnAlias.add(temp);
|
||||
pSb.append(pTableName.concat(".").concat(f.getName()))
|
||||
.append(" AS ")
|
||||
.append(temp)
|
||||
@@ -166,7 +162,6 @@ class DelegateFind extends AbsDelegate {
|
||||
pSb.append(cTableName.concat(".rowid AS ").concat(CHILD_COLUMN_ALIAS).concat("rowid,"));
|
||||
for (Field f : cColumn) {
|
||||
String temp = CHILD_COLUMN_ALIAS.concat(f.getName());
|
||||
cColumnAlias.add(temp);
|
||||
cSb.append(cTableName.concat(".").concat(f.getName()))
|
||||
.append(" AS ")
|
||||
.append(temp)
|
||||
@@ -223,8 +218,7 @@ class DelegateFind extends AbsDelegate {
|
||||
}
|
||||
Cursor cursor = db.rawQuery(sql, null);
|
||||
List<T> data =
|
||||
(List<T>) newInstanceEntity(clazz, parentClazz, childClazz, cursor, pColumn, cColumn,
|
||||
pColumnAlias, cColumnAlias);
|
||||
newInstanceEntity(wrapperClazz, parentClazz, childClazz, cursor, pColumn, cColumn);
|
||||
closeCursor(cursor);
|
||||
return data;
|
||||
} catch (ClassNotFoundException e) {
|
||||
@@ -242,139 +236,84 @@ class DelegateFind extends AbsDelegate {
|
||||
*
|
||||
* @param pColumn 父表的所有字段
|
||||
* @param cColumn 字表的所有字段
|
||||
* @param pColumnAlias 关联查询父表别名
|
||||
* @param cColumnAlias 关联查询子表别名
|
||||
*/
|
||||
private synchronized <T extends AbsDbWrapper, P extends DbEntity, C extends DbEntity> List<T> newInstanceEntity(
|
||||
Class<T> clazz, Class<P> parent,
|
||||
Class<C> child,
|
||||
Class<T> wrapperClazz, Class<P> parentClazz,
|
||||
Class<C> childClazz,
|
||||
Cursor cursor,
|
||||
List<Field> pColumn, List<Field> cColumn,
|
||||
List<String> pColumnAlias, List<String> cColumnAlias) {
|
||||
List<Field> pColumn, List<Field> cColumn) {
|
||||
List<T> wrappers = new ArrayList<>();
|
||||
SparseArray<List<DbEntity>> childs = new SparseArray<>(); // 所有子表数据
|
||||
SparseArray<DbEntity> parents = new SparseArray<>(); // 所有父表数据
|
||||
|
||||
try {
|
||||
String parentPrimary = ""; //父表主键别名
|
||||
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;
|
||||
while (cursor.moveToNext()) {
|
||||
//创建父实体
|
||||
Object ppValue = setPPValue(parentPrimary, cursor);
|
||||
if (old == null || ppValue != old) { //当主键不同时,表示是不同的父表数据
|
||||
old = ppValue;
|
||||
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);
|
||||
}
|
||||
int pRowId = cursor.getInt(cursor.getColumnIndex(PARENT_COLUMN_ALIAS.concat("rowid")));
|
||||
if (childs.get(pRowId) == null) {
|
||||
childs.put(pRowId, new ArrayList<DbEntity>());
|
||||
parents.put(pRowId, createParent(pRowId, parentClazz, pColumn, cursor));
|
||||
}
|
||||
|
||||
// 创建子实体
|
||||
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等于主键
|
||||
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);
|
||||
childs.get(pRowId).add(createChild(childClazz, cColumn, cursor));
|
||||
}
|
||||
|
||||
List<Field> wFields = SqlUtil.getAllNotIgnoreField(clazz);
|
||||
if (wFields != null && !wFields.isEmpty()) {
|
||||
Set<Object> pKeys = tempParent.keySet();
|
||||
for (Object pk : pKeys) {
|
||||
T wrapper = clazz.newInstance();
|
||||
P p = tempParent.get(pk);
|
||||
boolean isPSet = false, isCSet = false;
|
||||
for (Field f : wFields) {
|
||||
if (!isPSet && f.getAnnotation(One.class) != null) {
|
||||
f.set(wrapper, p);
|
||||
isPSet = true;
|
||||
}
|
||||
if (!isCSet && f.getAnnotation(Many.class) != null) {
|
||||
f.set(wrapper, tempChild.get(pk));
|
||||
isCSet = true;
|
||||
}
|
||||
}
|
||||
wrapper.handleConvert(); //处理下转换
|
||||
wrappers.add(wrapper);
|
||||
}
|
||||
List<Field> wFields = SqlUtil.getAllNotIgnoreField(wrapperClazz);
|
||||
if (wFields == null || wFields.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return wrappers;
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
for (int i = 0; i < parents.size(); i++) {
|
||||
int pRowId = parents.keyAt(i);
|
||||
T wrapper = wrapperClazz.newInstance();
|
||||
boolean isPSet = false, isCSet = false; // 保证One 或 Many 只设置一次
|
||||
for (Field f : wFields) {
|
||||
if (!isPSet && f.getAnnotation(One.class) != null) {
|
||||
f.set(wrapper, parents.get(pRowId));
|
||||
isPSet = true;
|
||||
}
|
||||
if (!isCSet && f.getAnnotation(Many.class) != null) {
|
||||
f.set(wrapper, childs.get(pRowId));
|
||||
isCSet = true;
|
||||
}
|
||||
}
|
||||
wrapper.handleConvert(); //处理下转换
|
||||
wrappers.add(wrapper);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
|
||||
return wrappers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取父表主键数据
|
||||
*
|
||||
* @param parentPrimary 父表主键别名
|
||||
* 创建子对象
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB) private Object setPPValue(String parentPrimary,
|
||||
Cursor cursor) {
|
||||
Object ppValue = null;
|
||||
int ppColumn = cursor.getColumnIndex(parentPrimary); //父表主键所在的列
|
||||
int type = cursor.getType(ppColumn);
|
||||
switch (type) {
|
||||
case Cursor.FIELD_TYPE_INTEGER:
|
||||
ppValue = cursor.getLong(ppColumn);
|
||||
break;
|
||||
case Cursor.FIELD_TYPE_FLOAT:
|
||||
ppValue = cursor.getFloat(ppColumn);
|
||||
break;
|
||||
case Cursor.FIELD_TYPE_STRING:
|
||||
ppValue = cursor.getString(ppColumn);
|
||||
break;
|
||||
private <T extends DbEntity> T createChild(Class<T> childClazz, List<Field> cColumn,
|
||||
Cursor cursor)
|
||||
throws InstantiationException, IllegalAccessException {
|
||||
T child = childClazz.newInstance();
|
||||
child.rowID = cursor.getInt(cursor.getColumnIndex(CHILD_COLUMN_ALIAS.concat("rowid")));
|
||||
for (Field field : cColumn) {
|
||||
field.setAccessible(true);
|
||||
int columnIndex = cursor.getColumnIndex(CHILD_COLUMN_ALIAS.concat(field.getName()));
|
||||
setFieldValue(field.getType(), field, columnIndex, cursor, child);
|
||||
}
|
||||
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[] temp = new String[selectionArgs.length];
|
||||
int i = 0;
|
||||
for (String arg : selectionArgs){
|
||||
for (String arg : selectionArgs) {
|
||||
temp[i] = encodeStr(arg);
|
||||
i ++;
|
||||
i++;
|
||||
}
|
||||
Cursor cursor = db.rawQuery(sql, temp);
|
||||
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
|
||||
@@ -525,43 +464,44 @@ class DelegateFind extends AbsDelegate {
|
||||
*
|
||||
* @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 {
|
||||
if (cursor == null || cursor.isClosed()) {
|
||||
ALog.e(TAG, "cursor没有初始化");
|
||||
return;
|
||||
}
|
||||
if (type == String.class) {
|
||||
String temp = cursor.getString(column);
|
||||
String temp = cursor.getString(columnIndex);
|
||||
if (!TextUtils.isEmpty(temp)) {
|
||||
field.set(entity, URLDecoder.decode(temp));
|
||||
}
|
||||
} 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) {
|
||||
field.setFloat(entity, cursor.getFloat(column));
|
||||
field.setFloat(entity, cursor.getFloat(columnIndex));
|
||||
} 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) {
|
||||
field.setLong(entity, cursor.getLong(column));
|
||||
field.setLong(entity, cursor.getLong(columnIndex));
|
||||
} else if (type == boolean.class || type == Boolean.class) {
|
||||
String temp = cursor.getString(column);
|
||||
String temp = cursor.getString(columnIndex);
|
||||
if (TextUtils.isEmpty(temp)) {
|
||||
field.setBoolean(entity, false);
|
||||
} else {
|
||||
field.setBoolean(entity, !temp.equalsIgnoreCase("false"));
|
||||
}
|
||||
} 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) {
|
||||
field.set(entity, cursor.getBlob(column));
|
||||
field.set(entity, cursor.getBlob(columnIndex));
|
||||
} else if (type == Map.class) {
|
||||
String temp = cursor.getString(column);
|
||||
String temp = cursor.getString(columnIndex);
|
||||
if (!TextUtils.isEmpty(temp)) {
|
||||
field.set(entity, SqlUtil.str2Map(URLDecoder.decode(temp)));
|
||||
}
|
||||
} else if (type == List.class) {
|
||||
String value = cursor.getString(column);
|
||||
String value = cursor.getString(columnIndex);
|
||||
if (!TextUtils.isEmpty(value)) {
|
||||
field.set(entity, SqlUtil.str2List(URLDecoder.decode(value), field));
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理数据库升级,该段代码无法修改表字段
|
||||
* 处理数据库升级
|
||||
*
|
||||
* @param modifyColumns 需要修改的表字段的映射,key为表名,
|
||||
* value{@code Map<String, String>}中的Map的key为老字段名称,value为该老字段对应的新字段名称
|
||||
@@ -176,8 +176,9 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
long count = cursor.getLong(0);
|
||||
cursor.close();
|
||||
|
||||
// 复制数据
|
||||
if (count > 0) {
|
||||
// 获取所有表字段名称
|
||||
// 获取旧表的所有字段名称
|
||||
Cursor columnC =
|
||||
db.rawQuery(String.format("PRAGMA table_info(%s_temp)", tableName), null);
|
||||
StringBuilder params = new StringBuilder();
|
||||
@@ -243,11 +244,17 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
mDelegate.dropTable(db, taskTable);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Map<String, String>> columnMap = new HashMap<>();
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("groupName", "groupHash");
|
||||
columnMap.put("DownloadEntity", map);
|
||||
columnMap.put("DownloadGroupEntity", map);
|
||||
// 处理DownloadEntity、DownloadGroupEntity的 groupName字段名的修改
|
||||
Map<String, String> groupNameModify = new HashMap<>();
|
||||
groupNameModify.put("groupName", "groupHash");
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -263,7 +270,7 @@ final class SqlHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
}
|
||||
|
||||
//删除所有主键为null和逐渐重复的数据
|
||||
//删除所有主键为null和主键重复的数据
|
||||
String[] tables = new String[] { "DownloadEntity", "DownloadGroupEntity" };
|
||||
String[] keys = new String[] { "downloadPath", "groupName" };
|
||||
int i = 0;
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
- fix bug https://github.com/AriaLyy/Aria/issues/403
|
||||
- 新增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)
|
||||
- 优化任务接收器的代码结构
|
||||
- 修复`DbEntity.saveAll()`失败的问题
|
||||
|
||||
@@ -34,7 +34,7 @@ public class M3U8VodModule extends BaseViewModule {
|
||||
// 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 = "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 =
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()
|
||||
+ "/1557993797897.ts";
|
||||
|
||||
@@ -73,6 +73,7 @@ final class FileListAdapter extends AbsRVAdapter<FileListEntity, FileListAdapter
|
||||
.setSubFileName(Arrays.asList(item.names))
|
||||
.setDirPath(item.downloadPath)
|
||||
.setGroupAlias(item.name)
|
||||
.unknownSize()
|
||||
.start();
|
||||
} else {
|
||||
Aria.download(getContext())
|
||||
|
||||
@@ -136,6 +136,9 @@ public class MultiTaskActivity extends BaseActivity<ActivityMultiBinding> {
|
||||
}
|
||||
|
||||
@DownloadGroup.onTaskFail void groupTaskFail(DownloadGroupTask task) {
|
||||
if (task == null){
|
||||
return;
|
||||
}
|
||||
mAdapter.updateBtState(task.getKey(), true);
|
||||
Log.d(TAG, String.format("group【%s】fail", task.getTaskName()));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user