移除记录配置文件,改用数据库记录任务记录

pull/330/head
laoyuyu 7 years ago
parent c7bb1cd0c5
commit 2d133901de
  1. 224
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
  2. 32
      Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java
  3. 45
      Aria/src/main/java/com/arialyy/aria/core/common/RecordWrapper.java
  4. 12
      Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java
  5. 2
      Aria/src/main/java/com/arialyy/aria/core/common/SubThreadConfig.java
  6. 50
      Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java
  7. 50
      Aria/src/main/java/com/arialyy/aria/core/common/ThreadRecord.java
  8. 17
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java
  9. 2
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java
  10. 25
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java
  11. 6
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java
  12. 3
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
  13. 6
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
  14. 16
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java
  15. 9
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java
  16. 27
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/Uploader.java
  17. 6
      Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java
  18. 7
      Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java
  19. 4
      Aria/src/main/java/com/arialyy/aria/orm/DelegateCommon.java
  20. 17
      Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java
  21. 56
      Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java
  22. 14
      Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java
  23. 11
      Aria/src/main/java/com/arialyy/aria/orm/SqlUtil.java
  24. 29
      Aria/src/main/java/com/arialyy/aria/orm/annotation/Unique.java
  25. 68
      Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java

@ -19,16 +19,17 @@ import android.content.Context;
import android.util.SparseArray; import android.util.SparseArray;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadEntity; 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.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener; import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.core.inf.IEventListener; import com.arialyy.aria.core.inf.IEventListener;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.Timer; import java.util.Timer;
@ -50,10 +51,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
protected IEventListener mListener; protected IEventListener mListener;
protected TASK_ENTITY mTaskEntity; protected TASK_ENTITY mTaskEntity;
protected ENTITY mEntity; protected ENTITY mEntity;
protected File mConfigFile;//信息配置文件
protected Context mContext; protected Context mContext;
protected File mTempFile; //文件 protected File mTempFile; //文件
protected boolean isNewTask = true;
protected StateConstance mConstance; protected StateConstance mConstance;
private ExecutorService mFixedThreadPool; private ExecutorService mFixedThreadPool;
//总线程数 //总线程数
@ -68,7 +67,13 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
* 小于1m的文件不启用多线程 * 小于1m的文件不启用多线程
*/ */
private Timer mTimer; private Timer mTimer;
@Deprecated
private File mConfigFile;
/**
* 进度刷新间隔
*/
private long mUpdateInterval = 1000; private long mUpdateInterval = 1000;
private TaskRecord mRecord;
protected AbsFileer(IEventListener listener, TASK_ENTITY taskEntity) { protected AbsFileer(IEventListener listener, TASK_ENTITY taskEntity) {
mListener = listener; mListener = listener;
@ -104,19 +109,21 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
private void startFlow() { private void startFlow() {
mConstance.resetState(); mConstance.resetState();
checkTask(); checkTask();
mConstance.TASK_RECORD = mRecord;
if (mListener instanceof IDownloadListener) { if (mListener instanceof IDownloadListener) {
((IDownloadListener) mListener).onPostPre(mEntity.getFileSize()); ((IDownloadListener) mListener).onPostPre(mEntity.getFileSize());
} }
if (!mTaskEntity.isSupportBP()) { if (!mTaskEntity.isSupportBP()) {
mTotalThreadNum = 1; mTotalThreadNum = 1;
mStartThreadNum = 1; mStartThreadNum = 1;
mConstance.THREAD_NUM = mTotalThreadNum;
handleNoSupportBP(); handleNoSupportBP();
} else { } else {
mTotalThreadNum = isNewTask ? (mStartThreadNum = setNewTaskThreadNum()) : mStartThreadNum; // TODO: 2018/5/11 如果不是新任务,就有问题
mConstance.THREAD_NUM = mTotalThreadNum; mTotalThreadNum =
mTaskEntity.isNewTask() ? (mStartThreadNum = setNewTaskThreadNum()) : mTotalThreadNum;
handleBreakpoint(); handleBreakpoint();
} }
mConstance.START_THREAD_NUM = mTotalThreadNum;
startTimer(); startTimer();
} }
@ -193,13 +200,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
task.cancel(); task.cancel();
} }
} }
if (mTaskEntity instanceof DownloadTaskEntity) { CommonUtil.delTaskRecord(mRecord, mTaskEntity.isRemoveFile(), mTaskEntity.getEntity());
CommonUtil.delDownloadTaskConfig(mTaskEntity.isRemoveFile(),
(DownloadEntity) mTaskEntity.getEntity());
} else if (mTaskEntity instanceof UploadTaskEntity) {
CommonUtil.delUploadTaskConfig(mTaskEntity.isRemoveFile(),
(UploadEntity) mTaskEntity.getEntity());
}
} }
@Override public void stop() { @Override public void stop() {
@ -230,53 +231,127 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
} }
/** /**
* 检查任务是否是新任务新任务条件 * 检查任务检查线程数
* 新任务条件
* 1文件不存在 * 1文件不存在
* 2下载记录文件不存在 * 2下载记录文件缺失或不匹配
* 3下载记录文件缺失或不匹配 * 3数据库记录不存在
* 4数据库记录不存在 * 4不支持断点则是新任务
* 5不支持断点则是新任务
*/ */
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() { private void convertDb() {
mStartThreadNum = 0; List<RecordWrapper> records =
mCompleteThreadNum = 0; DbEntity.findRelationData(RecordWrapper.class, "TaskRecord.filePath=?",
mTaskEntity.getKey());
if (records == null || records.size() == 0) {
Properties pro = CommonUtil.loadConfig(mConfigFile); Properties pro = CommonUtil.loadConfig(mConfigFile);
if (pro.isEmpty()) { if (pro.isEmpty()) {
return true; mTaskEntity.setNewTask(true);
return;
} }
initRecord();
Set<Object> keys = pro.keySet(); Set<Object> keys = pro.keySet();
int num = 0; // 老版本记录是5s存一次,但是5s中内,如果线程执行完成,record记录是没有的,只有state记录...
// 第一步应该是record 和 state去重取正确的线程数
Set<Integer> set = new HashSet<>();
for (Object key : keys) { for (Object key : keys) {
String str = String.valueOf(key); 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())); int i = Integer.parseInt(str.substring(str.length() - 1, str.length()));
if (pro.getProperty(mTempFile.getName() + RECORD + i) != null) { set.add(i);
mCompleteThreadNum++;
}
}
} }
if (num == 0) { int threadNum = set.size();
return true; if (threadNum == 0) {
mTaskEntity.setNewTask(true);
return;
} }
mStartThreadNum = num; mRecord.threadNum = threadNum;
for (int i = 0; i < mStartThreadNum; i++) { mTotalThreadNum = threadNum;
if (pro.getProperty(mTempFile.getName() + RECORD + i) == null) {
for (int i = 0; i < threadNum; i++) {
ThreadRecord tRecord = new ThreadRecord();
tRecord.key = mRecord.filePath;
Object state = pro.getProperty(mTempFile.getName() + STATE + i); Object state = pro.getProperty(mTempFile.getName() + STATE + i);
Object record = pro.getProperty(mTempFile.getName() + RECORD + i);
if (state != null && Integer.parseInt(state + "") == 1) { if (state != null && Integer.parseInt(state + "") == 1) {
mCompleteThreadNum++;
tRecord.isComplete = true;
continue; 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);
} }
return false; 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();
}
}
}
/**
* 保存任务记录
*/
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.STOP_NUM++;
mConstance.CANCEL_NUM++; mConstance.CANCEL_NUM++;
if (mConstance.isComplete()) { if (mConstance.isComplete()) {
if (mConfigFile.exists()) { mRecord.deleteData();
mConfigFile.delete();
}
mListener.onComplete(); mListener.onComplete();
mConstance.isRunning = false; mConstance.isRunning = false;
return true; return true;
@ -309,7 +382,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
* @param endL 该任务结束位置 * @param endL 该任务结束位置
* @param fileLength 该任务需要处理的文件长度 * @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<>(); SubThreadConfig<TASK_ENTITY> config = new SubThreadConfig<>();
config.FILE_SIZE = fileLength; config.FILE_SIZE = fileLength;
config.URL = mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getUrl(); 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.THREAD_ID = i;
config.START_LOCATION = startL; config.START_LOCATION = startL;
config.END_LOCATION = endL; config.END_LOCATION = endL;
config.CONFIG_FILE_PATH = mConfigFile.getPath();
config.SUPPORT_BP = mTaskEntity.isSupportBP(); config.SUPPORT_BP = mTaskEntity.isSupportBP();
config.TASK_ENTITY = mTaskEntity; config.TASK_ENTITY = mTaskEntity;
config.THREAD_RECORD = record;
return selectThreadTask(config); return selectThreadTask(config);
} }
/**
* 处理断点
*/
private void handleBreakpoint() { private void handleBreakpoint() {
long fileLength = mEntity.getFileSize(); long fileLength = mEntity.getFileSize();
Properties pro = CommonUtil.loadConfig(mConfigFile);
long blockSize = fileLength / mTotalThreadNum; long blockSize = fileLength / mTotalThreadNum;
int[] recordL = new int[mTotalThreadNum]; int[] threadId = new int[mTotalThreadNum];
int rl = 0;
mRecord.fileLength = fileLength;
for (int i = 0; i < mTotalThreadNum; i++) { for (int i = 0; i < mTotalThreadNum; i++) {
recordL[i] = -1; threadId[i] = -1;
} }
int rl = 0; if (mTaskEntity.isNewTask() && !handleNewTask()) {
if (isNewTask && !handleNewTask()) {
return; return;
} }
for (int i = 0; i < mTotalThreadNum; i++) { for (int i = 0; i < mTotalThreadNum; i++) {
long startL = i * blockSize, endL = (i + 1) * blockSize; long startL = i * blockSize, endL = (i + 1) * blockSize;
Object state = pro.getProperty(mTempFile.getName() + STATE + i); ThreadRecord tr;
Object record = pro.getProperty(mTempFile.getName() + RECORD + i); boolean isNewTr = false; // 是否是新的线程记录
if (state != null && Integer.parseInt(state + "") == 1 && record != null) { //该线程已经完成 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; if (resumeRecordLocation(i, startL, endL)) return;
continue; continue;
} }
//如果有记录,则恢复下载 //如果有记录,则恢复下载
if (!isNewTask && record != null && Long.parseLong(record + "") >= 0) { if (tr.startLocation >= 0) {
Long r = Long.parseLong(record + ""); Long r = tr.startLocation;
//记录的位置需要在线程区间中 //记录的位置需要在线程区间中
if (startL < r && r < (i == (mTotalThreadNum - 1) ? fileLength : endL)) { if (startL < r && r < (i == (mTotalThreadNum - 1) ? fileLength : endL)) {
mConstance.CURRENT_LOCATION += r - startL; mConstance.CURRENT_LOCATION += r - startL;
startL = r; startL = r;
} }
ALog.d(TAG, "任务【" + mEntity.getFileName() + "】线程__" + i + "__恢复下载"); ALog.d(TAG, "任务【" + mEntity.getFileName() + "】线程__" + i + "__恢复下载");
recordL[rl] = i;
rl++;
} else {
recordL[rl] = i;
rl++;
} }
if (i == (mTotalThreadNum - 1)) {
//最后一个线程的结束位置即为文件的总长度 //最后一个线程的结束位置即为文件的总长度
if (i == (mTotalThreadNum - 1)) {
endL = fileLength; 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; if (task == null) return;
mTask.put(i, task); 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) { if (mConstance.CURRENT_LOCATION > 0) {
mListener.onResume(mConstance.CURRENT_LOCATION); mListener.onResume(mConstance.CURRENT_LOCATION);
} else { } else {
@ -390,7 +474,6 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
mFixedThreadPool.execute(task); 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.THREAD_ID = 0;
config.START_LOCATION = 0; config.START_LOCATION = 0;
config.END_LOCATION = config.FILE_SIZE; config.END_LOCATION = config.FILE_SIZE;
config.CONFIG_FILE_PATH = mConfigFile.getPath();
config.SUPPORT_BP = mTaskEntity.isSupportBP(); config.SUPPORT_BP = mTaskEntity.isSupportBP();
config.TASK_ENTITY = mTaskEntity; config.TASK_ENTITY = mTaskEntity;
AbsThreadTask task = selectThreadTask(config); AbsThreadTask task = selectThreadTask(config);

@ -16,20 +16,17 @@
package com.arialyy.aria.core.common; package com.arialyy.aria.core.common;
import android.os.Build; import android.os.Build;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsNormalEntity; import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEventListener; import com.arialyy.aria.core.inf.IEventListener;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.ErrorHelp; import com.arialyy.aria.util.ErrorHelp;
import com.arialyy.aria.util.NetUtils; import com.arialyy.aria.util.NetUtils;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Properties;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -52,7 +49,6 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
private final String TAG = "AbsThreadTask"; private final String TAG = "AbsThreadTask";
protected long mChildCurrentLocation = 0, mSleepTime = 0; protected long mChildCurrentLocation = 0, mSleepTime = 0;
protected int mBufSize; protected int mBufSize;
protected String mConfigFPath;
protected IEventListener mListener; protected IEventListener mListener;
protected StateConstance STATE; protected StateConstance STATE;
protected SubThreadConfig<TASK_ENTITY> mConfig; protected SubThreadConfig<TASK_ENTITY> mConfig;
@ -84,7 +80,6 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
mConfig = info; mConfig = info;
mTaskEntity = mConfig.TASK_ENTITY; mTaskEntity = mConfig.TASK_ENTITY;
mEntity = mTaskEntity.getEntity(); mEntity = mTaskEntity.getEntity();
mConfigFPath = info.CONFIG_FILE_PATH;
mBufSize = manager.getDownloadConfig().getBuffSize(); mBufSize = manager.getDownloadConfig().getBuffSize();
setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxSpeed()); setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxSpeed());
mTaskType = getTaskType(); mTaskType = getTaskType();
@ -99,7 +94,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
mSleepTime = 0; mSleepTime = 0;
} else { } else {
BigDecimal db = new BigDecimal( 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(); 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++; STATE.CANCEL_NUM++;
ALog.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__取消"); ALog.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__取消");
if (STATE.isCancel()) { if (STATE.isCancel()) {
File configFile = new File(mConfigFPath);
if (configFile.exists()) {
configFile.delete();
}
if (mConfig.TEMP_FILE.exists() && !(mEntity instanceof UploadEntity)) { if (mConfig.TEMP_FILE.exists() && !(mEntity instanceof UploadEntity)) {
mConfig.TEMP_FILE.delete(); mConfig.TEMP_FILE.delete();
} }
@ -206,7 +197,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
} }
if (mConfig.SUPPORT_BP) { if (mConfig.SUPPORT_BP) {
writeConfig(false, currentLocation); writeConfig(false, currentLocation);
retryThis(STATE.THREAD_NUM != 1); retryThis(STATE.START_THREAD_NUM != 1);
} else { } else {
ALog.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败"); ALog.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
mListener.onFail(true); 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 { protected void writeConfig(boolean isComplete, final long record) throws IOException {
synchronized (AriaManager.LOCK) { if (mConfig.THREAD_RECORD != null) {
String key = null, value = null; mConfig.THREAD_RECORD.isComplete = isComplete;
if (record >= mConfig.END_LOCATION || isComplete) { if (0 < record && record < mConfig.END_LOCATION) {
key = mConfig.TEMP_FILE.getName() + AbsFileer.STATE + mConfig.THREAD_ID; mConfig.START_LOCATION = record;
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);
} }
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 CONNECT_TIME_OUT; //连接超时时间
public int READ_TIME_OUT; //流读取的超时时间 public int READ_TIME_OUT; //流读取的超时时间
public int COMPLETE_THREAD_NUM = 0; public int COMPLETE_THREAD_NUM = 0;
public int THREAD_NUM; public int START_THREAD_NUM; //启动的线程数
public long CURRENT_LOCATION = 0; public long CURRENT_LOCATION = 0;
public boolean isRunning = false; public boolean isRunning = false;
public boolean isCancel = false; public boolean isCancel = false;
public boolean isStop = false; public boolean isStop = false;
public TaskRecord TASK_RECORD;
public StateConstance() { public StateConstance() {
} }
@ -49,27 +50,28 @@ public class StateConstance {
* 所有子线程是否都已经停止下载 * 所有子线程是否都已经停止下载
*/ */
public boolean isStop() { public boolean isStop() {
return STOP_NUM == THREAD_NUM; return STOP_NUM == START_THREAD_NUM;
} }
/** /**
* 所有子线程是否都已经下载失败 * 所有子线程是否都已经下载失败
*/ */
public boolean isFail() { 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() { public boolean isComplete() {
return COMPLETE_THREAD_NUM >= THREAD_NUM; return COMPLETE_THREAD_NUM >= START_THREAD_NUM;
} }
/** /**
* 所有子线程是否都已经取消下载 * 所有子线程是否都已经取消下载
*/ */
public boolean isCancel() { 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 File TEMP_FILE;
//服务器地址 //服务器地址
public String URL; public String URL;
public String CONFIG_FILE_PATH;
public TASK_ENTITY TASK_ENTITY; public TASK_ENTITY TASK_ENTITY;
public boolean SUPPORT_BP = true; public boolean SUPPORT_BP = true;
public ThreadRecord THREAD_RECORD;
} }

@ -15,18 +15,62 @@
*/ */
package com.arialyy.aria.core.common; package com.arialyy.aria.core.common;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.orm.ActionPolicy;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.annotation.Foreign;
import com.arialyy.aria.orm.annotation.Ignore;
import com.arialyy.aria.orm.annotation.NoNull;
import com.arialyy.aria.orm.annotation.Primary;
import java.util.List;
/** /**
* Created by laoyuyu on 2018/3/21. * 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 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; @Ignore private List<DownloadEntity> subEntities;
/**
* 任务组下载文件的文件夹地址
*
* @see DownloadGroupTarget#setDirPath(String)
*/
private String dirPath;
/** /**
* 子任务实体列表 * 子任务实体列表
@ -47,14 +42,6 @@ public class DownloadGroupEntity extends AbsGroupEntity {
this.subEntities = subTasks; this.subEntities = subTasks;
} }
public String getDirPath() {
return dirPath;
}
public void setDirPath(String dirPath) {
this.dirPath = dirPath;
}
public void setGroupName(String key) { public void setGroupName(String key) {
this.groupName = key; this.groupName = key;
} }
@ -73,13 +60,11 @@ public class DownloadGroupEntity extends AbsGroupEntity {
@Override public void writeToParcel(Parcel dest, int flags) { @Override public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags); super.writeToParcel(dest, flags);
dest.writeTypedList(this.subEntities); dest.writeTypedList(this.subEntities);
dest.writeString(this.dirPath);
} }
protected DownloadGroupEntity(Parcel in) { protected DownloadGroupEntity(Parcel in) {
super(in); super(in);
this.subEntities = in.createTypedArrayList(DownloadEntity.CREATOR); this.subEntities = in.createTypedArrayList(DownloadEntity.CREATOR);
this.dirPath = in.readString();
} }
public static final Creator<DownloadGroupEntity> CREATOR = new Creator<DownloadGroupEntity>() { public static final Creator<DownloadGroupEntity> CREATOR = new Creator<DownloadGroupEntity>() {

@ -234,7 +234,7 @@ public abstract class AbsGroupUtil implements IUtil {
} }
} }
clearState(); clearState();
CommonUtil.delDownloadGroupTaskConfig(mGTEntity.isRemoveFile(), mGTEntity.getEntity()); CommonUtil.delGroupTaskRecord(mGTEntity.isRemoveFile(), mGTEntity.getEntity());
mListener.onCancel(); mListener.onCancel();
} }

@ -45,32 +45,17 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
} }
@Override protected int setNewTaskThreadNum() { @Override protected int setNewTaskThreadNum() {
return mEntity.getFileSize() <= SUB_LEN || mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP_DIR return
mEntity.getFileSize() <= SUB_LEN || mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP_DIR
? 1 ? 1
: AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum(); : AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum();
} }
@Override protected void checkTask() { @Override protected void checkTask() {
mConfigFile = new File(CommonUtil.getFileConfigPath(true, mEntity.getFileName())); super.checkTask();
mTempFile = new File(mEntity.getDownloadPath()); mTempFile = new File(mEntity.getDownloadPath());
if (!mTaskEntity.isSupportBP()) { mTaskEntity.setNewTask(!mTempFile.exists()
isNewTask = true; || DbEntity.findFirst(DownloadEntity.class, "url=?", mEntity.getUrl()) == null);
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();
}
} }
@Override protected boolean handleNewTask() { @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.core.inf.IDownloadListener;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile; import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPClient;
@ -107,10 +106,7 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
writeConfig(true, 1); writeConfig(true, 1);
STATE.COMPLETE_THREAD_NUM++; STATE.COMPLETE_THREAD_NUM++;
if (STATE.isComplete()) { if (STATE.isComplete()) {
File configFile = new File(mConfigFPath); STATE.TASK_RECORD.deleteData();
if (configFile.exists()) {
configFile.delete();
}
STATE.isRunning = false; STATE.isRunning = false;
mListener.onComplete(); mListener.onComplete();
} }

@ -148,6 +148,7 @@ class HttpFileInfoThread implements Runnable {
return; return;
} }
mEntity.setFileSize(len); mEntity.setFileSize(len);
mTaskEntity.setNewTask(true);
mTaskEntity.setSupportBP(false); mTaskEntity.setSupportBP(false);
end = true; end = true;
} else if (code == HttpURLConnection.HTTP_NOT_FOUND) { } else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
@ -180,7 +181,7 @@ class HttpFileInfoThread implements Runnable {
File oldFile = new File(mEntity.getDownloadPath()); File oldFile = new File(mEntity.getDownloadPath());
String oldName = oldFile.getName(); String oldName = oldFile.getName();
String newPath = oldFile.getParent() + "/" + newName; String newPath = oldFile.getParent() + "/" + newName;
if (oldFile.exists()){ if (oldFile.exists()) {
oldFile.renameTo(new File(newPath)); oldFile.renameTo(new File(newPath));
} }
mEntity.setFileName(newName); mEntity.setFileName(newName);

@ -25,7 +25,6 @@ import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile; import com.arialyy.aria.util.BufferedRandomAccessFile;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
@ -155,10 +154,7 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
writeConfig(true, 1); writeConfig(true, 1);
STATE.COMPLETE_THREAD_NUM++; STATE.COMPLETE_THREAD_NUM++;
if (STATE.isComplete()) { if (STATE.isComplete()) {
File configFile = new File(mConfigFPath); STATE.TASK_RECORD.deleteData();
if (configFile.exists()) {
configFile.delete();
}
STATE.isRunning = false; STATE.isRunning = false;
mListener.onComplete(); mListener.onComplete();
} }

@ -35,8 +35,24 @@ public abstract class AbsGroupEntity extends AbsEntity implements Parcelable {
*/ */
private String alias; private String alias;
/**
* 任务组下载文件的文件夹地址
*/
private String dirPath;
/**
* 子任务url地址
*/
private List<String> urls = new ArrayList<>(); private List<String> urls = new ArrayList<>();
public String getDirPath() {
return dirPath;
}
public void setDirPath(String dirPath) {
this.dirPath = dirPath;
}
public List<String> getUrls() { public List<String> getUrls() {
return urls; return urls;
} }

@ -23,7 +23,6 @@ import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity; import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile; import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPClient;
@ -82,10 +81,7 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
writeConfig(true, 1); writeConfig(true, 1);
STATE.COMPLETE_THREAD_NUM++; STATE.COMPLETE_THREAD_NUM++;
if (STATE.isComplete()) { if (STATE.isComplete()) {
File configFile = new File(mConfigFPath); STATE.TASK_RECORD.deleteData();
if (configFile.exists()) {
configFile.delete();
}
STATE.isRunning = false; STATE.isRunning = false;
mListener.onComplete(); mListener.onComplete();
} }
@ -114,7 +110,8 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
private void initPath() throws UnsupportedEncodingException { private void initPath() throws UnsupportedEncodingException {
dir = new String(mTaskEntity.getUrlEntity().remotePath.getBytes(charSet), SERVER_CHARSET); dir = new String(mTaskEntity.getUrlEntity().remotePath.getBytes(charSet), SERVER_CHARSET);
remotePath = new String( remotePath = new String(
("/" + mTaskEntity.getUrlEntity().remotePath + "/" + mEntity.getFileName()).getBytes(charSet), ("/" + mTaskEntity.getUrlEntity().remotePath + "/" + mEntity.getFileName()).getBytes(
charSet),
SERVER_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.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity; import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil;
import java.io.File; import java.io.File;
/** /**
@ -40,29 +39,11 @@ class Uploader extends AbsFileer<UploadEntity, UploadTaskEntity> {
AriaManager.getInstance(AriaManager.APP).getUploadConfig().getUpdateInterval()); AriaManager.getInstance(AriaManager.APP).getUploadConfig().getUpdateInterval());
} }
/**
* 检查任务是否是新任务新任务条件
* 1文件不存在
* 2记录文件不存在
* 3记录文件缺失或不匹配
* 4数据库记录不存在
* 5不支持断点则是新任务
*/
protected void checkTask() { protected void checkTask() {
mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName())); super.checkTask();
if (!mTaskEntity.isSupportBP()) { mTaskEntity.setNewTask(
isNewTask = true; DbEntity.findFirst(UploadEntity.class, "filePath=?", mEntity.getFilePath())
return; == null);
}
if (!mConfigFile.exists()) { //记录文件被删除,则重新下载
isNewTask = true;
CommonUtil.createFile(mConfigFile.getPath());
} else if (DbEntity.findFirst(UploadEntity.class, "filePath=?", mEntity.getFilePath())
== null) {
isNewTask = true;
} else {
isNewTask = checkConfigFile();
}
} }
@Override protected boolean handleNewTask() { @Override protected boolean handleNewTask() {

@ -16,6 +16,8 @@
package com.arialyy.aria.orm; package com.arialyy.aria.orm;
import android.text.TextUtils; 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.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity; import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; 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*/ /*adb pull /mnt/sdcard/Android/data/com.arialyy.simple/files/DB/AriaLyyDb d:/db*/
static Map<String, Class> mapping = new HashMap<>(); static Map<String, Class> mapping = new HashMap<>();
static String DB_NAME; static String DB_NAME;
static int VERSION = 31; static int VERSION = 32;
/** /**
* 是否将数据库保存在Sd卡{@code true} * 是否将数据库保存在Sd卡{@code true}
@ -56,5 +58,7 @@ class DBConfig {
mapping.put("UploadTaskEntity", UploadTaskEntity.class); mapping.put("UploadTaskEntity", UploadTaskEntity.class);
mapping.put("DownloadEntity", DownloadEntity.class); mapping.put("DownloadEntity", DownloadEntity.class);
mapping.put("UploadEntity", UploadEntity.class); mapping.put("UploadEntity", UploadEntity.class);
mapping.put("TaskRecord", TaskRecord.class);
mapping.put("ThreadRecord", ThreadRecord.class);
} }
} }

@ -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(","); sb.append(",");
} }

@ -51,6 +51,7 @@ class DelegateFind extends AbsDelegate {
* 如果查找不到数据或实体没有被{@link Wrapper}注解将返回null * 如果查找不到数据或实体没有被{@link Wrapper}注解将返回null
* 如果实体中没有{@link One}{@link Many}注解将返回null * 如果实体中没有{@link One}{@link Many}注解将返回null
* 如果实体中有多个{@link One}{@link Many}注解将返回nul * 如果实体中有多个{@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, <T extends AbsWrapper> List<T> findRelationData(SQLiteDatabase db, Class<T> clazz,
String... expression) { String... expression) {
@ -75,6 +76,10 @@ class DelegateFind extends AbsDelegate {
ALog.w(TAG, "查询数据失败,实体中有多个@Many 注解"); ALog.w(TAG, "查询数据失败,实体中有多个@Many 注解");
return null; return null;
} }
if (!field.getType().isAssignableFrom(List.class)) {
ALog.w(TAG, "查询数据失败,@Many 注解的类型不是List");
return null;
}
hasMany = true; hasMany = true;
many = field; many = field;
} }
@ -499,10 +504,16 @@ class DelegateFind extends AbsDelegate {
/** /**
* 通过rowId判断数据是否存在 * 通过rowId判断数据是否存在
*/ */
<T extends DbEntity> boolean itemExist(SQLiteDatabase db, Class<T> clazz, <T extends DbEntity> boolean itemExist(SQLiteDatabase db, Class<T> clazz, long rowId) {
long rowId) { return itemExist(db, CommonUtil.getClassName(clazz), rowId);
}
/**
* 通过rowId判断数据是否存在
*/
boolean itemExist(SQLiteDatabase db, String tableName, long rowId) {
db = checkDb(db); 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); print(ROW_ID, sql);
Cursor cursor = db.rawQuery(sql, null); Cursor cursor = db.rawQuery(sql, null);
boolean isExist = cursor.getCount() > 0; boolean isExist = cursor.getCount() > 0;

@ -18,7 +18,6 @@ package com.arialyy.aria.orm;
import android.content.ContentValues; import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.orm.annotation.Primary; import com.arialyy.aria.orm.annotation.Primary;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CheckUtil;
@ -36,6 +35,50 @@ class DelegateUpdate extends AbsDelegate {
private DelegateUpdate() { 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); db = checkDb(db);
Class<?> clazz = dbEntity.getClass(); Class<?> clazz = dbEntity.getClass();
List<Field> fields = CommonUtil.getAllFields(clazz); List<Field> fields = CommonUtil.getAllFields(clazz);
//DbEntity cacheEntity = mDataCache.get(getCacheKey(dbEntity));
if (fields != null && fields.size() > 0) { if (fields != null && fields.size() > 0) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
try { try {
@ -71,14 +113,6 @@ class DelegateUpdate extends AbsDelegate {
if (isIgnore(dbEntity, field)) { if (isIgnore(dbEntity, field)) {
continue; 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; String value;
Type type = field.getType(); Type type = field.getType();
if (type == Map.class && checkMap(field)) { if (type == Map.class && checkMap(field)) {
@ -101,7 +135,6 @@ class DelegateUpdate extends AbsDelegate {
ALog.d(TAG, "没有数据更新"); ALog.d(TAG, "没有数据更新");
} }
} }
//mDataCache.put(getCacheKey(dbEntity), dbEntity);
close(db); close(db);
} }
@ -137,7 +170,6 @@ class DelegateUpdate extends AbsDelegate {
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
e.printStackTrace(); e.printStackTrace();
} }
//print(INSERT_DATA, );
dbEntity.rowID = db.insert(CommonUtil.getClassName(dbEntity), null, values); dbEntity.rowID = db.insert(CommonUtil.getClassName(dbEntity), null, values);
} }
close(db); close(db);

@ -56,6 +56,13 @@ public class DelegateWrapper {
return INSTANCE; return INSTANCE;
} }
///**
// * 保存关联数据
// */
//void saveRelationData(AbsWrapper wrapper){
//
//}
/** /**
* 查询关联表数据 * 查询关联表数据
* *
@ -125,6 +132,13 @@ public class DelegateWrapper {
return mDManager.getDelegate(DelegateFind.class).itemExist(mDb, clazz, rowId); 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.NoNull;
import com.arialyy.aria.orm.annotation.One; import com.arialyy.aria.orm.annotation.One;
import com.arialyy.aria.orm.annotation.Primary; 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.orm.annotation.Wrapper;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@ -247,6 +248,16 @@ final class SqlUtil {
return nn != null; 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) { private static Object checkData(String type, String data) {
if (type.equalsIgnoreCase("java.lang.String")) { if (type.equalsIgnoreCase("java.lang.String")) {
return data; 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.group.GroupCmdFactory;
import com.arialyy.aria.core.command.normal.AbsNormalCmd; import com.arialyy.aria.core.command.normal.AbsNormalCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory; 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.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity; 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.AbsGroupTaskEntity;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.orm.DbEntity;
import java.io.File; import java.io.File;
import java.io.FileFilter; import java.io.FileFilter;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -65,6 +69,7 @@ import java.util.regex.Pattern;
/** /**
* Created by lyy on 2016/1/22. * Created by lyy on 2016/1/22.
* 通用工具
*/ */
public class CommonUtil { public class CommonUtil {
private static final String TAG = "CommonUtil"; private static final String TAG = "CommonUtil";
@ -82,7 +87,7 @@ public class CommonUtil {
String reg = Regular.REG_WINLOD_REPLACE; String reg = Regular.REG_WINLOD_REPLACE;
Pattern p = Pattern.compile(reg); Pattern p = Pattern.compile(reg);
Matcher m = p.matcher(text); Matcher m = p.matcher(text);
if (m.find()){ if (m.find()) {
String s = m.group(); String s = m.group();
s = s.substring(9, s.length() - 2); s = s.substring(9, s.length() - 2);
return s; return s;
@ -356,20 +361,27 @@ public class CommonUtil {
} }
/** /**
* 删除下载任务组的配置 * 删除任务组记录
* *
* @param removeFile {@code true} 不仅删除任务数据库记录还会删除已经删除完成的文件 * @param removeFile {@code true} 不仅删除任务数据库记录还会删除已经删除完成的文件
* {@code false}如果任务已经完成只删除任务数据库记录 * {@code false}如果任务已经完成只删除任务数据库记录
*/ */
public static void delDownloadGroupTaskConfig(boolean removeFile, public static void delGroupTaskRecord(boolean removeFile, AbsGroupEntity groupEntity) {
DownloadGroupEntity groupEntity) {
if (groupEntity == null) { if (groupEntity == null) {
ALog.e(TAG, "删除下载任务组记录失败,任务组实体为null"); ALog.e(TAG, "删除下载任务组记录失败,任务组实体为null");
return; return;
} }
List<TaskRecord> records = DbEntity.findDatas(TaskRecord.class,
groupEntity instanceof DownloadGroupEntity ? "dGroupName=?" : "uGroupName=?",
groupEntity.getGroupName());
for (DownloadEntity taskEntity : groupEntity.getSubEntities()) { if (records == null || records.isEmpty()) {
delDownloadTaskConfig(removeFile, taskEntity); ALog.w(TAG, "组任务记录删除失败,记录为null");
return;
}
for (TaskRecord tr : records) {
tr.deleteData();
} }
File dir = new File(groupEntity.getDirPath()); 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} 不仅删除任务数据库记录还会删除已经下载完成的文件 * @param removeFile {@code true} 不仅删除任务数据库记录还会删除已经下载完成的文件
* {@code false}如果任务已经完成只删除任务数据库记录 * {@code false}如果任务已经完成只删除任务数据库记录
*/ */
public static void delDownloadTaskConfig(boolean removeFile, DownloadEntity dEntity) { public static void delTaskRecord(TaskRecord record, boolean removeFile,
AbsNormalEntity dEntity) {
if (dEntity == null) return; 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 (removeFile) {
if (file.exists()) { if (file.exists()) {
file.delete(); file.delete();
@ -430,9 +427,8 @@ public class CommonUtil {
} }
} }
File config = new File(getFileConfigPath(true, dEntity.getFileName())); if (record != null) {
if (config.exists()) { record.deleteData();
config.delete();
} }
//下载任务实体和下载实体为一对一关系,下载实体删除,任务实体自动删除 //下载任务实体和下载实体为一对一关系,下载实体删除,任务实体自动删除
dEntity.deleteData(); dEntity.deleteData();

Loading…
Cancel
Save