移除记录配置文件,改用数据库记录任务记录
This commit is contained in:
@@ -19,16 +19,17 @@ import android.content.Context;
|
||||
import android.util.SparseArray;
|
||||
import com.arialyy.aria.core.AriaManager;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||
import com.arialyy.aria.core.inf.AbsNormalEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||
import com.arialyy.aria.core.inf.IDownloadListener;
|
||||
import com.arialyy.aria.core.inf.IEventListener;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.upload.UploadTaskEntity;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
@@ -50,10 +51,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
|
||||
protected IEventListener mListener;
|
||||
protected TASK_ENTITY mTaskEntity;
|
||||
protected ENTITY mEntity;
|
||||
protected File mConfigFile;//信息配置文件
|
||||
protected Context mContext;
|
||||
protected File mTempFile; //文件
|
||||
protected boolean isNewTask = true;
|
||||
protected StateConstance mConstance;
|
||||
private ExecutorService mFixedThreadPool;
|
||||
//总线程数
|
||||
@@ -68,7 +67,13 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
|
||||
* 小于1m的文件不启用多线程
|
||||
*/
|
||||
private Timer mTimer;
|
||||
@Deprecated
|
||||
private File mConfigFile;
|
||||
/**
|
||||
* 进度刷新间隔
|
||||
*/
|
||||
private long mUpdateInterval = 1000;
|
||||
private TaskRecord mRecord;
|
||||
|
||||
protected AbsFileer(IEventListener listener, TASK_ENTITY taskEntity) {
|
||||
mListener = listener;
|
||||
@@ -104,19 +109,21 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
|
||||
private void startFlow() {
|
||||
mConstance.resetState();
|
||||
checkTask();
|
||||
mConstance.TASK_RECORD = mRecord;
|
||||
if (mListener instanceof IDownloadListener) {
|
||||
((IDownloadListener) mListener).onPostPre(mEntity.getFileSize());
|
||||
}
|
||||
if (!mTaskEntity.isSupportBP()) {
|
||||
mTotalThreadNum = 1;
|
||||
mStartThreadNum = 1;
|
||||
mConstance.THREAD_NUM = mTotalThreadNum;
|
||||
handleNoSupportBP();
|
||||
} else {
|
||||
mTotalThreadNum = isNewTask ? (mStartThreadNum = setNewTaskThreadNum()) : mStartThreadNum;
|
||||
mConstance.THREAD_NUM = mTotalThreadNum;
|
||||
// TODO: 2018/5/11 如果不是新任务,就有问题
|
||||
mTotalThreadNum =
|
||||
mTaskEntity.isNewTask() ? (mStartThreadNum = setNewTaskThreadNum()) : mTotalThreadNum;
|
||||
handleBreakpoint();
|
||||
}
|
||||
mConstance.START_THREAD_NUM = mTotalThreadNum;
|
||||
startTimer();
|
||||
}
|
||||
|
||||
@@ -193,13 +200,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
|
||||
task.cancel();
|
||||
}
|
||||
}
|
||||
if (mTaskEntity instanceof DownloadTaskEntity) {
|
||||
CommonUtil.delDownloadTaskConfig(mTaskEntity.isRemoveFile(),
|
||||
(DownloadEntity) mTaskEntity.getEntity());
|
||||
} else if (mTaskEntity instanceof UploadTaskEntity) {
|
||||
CommonUtil.delUploadTaskConfig(mTaskEntity.isRemoveFile(),
|
||||
(UploadEntity) mTaskEntity.getEntity());
|
||||
}
|
||||
CommonUtil.delTaskRecord(mRecord, mTaskEntity.isRemoveFile(), mTaskEntity.getEntity());
|
||||
}
|
||||
|
||||
@Override public void stop() {
|
||||
@@ -230,53 +231,127 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查任务是否是新任务,新任务条件:
|
||||
* 检查任务、检查线程数
|
||||
* 新任务条件:
|
||||
* 1、文件不存在
|
||||
* 2、下载记录文件不存在
|
||||
* 3、下载记录文件缺失或不匹配
|
||||
* 4、数据库记录不存在
|
||||
* 5、不支持断点,则是新任务
|
||||
* 2、下载记录文件缺失或不匹配
|
||||
* 3、数据库记录不存在
|
||||
* 4、不支持断点,则是新任务
|
||||
*/
|
||||
protected abstract void checkTask();
|
||||
protected void checkTask() {
|
||||
mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
|
||||
if (mConfigFile.exists()) {
|
||||
convertDb();
|
||||
} else {
|
||||
List<RecordWrapper> records =
|
||||
DbEntity.findRelationData(RecordWrapper.class, "TaskRecord.filePath=?",
|
||||
mTaskEntity.getKey());
|
||||
if (records == null || records.size() == 0) {
|
||||
initRecord();
|
||||
mTaskEntity.setNewTask(true);
|
||||
} else {
|
||||
mRecord = records.get(0).taskRecord;
|
||||
if (mRecord.threadRecords == null || mRecord.threadRecords.isEmpty()) {
|
||||
initRecord();
|
||||
mTaskEntity.setNewTask(true);
|
||||
} else {
|
||||
for (ThreadRecord tr : mRecord.threadRecords) {
|
||||
if (tr.isComplete) {
|
||||
mCompleteThreadNum++;
|
||||
} else {
|
||||
mStartThreadNum++;
|
||||
}
|
||||
}
|
||||
mTotalThreadNum = mRecord.threadRecords.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查记录文件,如果是新任务返回{@code true},否则返回{@code false}
|
||||
* convertDb 为兼容性代码
|
||||
* 从3.4.1开始,线程配置信息将存储在数据库中。
|
||||
* 将配置文件的内容复制到数据库中,并将配置文件删除
|
||||
*/
|
||||
protected boolean checkConfigFile() {
|
||||
mStartThreadNum = 0;
|
||||
mCompleteThreadNum = 0;
|
||||
Properties pro = CommonUtil.loadConfig(mConfigFile);
|
||||
if (pro.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
Set<Object> keys = pro.keySet();
|
||||
int num = 0;
|
||||
for (Object key : keys) {
|
||||
String str = String.valueOf(key);
|
||||
Object state = pro.getProperty(str);
|
||||
if (str.contains(RECORD)) {
|
||||
num++;
|
||||
} else if (state != null && str.contains(STATE) && Integer.parseInt(state + "") == 1) {
|
||||
int i = Integer.parseInt(str.substring(str.length() - 1, str.length()));
|
||||
if (pro.getProperty(mTempFile.getName() + RECORD + i) != null) {
|
||||
mCompleteThreadNum++;
|
||||
}
|
||||
private void convertDb() {
|
||||
List<RecordWrapper> records =
|
||||
DbEntity.findRelationData(RecordWrapper.class, "TaskRecord.filePath=?",
|
||||
mTaskEntity.getKey());
|
||||
if (records == null || records.size() == 0) {
|
||||
Properties pro = CommonUtil.loadConfig(mConfigFile);
|
||||
if (pro.isEmpty()) {
|
||||
mTaskEntity.setNewTask(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (num == 0) {
|
||||
return true;
|
||||
}
|
||||
mStartThreadNum = num;
|
||||
for (int i = 0; i < mStartThreadNum; i++) {
|
||||
if (pro.getProperty(mTempFile.getName() + RECORD + i) == null) {
|
||||
initRecord();
|
||||
Set<Object> keys = pro.keySet();
|
||||
// 老版本记录是5s存一次,但是5s中内,如果线程执行完成,record记录是没有的,只有state记录...
|
||||
// 第一步应该是record 和 state去重取正确的线程数
|
||||
Set<Integer> set = new HashSet<>();
|
||||
for (Object key : keys) {
|
||||
String str = String.valueOf(key);
|
||||
int i = Integer.parseInt(str.substring(str.length() - 1, str.length()));
|
||||
set.add(i);
|
||||
}
|
||||
int threadNum = set.size();
|
||||
if (threadNum == 0) {
|
||||
mTaskEntity.setNewTask(true);
|
||||
return;
|
||||
}
|
||||
mRecord.threadNum = threadNum;
|
||||
mTotalThreadNum = threadNum;
|
||||
|
||||
for (int i = 0; i < threadNum; i++) {
|
||||
ThreadRecord tRecord = new ThreadRecord();
|
||||
tRecord.key = mRecord.filePath;
|
||||
Object state = pro.getProperty(mTempFile.getName() + STATE + i);
|
||||
Object record = pro.getProperty(mTempFile.getName() + RECORD + i);
|
||||
if (state != null && Integer.parseInt(state + "") == 1) {
|
||||
mCompleteThreadNum++;
|
||||
tRecord.isComplete = true;
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
mStartThreadNum++;
|
||||
if (record != null) {
|
||||
Long temp = Long.parseLong(record + "");
|
||||
tRecord.startLocation = temp > 0 ? temp : 0;
|
||||
} else {
|
||||
tRecord.startLocation = 0;
|
||||
}
|
||||
mRecord.threadRecords.add(tRecord);
|
||||
}
|
||||
mConfigFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化记录
|
||||
*/
|
||||
private void initRecord() {
|
||||
mRecord = new TaskRecord();
|
||||
mRecord.fileName = mEntity.getFileName();
|
||||
mRecord.filePath = mTaskEntity.getKey();
|
||||
mRecord.threadRecords = new ArrayList<>();
|
||||
mRecord.isGroupRecord = mTaskEntity.getEntity().isGroupChild();
|
||||
if (mRecord.isGroupRecord) {
|
||||
if (mTaskEntity.getEntity() instanceof DownloadEntity) {
|
||||
mRecord.dGroupName = ((DownloadEntity) mTaskEntity.getEntity()).getGroupName();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存任务记录
|
||||
*/
|
||||
private void saveRecord() {
|
||||
mRecord.save();
|
||||
for (ThreadRecord tr : mRecord.threadRecords) {
|
||||
tr.save();
|
||||
}
|
||||
}
|
||||
|
||||
public TaskRecord getRecord() {
|
||||
return mRecord;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -291,9 +366,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
|
||||
mConstance.STOP_NUM++;
|
||||
mConstance.CANCEL_NUM++;
|
||||
if (mConstance.isComplete()) {
|
||||
if (mConfigFile.exists()) {
|
||||
mConfigFile.delete();
|
||||
}
|
||||
mRecord.deleteData();
|
||||
mListener.onComplete();
|
||||
mConstance.isRunning = false;
|
||||
return true;
|
||||
@@ -309,7 +382,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
|
||||
* @param endL 该任务结束位置
|
||||
* @param fileLength 该任务需要处理的文件长度
|
||||
*/
|
||||
private AbsThreadTask createSingThreadTask(int i, long startL, long endL, long fileLength) {
|
||||
private AbsThreadTask createSingThreadTask(int i, long startL, long endL, long fileLength,
|
||||
ThreadRecord record) {
|
||||
SubThreadConfig<TASK_ENTITY> config = new SubThreadConfig<>();
|
||||
config.FILE_SIZE = fileLength;
|
||||
config.URL = mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getUrl();
|
||||
@@ -317,66 +391,76 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
|
||||
config.THREAD_ID = i;
|
||||
config.START_LOCATION = startL;
|
||||
config.END_LOCATION = endL;
|
||||
config.CONFIG_FILE_PATH = mConfigFile.getPath();
|
||||
config.SUPPORT_BP = mTaskEntity.isSupportBP();
|
||||
config.TASK_ENTITY = mTaskEntity;
|
||||
config.THREAD_RECORD = record;
|
||||
return selectThreadTask(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理断点
|
||||
*/
|
||||
private void handleBreakpoint() {
|
||||
long fileLength = mEntity.getFileSize();
|
||||
Properties pro = CommonUtil.loadConfig(mConfigFile);
|
||||
long blockSize = fileLength / mTotalThreadNum;
|
||||
int[] recordL = new int[mTotalThreadNum];
|
||||
for (int i = 0; i < mTotalThreadNum; i++) {
|
||||
recordL[i] = -1;
|
||||
}
|
||||
int[] threadId = new int[mTotalThreadNum];
|
||||
int rl = 0;
|
||||
if (isNewTask && !handleNewTask()) {
|
||||
|
||||
mRecord.fileLength = fileLength;
|
||||
for (int i = 0; i < mTotalThreadNum; i++) {
|
||||
threadId[i] = -1;
|
||||
}
|
||||
if (mTaskEntity.isNewTask() && !handleNewTask()) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < mTotalThreadNum; i++) {
|
||||
long startL = i * blockSize, endL = (i + 1) * blockSize;
|
||||
Object state = pro.getProperty(mTempFile.getName() + STATE + i);
|
||||
Object record = pro.getProperty(mTempFile.getName() + RECORD + i);
|
||||
if (state != null && Integer.parseInt(state + "") == 1 && record != null) { //该线程已经完成
|
||||
ThreadRecord tr;
|
||||
boolean isNewTr = false; // 是否是新的线程记录
|
||||
if (mTaskEntity.isNewTask()) {
|
||||
tr = new ThreadRecord();
|
||||
tr.key = mRecord.filePath;
|
||||
tr.threadId = i;
|
||||
isNewTr = true;
|
||||
} else {
|
||||
tr = mRecord.threadRecords.get(i);
|
||||
}
|
||||
if (tr.isComplete) {//该线程已经完成
|
||||
if (resumeRecordLocation(i, startL, endL)) return;
|
||||
continue;
|
||||
}
|
||||
|
||||
//如果有记录,则恢复下载
|
||||
if (!isNewTask && record != null && Long.parseLong(record + "") >= 0) {
|
||||
Long r = Long.parseLong(record + "");
|
||||
if (tr.startLocation >= 0) {
|
||||
Long r = tr.startLocation;
|
||||
//记录的位置需要在线程区间中
|
||||
if (startL < r && r < (i == (mTotalThreadNum - 1) ? fileLength : endL)) {
|
||||
mConstance.CURRENT_LOCATION += r - startL;
|
||||
startL = r;
|
||||
}
|
||||
ALog.d(TAG, "任务【" + mEntity.getFileName() + "】线程__" + i + "__恢复下载");
|
||||
recordL[rl] = i;
|
||||
rl++;
|
||||
} else {
|
||||
recordL[rl] = i;
|
||||
rl++;
|
||||
}
|
||||
//最后一个线程的结束位置即为文件的总长度
|
||||
if (i == (mTotalThreadNum - 1)) {
|
||||
//最后一个线程的结束位置即为文件的总长度
|
||||
endL = fileLength;
|
||||
}
|
||||
AbsThreadTask task = createSingThreadTask(i, startL, endL, fileLength);
|
||||
// 更新记录
|
||||
tr.startLocation = startL;
|
||||
tr.endLocation = endL;
|
||||
if (isNewTr) {
|
||||
mRecord.threadRecords.add(tr);
|
||||
}
|
||||
AbsThreadTask task = createSingThreadTask(i, startL, endL, fileLength, tr);
|
||||
if (task == null) return;
|
||||
mTask.put(i, task);
|
||||
threadId[rl] = i;
|
||||
rl++;
|
||||
}
|
||||
startSingleTask(recordL);
|
||||
saveRecord();
|
||||
startThreadTask(threadId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动单线程下载任务
|
||||
*/
|
||||
private void startSingleTask(int[] recordL) {
|
||||
private void startThreadTask(int[] recordL) {
|
||||
if (mConstance.CURRENT_LOCATION > 0) {
|
||||
mListener.onResume(mConstance.CURRENT_LOCATION);
|
||||
} else {
|
||||
@@ -390,7 +474,6 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
|
||||
mFixedThreadPool.execute(task);
|
||||
}
|
||||
}
|
||||
mTaskEntity.setNewTask(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -411,7 +494,6 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
|
||||
config.THREAD_ID = 0;
|
||||
config.START_LOCATION = 0;
|
||||
config.END_LOCATION = config.FILE_SIZE;
|
||||
config.CONFIG_FILE_PATH = mConfigFile.getPath();
|
||||
config.SUPPORT_BP = mTaskEntity.isSupportBP();
|
||||
config.TASK_ENTITY = mTaskEntity;
|
||||
AbsThreadTask task = selectThreadTask(config);
|
||||
|
||||
@@ -16,20 +16,17 @@
|
||||
package com.arialyy.aria.core.common;
|
||||
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.AriaManager;
|
||||
import com.arialyy.aria.core.inf.AbsNormalEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||
import com.arialyy.aria.core.inf.IEventListener;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.util.ErrorHelp;
|
||||
import com.arialyy.aria.util.NetUtils;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Properties;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@@ -52,7 +49,6 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
|
||||
private final String TAG = "AbsThreadTask";
|
||||
protected long mChildCurrentLocation = 0, mSleepTime = 0;
|
||||
protected int mBufSize;
|
||||
protected String mConfigFPath;
|
||||
protected IEventListener mListener;
|
||||
protected StateConstance STATE;
|
||||
protected SubThreadConfig<TASK_ENTITY> mConfig;
|
||||
@@ -84,7 +80,6 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
|
||||
mConfig = info;
|
||||
mTaskEntity = mConfig.TASK_ENTITY;
|
||||
mEntity = mTaskEntity.getEntity();
|
||||
mConfigFPath = info.CONFIG_FILE_PATH;
|
||||
mBufSize = manager.getDownloadConfig().getBuffSize();
|
||||
setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxSpeed());
|
||||
mTaskType = getTaskType();
|
||||
@@ -99,7 +94,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
|
||||
mSleepTime = 0;
|
||||
} else {
|
||||
BigDecimal db = new BigDecimal(
|
||||
((mBufSize / 1024) * (filterVersion() ? 1 : STATE.THREAD_NUM) / maxSpeed) * 1000);
|
||||
((mBufSize / 1024) * (filterVersion() ? 1 : STATE.START_THREAD_NUM) / maxSpeed) * 1000);
|
||||
mSleepTime = db.setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
|
||||
}
|
||||
}
|
||||
@@ -174,10 +169,6 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
|
||||
STATE.CANCEL_NUM++;
|
||||
ALog.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__取消");
|
||||
if (STATE.isCancel()) {
|
||||
File configFile = new File(mConfigFPath);
|
||||
if (configFile.exists()) {
|
||||
configFile.delete();
|
||||
}
|
||||
if (mConfig.TEMP_FILE.exists() && !(mEntity instanceof UploadEntity)) {
|
||||
mConfig.TEMP_FILE.delete();
|
||||
}
|
||||
@@ -206,7 +197,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
|
||||
}
|
||||
if (mConfig.SUPPORT_BP) {
|
||||
writeConfig(false, currentLocation);
|
||||
retryThis(STATE.THREAD_NUM != 1);
|
||||
retryThis(STATE.START_THREAD_NUM != 1);
|
||||
} else {
|
||||
ALog.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
|
||||
mListener.onFail(true);
|
||||
@@ -264,21 +255,12 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
|
||||
* 将记录写入到配置文件
|
||||
*/
|
||||
protected void writeConfig(boolean isComplete, final long record) throws IOException {
|
||||
synchronized (AriaManager.LOCK) {
|
||||
String key = null, value = null;
|
||||
if (record >= mConfig.END_LOCATION || isComplete) {
|
||||
key = mConfig.TEMP_FILE.getName() + AbsFileer.STATE + mConfig.THREAD_ID;
|
||||
value = "1";
|
||||
} else if (0 < record && record < mConfig.END_LOCATION) {
|
||||
key = mConfig.TEMP_FILE.getName() + AbsFileer.RECORD + mConfig.THREAD_ID;
|
||||
value = String.valueOf(record);
|
||||
}
|
||||
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
|
||||
File configFile = new File(mConfigFPath);
|
||||
Properties pro = CommonUtil.loadConfig(configFile);
|
||||
pro.setProperty(key, value);
|
||||
CommonUtil.saveConfig(configFile, pro);
|
||||
if (mConfig.THREAD_RECORD != null) {
|
||||
mConfig.THREAD_RECORD.isComplete = isComplete;
|
||||
if (0 < record && record < mConfig.END_LOCATION) {
|
||||
mConfig.START_LOCATION = record;
|
||||
}
|
||||
mConfig.THREAD_RECORD.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.common;
|
||||
|
||||
import com.arialyy.aria.orm.AbsWrapper;
|
||||
import com.arialyy.aria.orm.annotation.Many;
|
||||
import com.arialyy.aria.orm.annotation.One;
|
||||
import com.arialyy.aria.orm.annotation.Wrapper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/30.
|
||||
* 任务记录和线程记录的关系
|
||||
*/
|
||||
@Wrapper
|
||||
public class RecordWrapper extends AbsWrapper {
|
||||
|
||||
@One
|
||||
public TaskRecord taskRecord;
|
||||
|
||||
@Many(parentColumn = "filePath", entityColumn = "key")
|
||||
public List<ThreadRecord> threadRecords;
|
||||
|
||||
@Override protected void handleConvert() {
|
||||
if (threadRecords != null && !threadRecords.isEmpty()) {
|
||||
taskRecord.threadRecords = threadRecords;
|
||||
} else {
|
||||
taskRecord.threadRecords = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,11 +26,12 @@ public class StateConstance {
|
||||
public int CONNECT_TIME_OUT; //连接超时时间
|
||||
public int READ_TIME_OUT; //流读取的超时时间
|
||||
public int COMPLETE_THREAD_NUM = 0;
|
||||
public int THREAD_NUM;
|
||||
public int START_THREAD_NUM; //启动的线程数
|
||||
public long CURRENT_LOCATION = 0;
|
||||
public boolean isRunning = false;
|
||||
public boolean isCancel = false;
|
||||
public boolean isStop = false;
|
||||
public TaskRecord TASK_RECORD;
|
||||
|
||||
public StateConstance() {
|
||||
}
|
||||
@@ -49,27 +50,28 @@ public class StateConstance {
|
||||
* 所有子线程是否都已经停止下载
|
||||
*/
|
||||
public boolean isStop() {
|
||||
return STOP_NUM == THREAD_NUM;
|
||||
return STOP_NUM == START_THREAD_NUM;
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有子线程是否都已经下载失败
|
||||
*/
|
||||
public boolean isFail() {
|
||||
return COMPLETE_THREAD_NUM != THREAD_NUM && FAIL_NUM + COMPLETE_THREAD_NUM >= THREAD_NUM;
|
||||
return COMPLETE_THREAD_NUM != START_THREAD_NUM
|
||||
&& FAIL_NUM + COMPLETE_THREAD_NUM >= START_THREAD_NUM;
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有子线程是否都已经完成下载
|
||||
*/
|
||||
public boolean isComplete() {
|
||||
return COMPLETE_THREAD_NUM >= THREAD_NUM;
|
||||
return COMPLETE_THREAD_NUM >= START_THREAD_NUM;
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有子线程是否都已经取消下载
|
||||
*/
|
||||
public boolean isCancel() {
|
||||
return CANCEL_NUM == THREAD_NUM;
|
||||
return CANCEL_NUM == START_THREAD_NUM;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public class SubThreadConfig<TASK_ENTITY extends AbsTaskEntity> {
|
||||
public File TEMP_FILE;
|
||||
//服务器地址
|
||||
public String URL;
|
||||
public String CONFIG_FILE_PATH;
|
||||
public TASK_ENTITY TASK_ENTITY;
|
||||
public boolean SUPPORT_BP = true;
|
||||
public ThreadRecord THREAD_RECORD;
|
||||
}
|
||||
@@ -15,18 +15,62 @@
|
||||
*/
|
||||
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 java.util.List;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/3/21.
|
||||
* 任务上传或下载的记录
|
||||
* 任务上传或下载的任务记录
|
||||
*/
|
||||
class TaskRecord extends DbEntity {
|
||||
public class TaskRecord extends DbEntity {
|
||||
|
||||
@Ignore
|
||||
public List<ThreadRecord> threadRecords;
|
||||
|
||||
/**
|
||||
* 任务线程数
|
||||
*/
|
||||
public int threadNum;
|
||||
|
||||
//public int re
|
||||
/**
|
||||
* 任务文件路径
|
||||
*/
|
||||
@Primary
|
||||
public String filePath;
|
||||
|
||||
/**
|
||||
* 文件长度
|
||||
*/
|
||||
public long fileLength;
|
||||
|
||||
/**
|
||||
* 任务文件名
|
||||
*/
|
||||
@NoNull
|
||||
public String fileName;
|
||||
|
||||
/**
|
||||
* 是否是任务组的子任务记录
|
||||
* {@code true}是
|
||||
*/
|
||||
public boolean isGroupRecord = false;
|
||||
|
||||
/**
|
||||
* 下载任务组名
|
||||
*/
|
||||
@Foreign(parent = DownloadGroupEntity.class, column = "groupName", onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
|
||||
public String dGroupName;
|
||||
|
||||
/**
|
||||
* 上传组任务名,暂时没有用
|
||||
*/
|
||||
@Ignore
|
||||
@Deprecated
|
||||
public String uGroupName;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.common;
|
||||
|
||||
import com.arialyy.aria.orm.ActionPolicy;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.orm.annotation.Foreign;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/5/8.
|
||||
* 任务的线程记录
|
||||
*/
|
||||
public class ThreadRecord extends DbEntity {
|
||||
@Foreign(parent = TaskRecord.class, column = "filePath", onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
|
||||
public String key;
|
||||
|
||||
/**
|
||||
* 开始位置
|
||||
*/
|
||||
public long startLocation;
|
||||
|
||||
/**
|
||||
* 结束位置
|
||||
*/
|
||||
public long endLocation;
|
||||
|
||||
/**
|
||||
* 线程是否完成
|
||||
* {@code true}完成,{@code false}未完成
|
||||
*/
|
||||
public boolean isComplete = false;
|
||||
|
||||
/**
|
||||
* 线程id
|
||||
*/
|
||||
public int threadId = -1;
|
||||
}
|
||||
@@ -29,12 +29,7 @@ public class DownloadGroupEntity extends AbsGroupEntity {
|
||||
|
||||
@Ignore private List<DownloadEntity> subEntities;
|
||||
|
||||
/**
|
||||
* 任务组下载文件的文件夹地址
|
||||
*
|
||||
* @see DownloadGroupTarget#setDirPath(String)
|
||||
*/
|
||||
private String dirPath;
|
||||
|
||||
|
||||
/**
|
||||
* 子任务实体列表
|
||||
@@ -47,14 +42,6 @@ public class DownloadGroupEntity extends AbsGroupEntity {
|
||||
this.subEntities = subTasks;
|
||||
}
|
||||
|
||||
public String getDirPath() {
|
||||
return dirPath;
|
||||
}
|
||||
|
||||
public void setDirPath(String dirPath) {
|
||||
this.dirPath = dirPath;
|
||||
}
|
||||
|
||||
public void setGroupName(String key) {
|
||||
this.groupName = key;
|
||||
}
|
||||
@@ -73,13 +60,11 @@ public class DownloadGroupEntity extends AbsGroupEntity {
|
||||
@Override public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeTypedList(this.subEntities);
|
||||
dest.writeString(this.dirPath);
|
||||
}
|
||||
|
||||
protected DownloadGroupEntity(Parcel in) {
|
||||
super(in);
|
||||
this.subEntities = in.createTypedArrayList(DownloadEntity.CREATOR);
|
||||
this.dirPath = in.readString();
|
||||
}
|
||||
|
||||
public static final Creator<DownloadGroupEntity> CREATOR = new Creator<DownloadGroupEntity>() {
|
||||
|
||||
@@ -234,7 +234,7 @@ public abstract class AbsGroupUtil implements IUtil {
|
||||
}
|
||||
}
|
||||
clearState();
|
||||
CommonUtil.delDownloadGroupTaskConfig(mGTEntity.isRemoveFile(), mGTEntity.getEntity());
|
||||
CommonUtil.delGroupTaskRecord(mGTEntity.isRemoveFile(), mGTEntity.getEntity());
|
||||
mListener.onCancel();
|
||||
}
|
||||
|
||||
|
||||
@@ -45,32 +45,17 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
|
||||
}
|
||||
|
||||
@Override protected int setNewTaskThreadNum() {
|
||||
return mEntity.getFileSize() <= SUB_LEN || mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP_DIR
|
||||
? 1
|
||||
: AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum();
|
||||
return
|
||||
mEntity.getFileSize() <= SUB_LEN || mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP_DIR
|
||||
? 1
|
||||
: AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum();
|
||||
}
|
||||
|
||||
@Override protected void checkTask() {
|
||||
mConfigFile = new File(CommonUtil.getFileConfigPath(true, mEntity.getFileName()));
|
||||
super.checkTask();
|
||||
mTempFile = new File(mEntity.getDownloadPath());
|
||||
if (!mTaskEntity.isSupportBP()) {
|
||||
isNewTask = true;
|
||||
return;
|
||||
}
|
||||
if (mTaskEntity.isNewTask()) {
|
||||
isNewTask = true;
|
||||
return;
|
||||
}
|
||||
if (!mConfigFile.exists()) { //记录文件被删除,则重新下载
|
||||
isNewTask = true;
|
||||
CommonUtil.createFile(mConfigFile.getPath());
|
||||
} else if (!mTempFile.exists()) {
|
||||
isNewTask = true;
|
||||
} else if (DbEntity.findFirst(DownloadEntity.class, "url=?", mEntity.getUrl()) == null) {
|
||||
isNewTask = true;
|
||||
} else {
|
||||
isNewTask = checkConfigFile();
|
||||
}
|
||||
mTaskEntity.setNewTask(!mTempFile.exists()
|
||||
|| DbEntity.findFirst(DownloadEntity.class, "url=?", mEntity.getUrl()) == null);
|
||||
}
|
||||
|
||||
@Override protected boolean handleNewTask() {
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||
import com.arialyy.aria.core.inf.IDownloadListener;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import org.apache.commons.net.ftp.FTPClient;
|
||||
@@ -107,10 +106,7 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
|
||||
writeConfig(true, 1);
|
||||
STATE.COMPLETE_THREAD_NUM++;
|
||||
if (STATE.isComplete()) {
|
||||
File configFile = new File(mConfigFPath);
|
||||
if (configFile.exists()) {
|
||||
configFile.delete();
|
||||
}
|
||||
STATE.TASK_RECORD.deleteData();
|
||||
STATE.isRunning = false;
|
||||
mListener.onComplete();
|
||||
}
|
||||
|
||||
@@ -148,6 +148,7 @@ class HttpFileInfoThread implements Runnable {
|
||||
return;
|
||||
}
|
||||
mEntity.setFileSize(len);
|
||||
mTaskEntity.setNewTask(true);
|
||||
mTaskEntity.setSupportBP(false);
|
||||
end = true;
|
||||
} else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
|
||||
@@ -180,7 +181,7 @@ class HttpFileInfoThread implements Runnable {
|
||||
File oldFile = new File(mEntity.getDownloadPath());
|
||||
String oldName = oldFile.getName();
|
||||
String newPath = oldFile.getParent() + "/" + newName;
|
||||
if (oldFile.exists()){
|
||||
if (oldFile.exists()) {
|
||||
oldFile.renameTo(new File(newPath));
|
||||
}
|
||||
mEntity.setFileName(newName);
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
@@ -155,10 +154,7 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
|
||||
writeConfig(true, 1);
|
||||
STATE.COMPLETE_THREAD_NUM++;
|
||||
if (STATE.isComplete()) {
|
||||
File configFile = new File(mConfigFPath);
|
||||
if (configFile.exists()) {
|
||||
configFile.delete();
|
||||
}
|
||||
STATE.TASK_RECORD.deleteData();
|
||||
STATE.isRunning = false;
|
||||
mListener.onComplete();
|
||||
}
|
||||
|
||||
@@ -35,8 +35,24 @@ public abstract class AbsGroupEntity extends AbsEntity implements Parcelable {
|
||||
*/
|
||||
private String alias;
|
||||
|
||||
/**
|
||||
* 任务组下载文件的文件夹地址
|
||||
*/
|
||||
private String dirPath;
|
||||
|
||||
/**
|
||||
* 子任务url地址
|
||||
*/
|
||||
private List<String> urls = new ArrayList<>();
|
||||
|
||||
public String getDirPath() {
|
||||
return dirPath;
|
||||
}
|
||||
|
||||
public void setDirPath(String dirPath) {
|
||||
this.dirPath = dirPath;
|
||||
}
|
||||
|
||||
public List<String> getUrls() {
|
||||
return urls;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.upload.UploadTaskEntity;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import org.apache.commons.net.ftp.FTPClient;
|
||||
@@ -82,10 +81,7 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
|
||||
writeConfig(true, 1);
|
||||
STATE.COMPLETE_THREAD_NUM++;
|
||||
if (STATE.isComplete()) {
|
||||
File configFile = new File(mConfigFPath);
|
||||
if (configFile.exists()) {
|
||||
configFile.delete();
|
||||
}
|
||||
STATE.TASK_RECORD.deleteData();
|
||||
STATE.isRunning = false;
|
||||
mListener.onComplete();
|
||||
}
|
||||
@@ -114,7 +110,8 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
|
||||
private void initPath() throws UnsupportedEncodingException {
|
||||
dir = new String(mTaskEntity.getUrlEntity().remotePath.getBytes(charSet), SERVER_CHARSET);
|
||||
remotePath = new String(
|
||||
("/" + mTaskEntity.getUrlEntity().remotePath + "/" + mEntity.getFileName()).getBytes(charSet),
|
||||
("/" + mTaskEntity.getUrlEntity().remotePath + "/" + mEntity.getFileName()).getBytes(
|
||||
charSet),
|
||||
SERVER_CHARSET);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.arialyy.aria.core.inf.IUploadListener;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.core.upload.UploadTaskEntity;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
@@ -40,29 +39,11 @@ class Uploader extends AbsFileer<UploadEntity, UploadTaskEntity> {
|
||||
AriaManager.getInstance(AriaManager.APP).getUploadConfig().getUpdateInterval());
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查任务是否是新任务,新任务条件:
|
||||
* 1、文件不存在
|
||||
* 2、记录文件不存在
|
||||
* 3、记录文件缺失或不匹配
|
||||
* 4、数据库记录不存在
|
||||
* 5、不支持断点,则是新任务
|
||||
*/
|
||||
protected void checkTask() {
|
||||
mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
|
||||
if (!mTaskEntity.isSupportBP()) {
|
||||
isNewTask = true;
|
||||
return;
|
||||
}
|
||||
if (!mConfigFile.exists()) { //记录文件被删除,则重新下载
|
||||
isNewTask = true;
|
||||
CommonUtil.createFile(mConfigFile.getPath());
|
||||
} else if (DbEntity.findFirst(UploadEntity.class, "filePath=?", mEntity.getFilePath())
|
||||
== null) {
|
||||
isNewTask = true;
|
||||
} else {
|
||||
isNewTask = checkConfigFile();
|
||||
}
|
||||
super.checkTask();
|
||||
mTaskEntity.setNewTask(
|
||||
DbEntity.findFirst(UploadEntity.class, "filePath=?", mEntity.getFilePath())
|
||||
== null);
|
||||
}
|
||||
|
||||
@Override protected boolean handleNewTask() {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
package com.arialyy.aria.orm;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.aria.core.common.TaskRecord;
|
||||
import com.arialyy.aria.core.common.ThreadRecord;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
|
||||
@@ -33,7 +35,7 @@ class DBConfig {
|
||||
/*adb pull /mnt/sdcard/Android/data/com.arialyy.simple/files/DB/AriaLyyDb d:/db*/
|
||||
static Map<String, Class> mapping = new HashMap<>();
|
||||
static String DB_NAME;
|
||||
static int VERSION = 31;
|
||||
static int VERSION = 32;
|
||||
|
||||
/**
|
||||
* 是否将数据库保存在Sd卡,{@code true} 是
|
||||
@@ -56,5 +58,7 @@ class DBConfig {
|
||||
mapping.put("UploadTaskEntity", UploadTaskEntity.class);
|
||||
mapping.put("DownloadEntity", DownloadEntity.class);
|
||||
mapping.put("UploadEntity", UploadEntity.class);
|
||||
mapping.put("TaskRecord", TaskRecord.class);
|
||||
mapping.put("ThreadRecord", ThreadRecord.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,13 @@ public abstract class DbEntity {
|
||||
|
||||
}
|
||||
|
||||
///**
|
||||
// * 保存关联数据
|
||||
// */
|
||||
//public static void saveRelationData(AbsWrapper wrapper) {
|
||||
// DelegateWrapper.getInstance().saveRelationData(wrapper);
|
||||
//}
|
||||
|
||||
/**
|
||||
* 查询关联数据
|
||||
*
|
||||
|
||||
@@ -187,6 +187,10 @@ class DelegateCommon extends AbsDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
if (SqlUtil.isUnique(field)){
|
||||
sb.append(" UNIQUE");
|
||||
}
|
||||
|
||||
sb.append(",");
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ class DelegateFind extends AbsDelegate {
|
||||
* 如果查找不到数据或实体没有被{@link Wrapper}注解,将返回null
|
||||
* 如果实体中没有{@link One}或{@link Many}注解,将返回null
|
||||
* 如果实体中有多个{@link One}或{@link Many}注解,将返回nul
|
||||
* {@link One} 的注解对象必须是{@link DbEntity},{@link Many}的注解对象必须是List,并且List中的类型必须是{@link DbEntity}
|
||||
*/
|
||||
<T extends AbsWrapper> List<T> findRelationData(SQLiteDatabase db, Class<T> clazz,
|
||||
String... expression) {
|
||||
@@ -75,6 +76,10 @@ class DelegateFind extends AbsDelegate {
|
||||
ALog.w(TAG, "查询数据失败,实体中有多个@Many 注解");
|
||||
return null;
|
||||
}
|
||||
if (!field.getType().isAssignableFrom(List.class)) {
|
||||
ALog.w(TAG, "查询数据失败,@Many 注解的类型不是List");
|
||||
return null;
|
||||
}
|
||||
hasMany = true;
|
||||
many = field;
|
||||
}
|
||||
@@ -499,10 +504,16 @@ class DelegateFind extends AbsDelegate {
|
||||
/**
|
||||
* 通过rowId判断数据是否存在
|
||||
*/
|
||||
<T extends DbEntity> boolean itemExist(SQLiteDatabase db, Class<T> clazz,
|
||||
long rowId) {
|
||||
<T extends DbEntity> boolean itemExist(SQLiteDatabase db, Class<T> clazz, long rowId) {
|
||||
return itemExist(db, CommonUtil.getClassName(clazz), rowId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过rowId判断数据是否存在
|
||||
*/
|
||||
boolean itemExist(SQLiteDatabase db, String tableName, long rowId) {
|
||||
db = checkDb(db);
|
||||
String sql = "SELECT rowid FROM " + CommonUtil.getClassName(clazz) + " WHERE rowid=" + rowId;
|
||||
String sql = "SELECT rowid FROM " + tableName + " WHERE rowid=" + rowId;
|
||||
print(ROW_ID, sql);
|
||||
Cursor cursor = db.rawQuery(sql, null);
|
||||
boolean isExist = cursor.getCount() > 0;
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.arialyy.aria.orm;
|
||||
import android.content.ContentValues;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.orm.annotation.Primary;
|
||||
import com.arialyy.aria.util.ALog;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
@@ -36,6 +35,50 @@ class DelegateUpdate extends AbsDelegate {
|
||||
private DelegateUpdate() {
|
||||
}
|
||||
|
||||
///**
|
||||
// * 添加或更新关联数据
|
||||
// */
|
||||
//void saveRelationData(SQLiteDatabase db, AbsWrapper wrapper) {
|
||||
// Class clazz = wrapper.getClass();
|
||||
// List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
// DbEntity one = null;
|
||||
// Object many = null;
|
||||
// try {
|
||||
// for (Field field : fields) {
|
||||
// if (SqlUtil.isOne(field)) {
|
||||
// one = (DbEntity) field.get(wrapper);
|
||||
// } else if (SqlUtil.isMany(field)) {
|
||||
// many = field.get(wrapper);
|
||||
// }
|
||||
// }
|
||||
// if (one == null) {
|
||||
// ALog.w(TAG, "保存关联数据失败,@One注解的字段为null");
|
||||
// return;
|
||||
// }
|
||||
// if (many == null) {
|
||||
// ALog.w(TAG, "保存关联数据失败,@Many注解的字段为null");
|
||||
// return;
|
||||
// }
|
||||
// List<Field> oneFields = CommonUtil.getAllFields(one.getClass());
|
||||
// one.save();
|
||||
// if (many.getClass() == List.class) {
|
||||
// for (DbEntity sub : (List<DbEntity>) many) {
|
||||
// sub.getClass().getA
|
||||
// sub.save();
|
||||
// }
|
||||
// } else {
|
||||
// if (DbEntity.class.isInstance(many)) {
|
||||
// ((DbEntity) many).save();
|
||||
// } else {
|
||||
// ALog.w(TAG, "保存关联数据失败,@Many注解的字段不是DbEntity子类");
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// } catch (IllegalAccessException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* 删除某条数据
|
||||
*/
|
||||
@@ -62,7 +105,6 @@ class DelegateUpdate extends AbsDelegate {
|
||||
db = checkDb(db);
|
||||
Class<?> clazz = dbEntity.getClass();
|
||||
List<Field> fields = CommonUtil.getAllFields(clazz);
|
||||
//DbEntity cacheEntity = mDataCache.get(getCacheKey(dbEntity));
|
||||
if (fields != null && fields.size() > 0) {
|
||||
ContentValues values = new ContentValues();
|
||||
try {
|
||||
@@ -71,14 +113,6 @@ class DelegateUpdate extends AbsDelegate {
|
||||
if (isIgnore(dbEntity, field)) {
|
||||
continue;
|
||||
}
|
||||
//if (cacheEntity != null
|
||||
// && field.get(dbEntity).equals(field.get(cacheEntity))
|
||||
// && !field.getName().equals("state")) { //在LruCache中 state字段总是不能重新赋值...
|
||||
// Log.d(TAG, field.get(dbEntity) + "");
|
||||
// Log.d(TAG, field.get(cacheEntity) + "");
|
||||
//
|
||||
// continue;
|
||||
//}
|
||||
String value;
|
||||
Type type = field.getType();
|
||||
if (type == Map.class && checkMap(field)) {
|
||||
@@ -101,7 +135,6 @@ class DelegateUpdate extends AbsDelegate {
|
||||
ALog.d(TAG, "没有数据更新");
|
||||
}
|
||||
}
|
||||
//mDataCache.put(getCacheKey(dbEntity), dbEntity);
|
||||
close(db);
|
||||
}
|
||||
|
||||
@@ -137,7 +170,6 @@ class DelegateUpdate extends AbsDelegate {
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//print(INSERT_DATA, );
|
||||
dbEntity.rowID = db.insert(CommonUtil.getClassName(dbEntity), null, values);
|
||||
}
|
||||
close(db);
|
||||
|
||||
@@ -56,6 +56,13 @@ public class DelegateWrapper {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
///**
|
||||
// * 保存关联数据
|
||||
// */
|
||||
//void saveRelationData(AbsWrapper wrapper){
|
||||
//
|
||||
//}
|
||||
|
||||
/**
|
||||
* 查询关联表数据
|
||||
*
|
||||
@@ -125,6 +132,13 @@ public class DelegateWrapper {
|
||||
return mDManager.getDelegate(DelegateFind.class).itemExist(mDb, clazz, rowId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过rowId判断数据是否存在
|
||||
*/
|
||||
boolean isExist(String tableName, long rowId) {
|
||||
return mDManager.getDelegate(DelegateFind.class).itemExist(mDb, tableName, rowId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入数据
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.arialyy.aria.orm.annotation.Many;
|
||||
import com.arialyy.aria.orm.annotation.NoNull;
|
||||
import com.arialyy.aria.orm.annotation.One;
|
||||
import com.arialyy.aria.orm.annotation.Primary;
|
||||
import com.arialyy.aria.orm.annotation.Unique;
|
||||
import com.arialyy.aria.orm.annotation.Wrapper;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -247,6 +248,16 @@ final class SqlUtil {
|
||||
return nn != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是Unique
|
||||
*
|
||||
* @return {@code true}为Unique
|
||||
*/
|
||||
static boolean isUnique(Field field) {
|
||||
Unique nn = field.getAnnotation(Unique.class);
|
||||
return nn != null;
|
||||
}
|
||||
|
||||
private static Object checkData(String type, String data) {
|
||||
if (type.equalsIgnoreCase("java.lang.String")) {
|
||||
return data;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.orm.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created by laoyuyu on 2018/5/8.
|
||||
* 数据库 UNIQUE 约束
|
||||
*/
|
||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Unique {
|
||||
}
|
||||
@@ -30,11 +30,15 @@ import com.arialyy.aria.core.command.group.AbsGroupCmd;
|
||||
import com.arialyy.aria.core.command.group.GroupCmdFactory;
|
||||
import com.arialyy.aria.core.command.normal.AbsNormalCmd;
|
||||
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
|
||||
import com.arialyy.aria.core.common.TaskRecord;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.inf.AbsGroupEntity;
|
||||
import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
|
||||
import com.arialyy.aria.core.inf.AbsNormalEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||
import com.arialyy.aria.core.upload.UploadEntity;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
@@ -65,6 +69,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/1/22.
|
||||
* 通用工具
|
||||
*/
|
||||
public class CommonUtil {
|
||||
private static final String TAG = "CommonUtil";
|
||||
@@ -82,7 +87,7 @@ public class CommonUtil {
|
||||
String reg = Regular.REG_WINLOD_REPLACE;
|
||||
Pattern p = Pattern.compile(reg);
|
||||
Matcher m = p.matcher(text);
|
||||
if (m.find()){
|
||||
if (m.find()) {
|
||||
String s = m.group();
|
||||
s = s.substring(9, s.length() - 2);
|
||||
return s;
|
||||
@@ -356,20 +361,27 @@ public class CommonUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除下载任务组的配置
|
||||
* 删除任务组记录
|
||||
*
|
||||
* @param removeFile {@code true} 不仅删除任务数据库记录,还会删除已经删除完成的文件
|
||||
* {@code false}如果任务已经完成,只删除任务数据库记录
|
||||
*/
|
||||
public static void delDownloadGroupTaskConfig(boolean removeFile,
|
||||
DownloadGroupEntity groupEntity) {
|
||||
public static void delGroupTaskRecord(boolean removeFile, AbsGroupEntity groupEntity) {
|
||||
if (groupEntity == null) {
|
||||
ALog.e(TAG, "删除下载任务组记录失败,任务组实体为null");
|
||||
return;
|
||||
}
|
||||
List<TaskRecord> records = DbEntity.findDatas(TaskRecord.class,
|
||||
groupEntity instanceof DownloadGroupEntity ? "dGroupName=?" : "uGroupName=?",
|
||||
groupEntity.getGroupName());
|
||||
|
||||
for (DownloadEntity taskEntity : groupEntity.getSubEntities()) {
|
||||
delDownloadTaskConfig(removeFile, taskEntity);
|
||||
if (records == null || records.isEmpty()) {
|
||||
ALog.w(TAG, "组任务记录删除失败,记录为null");
|
||||
return;
|
||||
}
|
||||
|
||||
for (TaskRecord tr : records) {
|
||||
tr.deleteData();
|
||||
}
|
||||
|
||||
File dir = new File(groupEntity.getDirPath());
|
||||
@@ -386,38 +398,23 @@ public class CommonUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除上传任务的配置
|
||||
*
|
||||
* @param removeFile {@code true} 不仅删除任务数据库记录,还会删除已经删除完成的文件
|
||||
* {@code false}如果任务已经完成,只删除任务数据库记录
|
||||
*/
|
||||
public static void delUploadTaskConfig(boolean removeFile, UploadEntity uEntity) {
|
||||
if (uEntity == null) {
|
||||
return;
|
||||
}
|
||||
File file = new File(uEntity.getFilePath());
|
||||
if (removeFile) {
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
File config = new File(getFileConfigPath(false, uEntity.getFileName()));
|
||||
if (config.exists()) {
|
||||
config.delete();
|
||||
}
|
||||
//下载任务实体和下载实体为一对一关系,下载实体删除,任务实体自动删除
|
||||
uEntity.deleteData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除下载任务的配置
|
||||
* 删除任务记录
|
||||
*
|
||||
* @param removeFile {@code true} 不仅删除任务数据库记录,还会删除已经下载完成的文件
|
||||
* {@code false}如果任务已经完成,只删除任务数据库记录
|
||||
*/
|
||||
public static void delDownloadTaskConfig(boolean removeFile, DownloadEntity dEntity) {
|
||||
public static void delTaskRecord(TaskRecord record, boolean removeFile,
|
||||
AbsNormalEntity dEntity) {
|
||||
if (dEntity == null) return;
|
||||
File file = new File(dEntity.getDownloadPath());
|
||||
File file;
|
||||
if (dEntity instanceof DownloadEntity) {
|
||||
file = new File(((DownloadEntity) dEntity).getDownloadPath());
|
||||
} else if (dEntity instanceof UploadEntity) {
|
||||
file = new File(((UploadEntity) dEntity).getFilePath());
|
||||
} else {
|
||||
ALog.w(TAG, "删除记录失败,未知类型");
|
||||
return;
|
||||
}
|
||||
if (removeFile) {
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
@@ -430,9 +427,8 @@ public class CommonUtil {
|
||||
}
|
||||
}
|
||||
|
||||
File config = new File(getFileConfigPath(true, dEntity.getFileName()));
|
||||
if (config.exists()) {
|
||||
config.delete();
|
||||
if (record != null) {
|
||||
record.deleteData();
|
||||
}
|
||||
//下载任务实体和下载实体为一对一关系,下载实体删除,任务实体自动删除
|
||||
dEntity.deleteData();
|
||||
|
||||
Reference in New Issue
Block a user