Merge branch '3.4.1'

pull/330/head
laoyuyu 7 years ago
commit 0259ecb9bc
  1. 18
      Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
  2. 29
      Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java
  3. 1
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java
  4. 227
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
  5. 3
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpThreadTask.java
  6. 45
      Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java
  7. 40
      Aria/src/main/java/com/arialyy/aria/core/common/ProxyHelper.java
  8. 45
      Aria/src/main/java/com/arialyy/aria/core/common/RecordWrapper.java
  9. 14
      Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java
  10. 2
      Aria/src/main/java/com/arialyy/aria/core/common/SubThreadConfig.java
  11. 56
      Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java
  12. 50
      Aria/src/main/java/com/arialyy/aria/core/common/ThreadRecord.java
  13. 15
      Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java
  14. 3
      Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java
  15. 17
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java
  16. 2
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
  17. 1
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java
  18. 5
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java
  19. 8
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java
  20. 2
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
  21. 1
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java
  22. 38
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java
  23. 24
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java
  24. 5
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
  25. 33
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
  26. 4
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java
  27. 16
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java
  28. 2
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java
  29. 10
      Aria/src/main/java/com/arialyy/aria/core/manager/UTEFactory.java
  30. 10
      Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java
  31. 1
      Aria/src/main/java/com/arialyy/aria/core/queue/DownloadGroupTaskQueue.java
  32. 1
      Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java
  33. 1
      Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java
  34. 19
      Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java
  35. 1
      Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java
  36. 14
      Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java
  37. 38
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpFileInfoThread.java
  38. 15
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java
  39. 12
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java
  40. 26
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/Uploader.java
  41. 8
      Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java
  42. 7
      Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java
  43. 4
      Aria/src/main/java/com/arialyy/aria/orm/DelegateCommon.java
  44. 17
      Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java
  45. 56
      Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java
  46. 14
      Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java
  47. 11
      Aria/src/main/java/com/arialyy/aria/orm/SqlUtil.java
  48. 29
      Aria/src/main/java/com/arialyy/aria/orm/annotation/Unique.java
  49. 176
      Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
  50. 42
      Aria/src/main/java/com/arialyy/aria/util/DbHelper.java
  51. 4
      AriaCompiler/src/main/java/com/arialyy/compiler/CountFiler.java
  52. 7
      DEV_LOG.md
  53. 19
      README.md
  54. 16
      app/build.gradle
  55. 4
      app/src/main/AndroidManifest.xml
  56. 21
      app/src/main/assets/aria_config.xml
  57. 20
      app/src/main/java/com/arialyy/simple/test/AnyRunActivity.java
  58. 50
      app/src/main/java/com/arialyy/simple/test/AnyRunnModule.java
  59. 13
      app/src/main/java/com/arialyy/simple/test/TestActivity.java
  60. 95
      aria/src/main/java/com/arialyy/aria/core/Configuration.java
  61. 5
      aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java
  62. 2
      build.gradle

@ -77,8 +77,8 @@ import org.xml.sax.SAXException;
private Configuration.AppConfig mAConfig; private Configuration.AppConfig mAConfig;
private AriaManager(Context context) { private AriaManager(Context context) {
DelegateWrapper.init(context.getApplicationContext());
APP = context.getApplicationContext(); APP = context.getApplicationContext();
initDb(APP);
regAppLifeCallback(context); regAppLifeCallback(context);
initConfig(); initConfig();
initAria(); initAria();
@ -100,6 +100,20 @@ import org.xml.sax.SAXException;
return INSTANCE; return INSTANCE;
} }
private void initDb(Context context) {
String dbBase = context.getFilesDir().getPath() + context.getPackageName() + "/databases/";
File db = new File(dbBase + "AriaLyyDb");
File dbConfig = new File(dbBase + "AriaLyyDb-journal");
if (db.exists()) {
db.renameTo(new File(dbBase + "AndroidAria.db"));
// 如果数据库是在/data/data/{packagename}/databases/下面,journal文件因权限问题将无法删除和重命名
if (dbConfig.exists()) {
dbConfig.delete();
}
}
DelegateWrapper.init(context.getApplicationContext());
}
private void initAria() { private void initAria() {
if (mAConfig.getUseAriaCrashHandler()) { if (mAConfig.getUseAriaCrashHandler()) {
Thread.setDefaultUncaughtExceptionHandler(new AriaCrashHandler()); Thread.setDefaultUncaughtExceptionHandler(new AriaCrashHandler());
@ -363,7 +377,7 @@ import org.xml.sax.SAXException;
} else { } else {
try { try {
String md5Code = CommonUtil.getFileMD5(xmlFile); String md5Code = CommonUtil.getFileMD5(xmlFile);
File file = new File(APP.getFilesDir().getPath() + "temp.xml"); File file = new File(APP.getFilesDir().getPath() + "/temp.xml");
if (file.exists()) { if (file.exists()) {
file.delete(); file.delete();
} }

@ -59,6 +59,9 @@ class ConfigHelper extends DefaultHandler {
String value = attributes.getValue("value"); String value = attributes.getValue("value");
switch (qName) { switch (qName) {
case "openDynamicFile":
loadOpenDynamicFile(value);
break;
case "threadNum": case "threadNum":
loadThreadNum(value); loadThreadNum(value);
break; break;
@ -97,6 +100,9 @@ class ConfigHelper extends DefaultHandler {
case "updateInterval": case "updateInterval":
loadUpdateInterval(value); loadUpdateInterval(value);
break; break;
case "notNetRetry":
loadNotNetRetry(value);
break;
} }
} else if (isAppConfig) { } else if (isAppConfig) {
String value = attributes.getValue("value"); String value = attributes.getValue("value");
@ -111,6 +117,21 @@ class ConfigHelper extends DefaultHandler {
} }
} }
private void loadOpenDynamicFile(String value) {
if (isDownloadConfig) {
mDownloadConfig.openDynamicFile = checkBoolean(value) ? Boolean.valueOf(value) : false;
}
}
private void loadNotNetRetry(String value) {
if (isDownloadConfig) {
mDownloadConfig.notNetRetry = checkBoolean(value) ? Boolean.valueOf(value) : false;
}
if (isUploadConfig) {
mUploadConfig.notNetRetry = checkBoolean(value) ? Boolean.valueOf(value) : false;
}
}
private void loadLogLevel(String value) { private void loadLogLevel(String value) {
int level; int level;
try { try {
@ -210,6 +231,10 @@ class ConfigHelper extends DefaultHandler {
if (isDownloadConfig) { if (isDownloadConfig) {
mDownloadConfig.buffSize = buffSize; mDownloadConfig.buffSize = buffSize;
} }
if (isUploadConfig) {
mUploadConfig.buffSize = buffSize;
}
} }
private void loadIOTimeout(String value) { private void loadIOTimeout(String value) {
@ -222,6 +247,10 @@ class ConfigHelper extends DefaultHandler {
if (isDownloadConfig) { if (isDownloadConfig) {
mDownloadConfig.iOTimeOut = time; mDownloadConfig.iOTimeOut = time;
} }
if (isUploadConfig) {
mUploadConfig.iOTimeOut = time;
}
} }
private void loadConnectTime(String value) { private void loadConnectTime(String value) {

@ -56,7 +56,6 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
return; return;
} }
String mod; String mod;
// TODO: 2018/4/12 配置文件不存在,是否会出现wait获取不到 ?
int maxTaskNum = mQueue.getMaxTaskNum(); int maxTaskNum = mQueue.getMaxTaskNum();
AriaManager manager = AriaManager.getInstance(AriaManager.APP); AriaManager manager = AriaManager.getInstance(AriaManager.APP);
if (isDownloadCmd) { if (isDownloadCmd) {

@ -19,16 +19,18 @@ 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 com.arialyy.aria.util.DbHelper;
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 +52,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 +68,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;
protected TaskRecord mRecord;
protected AbsFileer(IEventListener listener, TASK_ENTITY taskEntity) { protected AbsFileer(IEventListener listener, TASK_ENTITY taskEntity) {
mListener = listener; mListener = listener;
@ -104,19 +110,20 @@ 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; mTotalThreadNum =
mConstance.THREAD_NUM = mTotalThreadNum; mTaskEntity.isNewTask() ? (mStartThreadNum = setNewTaskThreadNum()) : mTotalThreadNum;
handleBreakpoint(); handleBreakpoint();
} }
mConstance.START_THREAD_NUM = mTotalThreadNum;
startTimer(); startTimer();
} }
@ -193,13 +200,6 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
task.cancel(); 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());
}
} }
@Override public void stop() { @Override public void stop() {
@ -230,53 +230,131 @@ 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 {
mRecord = DbHelper.getTaskRecord(mTaskEntity.getKey());
if (mRecord == null) {
initRecord();
mTaskEntity.setNewTask(true);
} else {
if (mRecord.threadRecords == null || mRecord.threadRecords.isEmpty()) {
initRecord();
mTaskEntity.setNewTask(true);
} else if (mTempFile.length() == 0) {
mRecord.deleteData();
initRecord();
mTaskEntity.setNewTask(true);
} else {
for (ThreadRecord tr : mRecord.threadRecords) {
if (tr.isComplete) {
mCompleteThreadNum++;
} else {
mStartThreadNum++;
}
}
mTotalThreadNum = mRecord.threadRecords.size();
mTaskEntity.setNewTask(false);
}
}
}
}
/** /**
* 检查记录文件如果是新任务返回{@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);
}
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();
mRecord.isOpenDynamicFile =
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().isOpenDynamicFile();
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 +369,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 +385,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 +394,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 +477,6 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
mFixedThreadPool.execute(task); mFixedThreadPool.execute(task);
} }
} }
mTaskEntity.setNewTask(false);
} }
/** /**
@ -411,7 +497,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);

@ -98,7 +98,8 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
charSet = mTaskEntity.getCharSet(); charSet = mTaskEntity.getCharSet();
} }
client.setControlEncoding(charSet); client.setControlEncoding(charSet);
client.setDataTimeout(10 * 1000); client.setDataTimeout(mReadTimeOut);
client.setConnectTimeout(mConnectTimeOut);
client.enterLocalPassiveMode(); client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE); client.setFileType(FTP.BINARY_FILE_TYPE);
client.setControlKeepAliveTimeout(5000); client.setControlKeepAliveTimeout(5000);

@ -16,20 +16,16 @@
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.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 +48,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;
@ -63,6 +58,10 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
private Timer mFailTimer; private Timer mFailTimer;
private long mLastSaveTime; private long mLastSaveTime;
private ExecutorService mConfigThreadPool; private ExecutorService mConfigThreadPool;
protected int mConnectTimeOut; //连接超时时间
protected int mReadTimeOut; //流读取的超时时间
protected boolean isNotNetRetry = false; //断网情况是否重试
private Thread mConfigThread = new Thread(new Runnable() { private Thread mConfigThread = new Thread(new Runnable() {
@Override public void run() { @Override public void run() {
final long currentTemp = mChildCurrentLocation; final long currentTemp = mChildCurrentLocation;
@ -76,17 +75,11 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
protected AbsThreadTask(StateConstance constance, IEventListener listener, protected AbsThreadTask(StateConstance constance, IEventListener listener,
SubThreadConfig<TASK_ENTITY> info) { SubThreadConfig<TASK_ENTITY> info) {
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
STATE = constance; STATE = constance;
STATE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut();
STATE.READ_TIME_OUT = manager.getDownloadConfig().getIOTimeOut();
mListener = listener; mListener = listener;
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();
setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxSpeed());
mTaskType = getTaskType(); mTaskType = getTaskType();
mLastSaveTime = System.currentTimeMillis(); mLastSaveTime = System.currentTimeMillis();
mConfigThreadPool = Executors.newCachedThreadPool(); mConfigThreadPool = Executors.newCachedThreadPool();
@ -99,7 +92,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 +167,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 +195,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);
@ -228,13 +217,14 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
mFailTimer.purge(); mFailTimer.purge();
mFailTimer.cancel(); mFailTimer.cancel();
} }
if (!NetUtils.isConnected(AriaManager.APP)) { if (!NetUtils.isConnected(AriaManager.APP) && !isNotNetRetry) {
ALog.w(TAG, ALog.w(TAG,
"任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__重试失败,网络未连接"); "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__重试失败,网络未连接");
} }
if (mFailNum < RETRY_NUM if (mFailNum < RETRY_NUM
&& needRetry && needRetry
&& NetUtils.isConnected(AriaManager.APP) && NetUtils.isConnected(AriaManager.APP)
&& !isNotNetRetry
&& !STATE.isCancel && !STATE.isCancel
&& !STATE.isStop) { && !STATE.isStop) {
mFailTimer = new Timer(true); mFailTimer = new Timer(true);
@ -264,21 +254,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.THREAD_RECORD.startLocation = 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();
} }
} }
} }

@ -16,12 +16,14 @@
package com.arialyy.aria.core.common; package com.arialyy.aria.core.common;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import static java.util.Collections.unmodifiableSet;
/** /**
* Created by Aria.Lao on 2017/7/10. * Created by Aria.Lao on 2017/7/10.
* 代理参数获取 * 代理参数获取
@ -45,8 +47,18 @@ public class ProxyHelper {
} }
private void init() { private void init() {
List<String> classes = CommonUtil.getClassName(AriaManager.APP, "com.arialyy.aria");
for (String className : classes) {
if (!className.startsWith("com.arialyy.aria.ProxyClassCounter")){
continue;
}
count(className);
}
}
private void count(String className) {
try { try {
Class clazz = Class.forName("com.arialyy.aria.ProxyClassCounter"); Class clazz = Class.forName(className);
Method download = clazz.getMethod("getDownloadCounter"); Method download = clazz.getMethod("getDownloadCounter");
Method downloadGroup = clazz.getMethod("getDownloadGroupCounter"); Method downloadGroup = clazz.getMethod("getDownloadGroupCounter");
Method downloadGroupSub = clazz.getMethod("getDownloadGroupSubCounter"); Method downloadGroupSub = clazz.getMethod("getDownloadGroupSubCounter");
@ -54,19 +66,31 @@ public class ProxyHelper {
Object object = clazz.newInstance(); Object object = clazz.newInstance();
Object dc = download.invoke(object); Object dc = download.invoke(object);
if (dc != null) { if (dc != null) {
downloadCounter = unmodifiableSet((Set<String>) dc); if (downloadCounter == null) {
downloadCounter = new HashSet<>();
}
downloadCounter.addAll((Set<String>) dc);
} }
Object dgc = downloadGroup.invoke(object); Object dgc = downloadGroup.invoke(object);
if (dgc != null) { if (dgc != null) {
downloadGroupCounter = unmodifiableSet((Set<String>) dgc); if (downloadGroupCounter == null) {
downloadGroupCounter = new HashSet<>();
}
downloadGroupCounter.addAll((Set<String>) dgc);
} }
Object dgsc = downloadGroupSub.invoke(object); Object dgsc = downloadGroupSub.invoke(object);
if (dgsc != null){ if (dgsc != null) {
downloadGroupSubCounter = unmodifiableSet((Set<? extends String>) dgsc); if (downloadGroupSubCounter == null) {
downloadGroupSubCounter = new HashSet<>();
}
downloadGroupSubCounter.addAll((Set<String>) dgsc);
} }
Object uc = upload.invoke(object); Object uc = upload.invoke(object);
if (uc != null) { if (uc != null) {
uploadCounter = unmodifiableSet((Set<String>) uc); if (uploadCounter == null) {
uploadCounter = new HashSet<>();
}
uploadCounter.addAll((Set<String>) uc);
} }
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
e.printStackTrace(); e.printStackTrace();

@ -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<>();
}
}
}

@ -23,14 +23,13 @@ public class StateConstance {
public int CANCEL_NUM = 0; public int CANCEL_NUM = 0;
public int STOP_NUM = 0; public int STOP_NUM = 0;
public int FAIL_NUM = 0; public int FAIL_NUM = 0;
public int CONNECT_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 +48,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,68 @@
*/ */
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;
/**
* 是否是使用虚拟文件下载的
* {@code true}{@code false}不是
*/
public boolean isOpenDynamicFile = false;
} }

@ -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;
}

@ -17,12 +17,16 @@ package com.arialyy.aria.core.download;
import android.os.Handler; import android.os.Handler;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.TaskRecord;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsGroupEntity;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTask; import com.arialyy.aria.core.inf.AbsTask;
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.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.scheduler.ISchedulers; import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -154,7 +158,16 @@ class BaseDListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<
mEntity.setState(state); mEntity.setState(state);
mEntity.setComplete(state == IEntity.STATE_COMPLETE); mEntity.setComplete(state == IEntity.STATE_COMPLETE);
if (state == IEntity.STATE_CANCEL) { if (state == IEntity.STATE_CANCEL) {
mEntity.deleteData(); if (mEntity instanceof AbsNormalEntity) {
TaskRecord record =
DbEntity.findFirst(TaskRecord.class, "TaskRecord.filePath=?", mTaskEntity.getKey());
if (record != null) {
CommonUtil.delTaskRecord(record, mTaskEntity.isRemoveFile(), (AbsNormalEntity) mEntity);
}
} else if (mEntity instanceof AbsGroupEntity) {
CommonUtil.delGroupTaskRecord(mTaskEntity.isRemoveFile(), ((AbsGroupEntity) mEntity));
}
//mEntity.deleteData();
return; return;
} else if (mEntity.isComplete()) { } else if (mEntity.isComplete()) {
mEntity.setCompleteTime(System.currentTimeMillis()); mEntity.setCompleteTime(System.currentTimeMillis());

@ -150,10 +150,9 @@ abstract class BaseNormalTarget<TARGET extends BaseNormalTarget>
mEntity.setDownloadPath(filePath); mEntity.setDownloadPath(filePath);
mEntity.setFileName(newFile.getName()); mEntity.setFileName(newFile.getName());
mTaskEntity.setKey(filePath); mTaskEntity.setKey(filePath);
//mTaskEntity.update();
if (oldFile.exists()) { if (oldFile.exists()) {
oldFile.renameTo(newFile); oldFile.renameTo(newFile);
CommonUtil.renameDownloadConfig(oldFile.getName(), newFile.getName()); CommonUtil.modifyTaskRecord(oldFile.getPath(), newFile.getPath());
} }
} }
return true; return true;

@ -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>() {

@ -224,7 +224,7 @@ public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
if (oldFile.exists()) { if (oldFile.exists()) {
oldFile.renameTo(new File(newPath)); oldFile.renameTo(new File(newPath));
} }
CommonUtil.renameDownloadConfig(oldFile.getName(), newName); CommonUtil.modifyTaskRecord(oldFile.getPath(), newPath);
entity.setDownloadPath(newPath); entity.setDownloadPath(newPath);
taskEntity.setKey(newPath); taskEntity.setKey(newPath);
entity.setFileName(newName); entity.setFileName(newName);

@ -49,7 +49,6 @@ public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
/** /**
* 是否使用服务器通过content-disposition传递的文件名内容格式{@code attachment;filename=***} * 是否使用服务器通过content-disposition传递的文件名内容格式{@code attachment;filename=***}
* 如果获取不到服务器文件名则使用用户设置的文件名 * 如果获取不到服务器文件名则使用用户设置的文件名
* 只适用于HTTP请求
* *
* @param use {@code true} 使用 * @param use {@code true} 使用
*/ */

@ -137,10 +137,11 @@ public class DownloadTask extends AbsNormalTask<DownloadTaskEntity> {
* 取消下载 * 取消下载
*/ */
@Override public void cancel() { @Override public void cancel() {
if (!mUtil.isRunning()) { if (mUtil.isRunning()) {
mUtil.cancel();
} else {
mListener.onCancel(); mListener.onCancel();
} }
mUtil.cancel();
} }
@Override public String getTaskName() { @Override public String getTaskName() {

@ -73,6 +73,10 @@ public class DownloadTaskEntity extends AbsNormalTaskEntity<DownloadEntity> {
return key; return key;
} }
@Override public void setKey(String key) {
this.key = key;
}
public String getUrl() { public String getUrl() {
return url; return url;
} }
@ -109,7 +113,5 @@ public class DownloadTaskEntity extends AbsNormalTaskEntity<DownloadEntity> {
isGroupTask = groupTask; isGroupTask = groupTask;
} }
public void setKey(String key) {
this.key = key;
}
} }

@ -68,8 +68,6 @@ public class FtpDownloadTarget extends BaseNormalTarget<FtpDownloadTarget>
* 关于文件名 * 关于文件名
* 1如果保存路径是该文件的保存路径/mnt/sdcard/file.zip则使用路径中的文件名file.zip * 1如果保存路径是该文件的保存路径/mnt/sdcard/file.zip则使用路径中的文件名file.zip
* 2如果保存路径是文件夹路径/mnt/sdcard/则使用FTP服务器该文件的文件名 * 2如果保存路径是文件夹路径/mnt/sdcard/则使用FTP服务器该文件的文件名
*
* @param filePath 路径必须为文件路径不能为文件夹路径
*/ */
public FtpDownloadTarget setFilePath(@NonNull String filePath) { public FtpDownloadTarget setFilePath(@NonNull String filePath) {
mTempFilePath = filePath; mTempFilePath = filePath;

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

@ -23,7 +23,6 @@ import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
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.orm.DbEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.BufferedRandomAccessFile; import com.arialyy.aria.util.BufferedRandomAccessFile;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
@ -40,46 +39,29 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
Downloader(IDownloadListener listener, DownloadTaskEntity taskEntity) { Downloader(IDownloadListener listener, DownloadTaskEntity taskEntity) {
super(listener, taskEntity); super(listener, taskEntity);
setUpdateInterval( mTempFile = new File(mEntity.getDownloadPath());
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getUpdateInterval()); AriaManager manager = AriaManager.getInstance(AriaManager.APP);
setUpdateInterval(manager.getDownloadConfig().getUpdateInterval());
} }
@Override protected int setNewTaskThreadNum() { @Override protected int setNewTaskThreadNum() {
return mEntity.getFileSize() <= SUB_LEN || mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP_DIR return
// 小于1m的文件或是任务组的子任务、使用虚拟文件,线程数都是1
mEntity.getFileSize() <= SUB_LEN
|| mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP_DIR
|| mTaskEntity.getRequestType() == AbsTaskEntity.DG_HTTP
|| mRecord.isOpenDynamicFile
? 1 ? 1
: AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum(); : AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum();
} }
@Override protected void checkTask() {
mConfigFile = new File(CommonUtil.getFileConfigPath(true, mEntity.getFileName()));
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();
}
}
@Override protected boolean handleNewTask() { @Override protected boolean handleNewTask() {
CommonUtil.createFile(mTempFile.getPath()); CommonUtil.createFile(mTempFile.getPath());
BufferedRandomAccessFile file = null; BufferedRandomAccessFile file = null;
try { try {
file = new BufferedRandomAccessFile(new File(mTempFile.getPath()), "rwd", 8192); file = new BufferedRandomAccessFile(new File(mTempFile.getPath()), "rwd", 8192);
//设置文件长度 //设置文件长度
file.setLength(mEntity.getFileSize()); file.setLength(mRecord.isOpenDynamicFile ? 1 : mEntity.getFileSize());
return true; return true;
} catch (IOException e) { } catch (IOException e) {
failDownload("下载失败【downloadUrl:" failDownload("下载失败【downloadUrl:"

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsFtpThreadTask; import com.arialyy.aria.core.common.AbsFtpThreadTask;
import com.arialyy.aria.core.common.StateConstance; import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
@ -23,7 +24,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;
@ -35,10 +35,22 @@ import org.apache.commons.net.ftp.FTPReply;
*/ */
class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity> { class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity> {
private final String TAG = "FtpThreadTask"; private final String TAG = "FtpThreadTask";
private boolean isOpenDynamicFile;
/**
* 2M的动态长度
*/
private final int LEN_INTERVAL = 1024 * 1024 * 2;
FtpThreadTask(StateConstance constance, IDownloadListener listener, FtpThreadTask(StateConstance constance, IDownloadListener listener,
SubThreadConfig<DownloadTaskEntity> downloadInfo) { SubThreadConfig<DownloadTaskEntity> downloadInfo) {
super(constance, listener, downloadInfo); super(constance, listener, downloadInfo);
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
mConnectTimeOut = manager.getDownloadConfig().getConnectTimeOut();
mReadTimeOut = manager.getDownloadConfig().getIOTimeOut();
mBufSize = manager.getDownloadConfig().getBuffSize();
isNotNetRetry = manager.getDownloadConfig().isNotNetRetry();
isOpenDynamicFile = STATE.TASK_RECORD.isOpenDynamicFile;
setMaxSpeed(manager.getDownloadConfig().getMaxSpeed());
} }
@Override public void run() { @Override public void run() {
@ -92,6 +104,11 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
break; break;
} }
if (mSleepTime > 0) Thread.sleep(mSleepTime); if (mSleepTime > 0) Thread.sleep(mSleepTime);
if (isOpenDynamicFile) {
file.setLength(
STATE.CURRENT_LOCATION + LEN_INTERVAL < mEntity.getFileSize() ? STATE.CURRENT_LOCATION
+ LEN_INTERVAL : mEntity.getFileSize());
}
if (mChildCurrentLocation + len >= mConfig.END_LOCATION) { if (mChildCurrentLocation + len >= mConfig.END_LOCATION) {
len = (int) (mConfig.END_LOCATION - mChildCurrentLocation); len = (int) (mConfig.END_LOCATION - mChildCurrentLocation);
file.write(buffer, 0, len); file.write(buffer, 0, len);
@ -107,10 +124,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) {
@ -178,15 +179,13 @@ class HttpFileInfoThread implements Runnable {
return; return;
} }
File oldFile = new File(mEntity.getDownloadPath()); File oldFile = new File(mEntity.getDownloadPath());
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);
mEntity.setDownloadPath(newPath); mEntity.setDownloadPath(newPath);
mTaskEntity.setKey(newPath); mTaskEntity.setKey(newPath);
CommonUtil.renameDownloadConfig(oldName, newName);
} }
/** /**

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsThreadTask; import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.common.StateConstance; import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
@ -25,10 +26,8 @@ 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.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
@ -39,10 +38,22 @@ import java.net.URL;
*/ */
final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEntity> { final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEntity> {
private final String TAG = "HttpThreadTask"; private final String TAG = "HttpThreadTask";
/**
* 2M的动态长度
*/
private final int LEN_INTERVAL = 1024 * 1024 * 2;
private boolean isOpenDynamicFile;
HttpThreadTask(StateConstance constance, IDownloadListener listener, HttpThreadTask(StateConstance constance, IDownloadListener listener,
SubThreadConfig<DownloadTaskEntity> downloadInfo) { SubThreadConfig<DownloadTaskEntity> downloadInfo) {
super(constance, listener, downloadInfo); super(constance, listener, downloadInfo);
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
mConnectTimeOut = manager.getDownloadConfig().getConnectTimeOut();
mReadTimeOut = manager.getDownloadConfig().getIOTimeOut();
mBufSize = manager.getDownloadConfig().getBuffSize();
isNotNetRetry = manager.getDownloadConfig().isNotNetRetry();
isOpenDynamicFile = STATE.TASK_RECORD.isOpenDynamicFile;
setMaxSpeed(manager.getDownloadConfig().getMaxSpeed());
} }
@Override public void run() { @Override public void run() {
@ -71,8 +82,8 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
ALog.w(TAG, "该下载不支持断点"); ALog.w(TAG, "该下载不支持断点");
} }
conn = ConnectionHelp.setConnectParam(mConfig.TASK_ENTITY, conn); conn = ConnectionHelp.setConnectParam(mConfig.TASK_ENTITY, conn);
conn.setConnectTimeout(STATE.CONNECT_TIME_OUT); conn.setConnectTimeout(mConnectTimeOut);
conn.setReadTimeout(STATE.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数 conn.setReadTimeout(mReadTimeOut); //设置读取流的等待时间,必须设置该参数
is = new BufferedInputStream(ConnectionHelp.convertInputStream(conn)); is = new BufferedInputStream(ConnectionHelp.convertInputStream(conn));
//创建可设置位置的文件 //创建可设置位置的文件
@ -118,7 +129,7 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
* *
* @deprecated 暂时先这样处理无chun * @deprecated 暂时先这样处理无chun
*/ */
private void readChunk(InputStream is, RandomAccessFile file) private void readChunk(InputStream is, BufferedRandomAccessFile file)
throws IOException, InterruptedException { throws IOException, InterruptedException {
readNormal(is, file); readNormal(is, file);
} }
@ -126,7 +137,7 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
/** /**
* 读取普通的文件流 * 读取普通的文件流
*/ */
private void readNormal(InputStream is, RandomAccessFile file) private void readNormal(InputStream is, BufferedRandomAccessFile file)
throws IOException, InterruptedException { throws IOException, InterruptedException {
byte[] buffer = new byte[mBufSize]; byte[] buffer = new byte[mBufSize];
int len; int len;
@ -137,6 +148,11 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
if (mSleepTime > 0) { if (mSleepTime > 0) {
Thread.sleep(mSleepTime); Thread.sleep(mSleepTime);
} }
if (isOpenDynamicFile) {
file.setLength(
STATE.CURRENT_LOCATION + LEN_INTERVAL < mEntity.getFileSize() ? STATE.CURRENT_LOCATION
+ LEN_INTERVAL : mEntity.getFileSize());
}
file.write(buffer, 0, len); file.write(buffer, 0, len);
progress(len); progress(len);
} }
@ -155,10 +171,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();
} }

@ -22,6 +22,7 @@ import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
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.IEntity;
import com.arialyy.aria.util.ErrorHelp; import com.arialyy.aria.util.ErrorHelp;
/** /**
@ -93,7 +94,8 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
mListener.onPre(); mListener.onPre();
if (mTaskEntity.getEntity().getFileSize() <= 1 if (mTaskEntity.getEntity().getFileSize() <= 1
|| mTaskEntity.isRefreshInfo() || mTaskEntity.isRefreshInfo()
|| mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP) { || mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP
|| mTaskEntity.getState() == IEntity.STATE_FAIL) {
new Thread(createInfoThread()).start(); new Thread(createInfoThread()).start();
} else { } else {
mDownloader.start(); mDownloader.start();

@ -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;
} }

@ -137,6 +137,8 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
public abstract String getKey(); public abstract String getKey();
public abstract void setKey(String key);
@Override public void update() { @Override public void update() {
if (getEntity() != null) { if (getEntity() != null) {
getEntity().update(); getEntity().update();

@ -48,9 +48,9 @@ class UTEFactory implements INormalTEFactory<UploadEntity, UploadTaskEntity> {
List<UTEWrapper> wrapper = List<UTEWrapper> wrapper =
DbEntity.findRelationData(UTEWrapper.class, "UploadTaskEntity.key=?", DbEntity.findRelationData(UTEWrapper.class, "UploadTaskEntity.key=?",
entity.getFilePath()); entity.getFilePath());
UploadTaskEntity uTaskEntity = null;
if (wrapper != null && !wrapper.isEmpty()) { if (wrapper != null && !wrapper.isEmpty()) {
UploadTaskEntity uTaskEntity = wrapper.get(0).taskEntity; uTaskEntity = wrapper.get(0).taskEntity;
if (uTaskEntity == null) { if (uTaskEntity == null) {
uTaskEntity = new UploadTaskEntity(); uTaskEntity = new UploadTaskEntity();
uTaskEntity.setEntity(entity); uTaskEntity.setEntity(entity);
@ -58,12 +58,12 @@ class UTEFactory implements INormalTEFactory<UploadEntity, UploadTaskEntity> {
uTaskEntity.getEntity().getFilePath())) { uTaskEntity.getEntity().getFilePath())) {
uTaskEntity.setEntity(entity); uTaskEntity.setEntity(entity);
} }
return uTaskEntity;
} else { } else {
UploadTaskEntity uTaskEntity = new UploadTaskEntity(); uTaskEntity = new UploadTaskEntity();
uTaskEntity.setEntity(entity); uTaskEntity.setEntity(entity);
return uTaskEntity;
} }
uTaskEntity.setKey(entity.getFilePath());
return uTaskEntity;
} }
@Override public UploadTaskEntity create(String key) { @Override public UploadTaskEntity create(String key) {

@ -16,14 +16,12 @@
package com.arialyy.aria.core.queue; package com.arialyy.aria.core.queue;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsTask; import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.queue.pool.BaseCachePool; import com.arialyy.aria.core.queue.pool.BaseCachePool;
import com.arialyy.aria.core.queue.pool.BaseExecutePool; import com.arialyy.aria.core.queue.pool.BaseExecutePool;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.NetUtils;
/** /**
* Created by lyy on 2017/2/23. * Created by lyy on 2017/2/23.
@ -195,10 +193,10 @@ abstract class AbsTaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
ALog.e(TAG, "任务重试失败,原因:task 为null"); ALog.e(TAG, "任务重试失败,原因:task 为null");
return; return;
} }
if (!NetUtils.isConnected(AriaManager.APP)) { //if (!NetUtils.isConnected(AriaManager.APP)) {
ALog.e(TAG, "任务【" + task.getTaskName() + "】重试失败,原因:网络未连接"); // ALog.e(TAG, "任务【" + task.getTaskName() + "】重试失败,原因:网络未连接");
return; // return;
} //}
if (!task.isRunning()) { if (!task.isRunning()) {
task.start(); task.start();
} else { } else {

@ -67,7 +67,6 @@ public class DownloadGroupTaskQueue
&& mExecutePool.getTask(entity.getEntity().getKey()) == null) { && mExecutePool.getTask(entity.getEntity().getKey()) == null) {
task = (DownloadGroupTask) TaskFactory.getInstance() task = (DownloadGroupTask) TaskFactory.getInstance()
.createTask(targetName, entity, DownloadGroupSchedulers.getInstance()); .createTask(targetName, entity, DownloadGroupSchedulers.getInstance());
entity.setKey(entity.getEntity().getGroupName());
mCachePool.putTask(task); mCachePool.putTask(task);
} else { } else {
ALog.w(TAG, "任务已存在"); ALog.w(TAG, "任务已存在");

@ -123,7 +123,6 @@ public class DownloadTaskQueue extends AbsTaskQueue<DownloadTask, DownloadTaskEn
&& mExecutePool.getTask(entity.getEntity().getKey()) == null) { && mExecutePool.getTask(entity.getEntity().getKey()) == null) {
task = (DownloadTask) TaskFactory.getInstance() task = (DownloadTask) TaskFactory.getInstance()
.createTask(target, entity, DownloadSchedulers.getInstance()); .createTask(target, entity, DownloadSchedulers.getInstance());
entity.setKey(entity.getEntity().getDownloadPath());
mCachePool.putTask(task); mCachePool.putTask(task);
} else { } else {
ALog.w(TAG, "任务已存在"); ALog.w(TAG, "任务已存在");

@ -69,7 +69,6 @@ public class UploadTaskQueue extends AbsTaskQueue<UploadTask, UploadTaskEntity>
&& mExecutePool.getTask(entity.getEntity().getKey()) == null) { && mExecutePool.getTask(entity.getEntity().getKey()) == null) {
task = (UploadTask) TaskFactory.getInstance() task = (UploadTask) TaskFactory.getInstance()
.createTask(targetName, entity, UploadSchedulers.getInstance()); .createTask(targetName, entity, UploadSchedulers.getInstance());
entity.setKey(entity.getEntity().getFilePath());
mCachePool.putTask(task); mCachePool.putTask(task);
} else { } else {
ALog.w(TAG, "任务已存在"); ALog.w(TAG, "任务已存在");

@ -30,6 +30,7 @@ import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.queue.ITaskQueue; import com.arialyy.aria.core.queue.ITaskQueue;
import com.arialyy.aria.core.upload.UploadTask; import com.arialyy.aria.core.upload.UploadTask;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.NetUtils;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -181,8 +182,10 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
if (what == CANCEL || what == COMPLETE) { if (what == CANCEL || what == COMPLETE) {
TEManager.getInstance().removeTEntity(task.getKey()); TEManager.getInstance().removeTEntity(task.getKey());
} else { } else {
if (what != RUNNING) {
TEManager.getInstance().putTEntity(task.getKey(), task.getTaskEntity()); TEManager.getInstance().putTEntity(task.getKey(), task.getTaskEntity());
} }
}
if (what != FAIL) { if (what != FAIL) {
callback(what, task); callback(what, task);
} }
@ -260,16 +263,21 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
} }
long interval = 2000; long interval = 2000;
int num = 10; int num = 10;
boolean isNotNetRetry = false;
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
if (task instanceof DownloadTask || task instanceof DownloadGroupTask) { if (task instanceof DownloadTask || task instanceof DownloadGroupTask) {
interval = AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getReTryInterval(); interval = manager.getDownloadConfig().getReTryInterval();
num = AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getReTryNum(); num = manager.getDownloadConfig().getReTryNum();
isNotNetRetry = manager.getDownloadConfig().isNotNetRetry();
} else if (task instanceof UploadTask) { } else if (task instanceof UploadTask) {
interval = AriaManager.getInstance(AriaManager.APP).getUploadConfig().getReTryInterval(); interval = manager.getUploadConfig().getReTryInterval();
num = AriaManager.getInstance(AriaManager.APP).getUploadConfig().getReTryNum(); num = manager.getUploadConfig().getReTryNum();
isNotNetRetry = manager.getUploadConfig().isNotNetRetry();
} }
final int reTryNum = num; final int reTryNum = num;
if (task.getTaskEntity().getEntity().getFailNum() > reTryNum) { if ((!NetUtils.isConnected(AriaManager.APP) && !isNotNetRetry)
|| task.getTaskEntity().getEntity().getFailNum() > reTryNum) {
callback(FAIL, task); callback(FAIL, task);
mQueue.removeTaskFormQueue(task.getKey()); mQueue.removeTaskFormQueue(task.getKey());
startNextTask(); startNextTask();
@ -284,6 +292,7 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
@Override public void onFinish() { @Override public void onFinish() {
AbsEntity entity = task.getTaskEntity().getEntity(); AbsEntity entity = task.getTaskEntity().getEntity();
if (entity.getFailNum() <= reTryNum) { if (entity.getFailNum() <= reTryNum) {
ALog.d(TAG, "任务【" + task.getTaskName() + "】开始重试");
TASK task = mQueue.getTask(entity.getKey()); TASK task = mQueue.getTask(entity.getKey());
mQueue.reTryStart(task); mQueue.reTryStart(task);
} else { } else {

@ -105,6 +105,7 @@ abstract class BaseNormalTarget<TARGET extends AbsUploadTarget>
ALog.e(TAG, "上传失败,文件【" + filePath + "】不能是文件夹"); ALog.e(TAG, "上传失败,文件【" + filePath + "】不能是文件夹");
return false; return false;
} }
mTaskEntity.setKey(mEntity.getFilePath());
return true; return true;
} }

@ -17,12 +17,16 @@ package com.arialyy.aria.core.upload;
import android.os.Handler; import android.os.Handler;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.TaskRecord;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsGroupEntity;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTask; import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.IUploadListener; import com.arialyy.aria.core.inf.IUploadListener;
import com.arialyy.aria.core.scheduler.ISchedulers; import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -140,7 +144,15 @@ class BaseUListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<
mEntity.setState(state); mEntity.setState(state);
mEntity.setComplete(state == IEntity.STATE_COMPLETE); mEntity.setComplete(state == IEntity.STATE_COMPLETE);
if (state == IEntity.STATE_CANCEL) { if (state == IEntity.STATE_CANCEL) {
mEntity.deleteData(); if (mEntity instanceof AbsNormalEntity) {
TaskRecord record =
DbEntity.findFirst(TaskRecord.class, "TaskRecord.filePath=?", mTaskEntity.getKey());
if (record != null) {
CommonUtil.delTaskRecord(record, mTaskEntity.isRemoveFile(), (AbsNormalEntity) mEntity);
}
} else if (mEntity instanceof AbsGroupEntity) {
CommonUtil.delGroupTaskRecord(mTaskEntity.isRemoveFile(), ((AbsGroupEntity) mEntity));
}
return; return;
} else if (mEntity.isComplete()) { } else if (mEntity.isComplete()) {
mEntity.setCompleteTime(System.currentTimeMillis()); mEntity.setCompleteTime(System.currentTimeMillis());

@ -18,20 +18,21 @@ package com.arialyy.aria.core.upload.uploader;
import com.arialyy.aria.core.common.AbsFtpInfoThread; import com.arialyy.aria.core.common.AbsFtpInfoThread;
import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.OnFileInfoCallback; import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.common.TaskRecord;
import com.arialyy.aria.core.common.ThreadRecord;
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.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.DbHelper;
import java.io.File; import java.util.ArrayList;
import java.util.Properties;
import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPFile;
/** /**
* Created by Aria.Lao on 2017/9/26. * Created by Aria.Lao on 2017/9/26.
* 单任务远程服务器文件信息 * 单任务上传远程服务器文件信息
*/ */
class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity> { class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity> {
private static final String TAG = "FtpUploadFtpFileInfoThread"; private static final String TAG = "FtpUploadFileInfoThread";
static final int CODE_COMPLETE = 0xab1; static final int CODE_COMPLETE = 0xab1;
private boolean isComplete = false; private boolean isComplete = false;
@ -67,16 +68,27 @@ class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity>
+ "尝试从位置:" + "尝试从位置:"
+ (ftpFile.getSize() - 1) + (ftpFile.getSize() - 1)
+ "开始上传"); + "开始上传");
File configFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
Properties pro = CommonUtil.loadConfig(configFile);
String key = mEntity.getFileName() + "_record_" + 0;
mTaskEntity.setNewTask(false); mTaskEntity.setNewTask(false);
long oldRecord = Long.parseLong(pro.getProperty(key, "0"));
if (oldRecord == 0 || oldRecord != ftpFile.getSize()) { // 修改记录
//修改本地保存的停止地址为服务器上对应文件的大小 TaskRecord record = DbHelper.getTaskRecord(mTaskEntity.getKey());
pro.setProperty(key, (ftpFile.getSize() - 1) + ""); if (record == null) {
CommonUtil.saveConfig(configFile, pro); record = new TaskRecord();
record.fileName = mEntity.getFileName();
record.filePath = mTaskEntity.getKey();
record.threadRecords = new ArrayList<>();
} }
ThreadRecord threadRecord;
if (record.threadRecords == null || record.threadRecords.isEmpty()) {
threadRecord = new ThreadRecord();
threadRecord.key = record.filePath;
} else {
threadRecord = record.threadRecords.get(0);
}
//修改本地保存的停止地址为服务器上对应文件的大小
threadRecord.startLocation = ftpFile.getSize() - 1;
record.save();
threadRecord.save();
} }
} }
} }

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.upload.uploader; package com.arialyy.aria.core.upload.uploader;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsFtpThreadTask; import com.arialyy.aria.core.common.AbsFtpThreadTask;
import com.arialyy.aria.core.common.StateConstance; import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
@ -23,7 +24,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;
@ -41,6 +41,11 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
FtpThreadTask(StateConstance constance, IEventListener listener, FtpThreadTask(StateConstance constance, IEventListener listener,
SubThreadConfig<UploadTaskEntity> info) { SubThreadConfig<UploadTaskEntity> info) {
super(constance, listener, info); super(constance, listener, info);
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
mConnectTimeOut = manager.getUploadConfig().getConnectTimeOut();
mReadTimeOut = manager.getUploadConfig().getIOTimeOut();
mBufSize = manager.getUploadConfig().getBuffSize();
isNotNetRetry = manager.getUploadConfig().isNotNetRetry();
} }
@Override public void run() { @Override public void run() {
@ -82,10 +87,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 +116,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);
} }

@ -15,7 +15,7 @@
*/ */
package com.arialyy.aria.core.upload.uploader; package com.arialyy.aria.core.upload.uploader;
import android.util.Log; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsThreadTask; import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.common.StateConstance; import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
@ -52,6 +52,11 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
HttpThreadTask(StateConstance constance, IUploadListener listener, HttpThreadTask(StateConstance constance, IUploadListener listener,
SubThreadConfig<UploadTaskEntity> uploadInfo) { SubThreadConfig<UploadTaskEntity> uploadInfo) {
super(constance, listener, uploadInfo); super(constance, listener, uploadInfo);
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
mConnectTimeOut = manager.getUploadConfig().getConnectTimeOut();
mReadTimeOut = manager.getUploadConfig().getIOTimeOut();
mBufSize = manager.getUploadConfig().getBuffSize();
isNotNetRetry = manager.getUploadConfig().isNotNetRetry();
} }
@Override public void run() { @Override public void run() {
@ -74,10 +79,11 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
mHttpConn.setRequestProperty("Content-Type", mHttpConn.setRequestProperty("Content-Type",
mTaskEntity.getContentType() + "; boundary=" + BOUNDARY); mTaskEntity.getContentType() + "; boundary=" + BOUNDARY);
mHttpConn.setRequestProperty("User-Agent", mTaskEntity.getUserAgent()); mHttpConn.setRequestProperty("User-Agent", mTaskEntity.getUserAgent());
mHttpConn.setConnectTimeout(5000); mHttpConn.setConnectTimeout(mConnectTimeOut);
mHttpConn.setReadTimeout(mReadTimeOut);
//mHttpConn.setRequestProperty("Range", "bytes=" + 0 + "-" + "100"); //mHttpConn.setRequestProperty("Range", "bytes=" + 0 + "-" + "100");
//内部缓冲区---分段上传防止oom //内部缓冲区---分段上传防止oom
mHttpConn.setChunkedStreamingMode(1024); mHttpConn.setChunkedStreamingMode(mBufSize);
//添加Http请求头部 //添加Http请求头部
Set<String> keys = mTaskEntity.getHeaders().keySet(); Set<String> keys = mTaskEntity.getHeaders().keySet();

@ -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,31 +39,6 @@ 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() {
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();
}
}
@Override protected boolean handleNewTask() { @Override protected boolean handleNewTask() {
return true; return true;
} }

@ -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 = 33;
/** /**
* 是否将数据库保存在Sd卡{@code true} * 是否将数据库保存在Sd卡{@code true}
@ -42,7 +44,7 @@ class DBConfig {
static { static {
if (TextUtils.isEmpty(DB_NAME)) { if (TextUtils.isEmpty(DB_NAME)) {
DB_NAME = "AriaLyyDb"; DB_NAME = "AndroidAria.db";
} }
if (VERSION == -1) { if (VERSION == -1) {
VERSION = 1; VERSION = 1;
@ -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,16 @@ 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 dalvik.system.DexFile;
import java.io.File; import java.io.File;
import java.io.FileFilter; import java.io.FileFilter;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -53,9 +58,8 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
@ -65,10 +69,44 @@ 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";
/**
* 获取某包下所有类
*
* @param packageName 包名
* @return 类的完整名称
*/
public static List<String> getClassName(Context context, String packageName) {
List<String> classNameList = new ArrayList<>();
try {
String pPath = context.getPackageCodePath();
File dir = new File(pPath).getParentFile();
String dPath = dir.getPath();
for (String path : dir.list()) {
String fPath = dPath + "/" + path;
if (!fPath.endsWith(".apk")) {
continue;
}
DexFile df = new DexFile(fPath);//通过DexFile查找当前的APK中可执行文件
Enumeration<String> enumeration = df.entries();//获取df中的元素 这里包含了所有可执行的类名 该类名包含了包名+类名的方式
while (enumeration.hasMoreElements()) {//遍历
String className = enumeration.nextElement();
if (className.contains(packageName)) {//在当前所有可执行的类里面查找包含有该包名的所有类
classNameList.add(className);
}
}
df.close();
}
} catch (IOException e) {
e.printStackTrace();
}
return classNameList;
}
/** /**
* 拦截window.location.replace数据 * 拦截window.location.replace数据
* *
@ -82,7 +120,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 +394,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 +431,23 @@ public class CommonUtil {
} }
/** /**
* 删除上传任务的配置 * 删除任务记录
* *
* @param removeFile {@code true} 不仅删除任务数据库记录还会删除已经删除完成的文件 * @param removeFile {@code true} 不仅删除任务数据库记录还会删除已经完成的文件
* {@code false}如果任务已经完成只删除任务数据库记录 * {@code false}如果任务已经完成只删除任务数据库记录
*/ */
public static void delUploadTaskConfig(boolean removeFile, UploadEntity uEntity) { public static void delTaskRecord(TaskRecord record, boolean removeFile,
if (uEntity == null) { AbsNormalEntity dEntity) {
if (dEntity == null) return;
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; 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) {
if (dEntity == null) return;
File file = new File(dEntity.getDownloadPath());
if (removeFile) { if (removeFile) {
if (file.exists()) { if (file.exists()) {
file.delete(); file.delete();
@ -430,9 +460,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();
@ -473,9 +502,10 @@ public class CommonUtil {
public static void createFileFormInputStream(InputStream is, String path) { public static void createFileFormInputStream(InputStream is, String path) {
try { try {
FileOutputStream fos = new FileOutputStream(path); FileOutputStream fos = new FileOutputStream(path);
byte[] buf = new byte[1376]; byte[] buf = new byte[1024];
while (is.read(buf) > 0) { int len;
fos.write(buf, 0, buf.length); while ((len = is.read(buf)) > 0) {
fos.write(buf, 0, len);
} }
is.close(); is.close();
fos.flush(); fos.flush();
@ -849,60 +879,28 @@ public class CommonUtil {
} }
/** /**
* 重命名下载配置文件 * 更新任务记录
* 如果旧的配置文件名不存在则使用新的配置文件名新创建一个文件否则将旧的配置文件重命名为新的位置文件名
* 除了重命名配置文件名外还会将文件中的记录重命名为新的记录如果没有记录则不做处理
*
* @param oldName 旧的下载文件名
* @param newName 新的下载文件名
*/
public static void renameDownloadConfig(String oldName, String newName) {
renameConfig(true, oldName, newName);
}
/**
* 重命名上传配置文件
* 如果旧的配置文件名不存在则使用新的配置文件名新创建一个文件否则将旧的配置文件重命名为新的位置文件名
* 除了重命名配置文件名外还会将文件中的记录重命名为新的记录如果没有记录则不做处理
* *
* @param oldName 旧的上传文件名 * @param oldPath 旧的文件路径
* @param newName 新的上传文件名 * @param newPath 新的文件路径
*/ */
public static void renameUploadConfig(String oldName, String newName) { public static void modifyTaskRecord(String oldPath, String newPath) {
renameConfig(false, oldName, newName); if (oldPath.equals(newPath)) {
ALog.w(TAG, "修改任务记录失败,新文件路径和旧文件路径一致");
return;
} }
File oldFile = new File(oldPath);
private static void renameConfig(boolean isDownload, String oldName, String newName) {
if (oldName.equals(newName)) return;
File oldFile = new File(getFileConfigPath(isDownload, oldName));
File newFile = new File(getFileConfigPath(isDownload, oldName));
if (!oldFile.exists()) { if (!oldFile.exists()) {
createFile(newFile.getPath()); ALog.w(TAG, "修改任务记录失败,文件【" + oldPath + "】不存在");
} else { return;
Properties pro = CommonUtil.loadConfig(oldFile);
if (!pro.isEmpty()) {
Set<Object> keys = pro.keySet();
Set<String> newKeys = new LinkedHashSet<>();
Set<String> values = new LinkedHashSet<>();
for (Object key : keys) {
String oldKey = String.valueOf(key);
if (oldKey.contains(oldName)) {
values.add(pro.getProperty(oldKey));
newKeys.add(oldKey.replace(oldName, newName));
}
}
pro.clear();
Iterator<String> next = values.iterator();
for (String key : newKeys) {
pro.setProperty(key, next.next());
}
CommonUtil.saveConfig(oldFile, pro);
} }
TaskRecord record = DbHelper.getTaskRecord(oldPath);
oldFile.renameTo(newFile); if (record == null) {
ALog.w(TAG, "修改任务记录失败,文件【" + oldPath + "】对应的任务记录不存在");
return;
} }
record.filePath = newPath;
record.update();
} }
/** /**

@ -0,0 +1,42 @@
/*
* 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.util;
import com.arialyy.aria.core.common.RecordWrapper;
import com.arialyy.aria.core.common.TaskRecord;
import com.arialyy.aria.orm.DbEntity;
import java.util.List;
/**
* 数据库帮助类
*/
public class DbHelper {
/**
* 获取任务记录
*
* @param filePath 文件地址
* @return 没有记录返回null有记录则返回任务记录
*/
public static TaskRecord getTaskRecord(String filePath) {
List<RecordWrapper> records =
DbEntity.findRelationData(RecordWrapper.class, "TaskRecord.filePath=?", filePath);
if (records == null || records.size() == 0) {
return null;
}
return records.get(0).taskRecord;
}
}

@ -27,6 +27,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID;
import javax.annotation.processing.Filer; import javax.annotation.processing.Filer;
import javax.lang.model.element.Modifier; import javax.lang.model.element.Modifier;
@ -49,7 +50,8 @@ final class CountFiler {
void createCountFile() throws IOException { void createCountFile() throws IOException {
Set<String> keys = mPbUtil.getListenerClass().keySet(); Set<String> keys = mPbUtil.getListenerClass().keySet();
if (keys.size() == 0) return; if (keys.size() == 0) return;
TypeSpec.Builder builder = TypeSpec.classBuilder(ProxyConstance.PROXY_COUNTER_NAME) TypeSpec.Builder builder = TypeSpec.classBuilder(
ProxyConstance.PROXY_COUNTER_NAME + UUID.randomUUID().toString().replace("-", ""))
.addModifiers(Modifier.PUBLIC, Modifier.FINAL); .addModifiers(Modifier.PUBLIC, Modifier.FINAL);
FieldSpec mappingField = FieldSpec.builder( FieldSpec mappingField = FieldSpec.builder(

@ -1,4 +1,11 @@
## 开发日志 ## 开发日志
+ v_3.4.1
- 移除记录配置文件,改用数据库记录任务记录
- 上传配置添加io超时时间、缓存大小配置
- 添加没有网络也会重试的开关
- 修复多次删除记录的bug
- 文件长度现在可动态增加,详情见 https://aria.laoyuyu.me/aria_doc/start/config.html
- 修复多module同时引用Aria导致打正式包出错的问题 https://github.com/AriaLyy/Aria/issues/240
+ v_3.4 + v_3.4
- 优化大量代码 - 优化大量代码
- 重构Aria的ORM模型,提高了数据读取的可靠性和读写速度 - 重构Aria的ORM模型,提高了数据读取的可靠性和读写速度

@ -14,6 +14,7 @@ Aria有以下特点:
+ 支持https地址下载 + 支持https地址下载
- 在配置文件中很容易就可以设置CA证书的信息 - 在配置文件中很容易就可以设置CA证书的信息
+ 支持300、301、302重定向下载链接下载 + 支持300、301、302重定向下载链接下载
+ 下载支持文件长度动态增加,文件下载初始化时将不再占用过多的内存空间,见[动态长度配置](https://aria.laoyuyu.me/aria_doc/start/config.html#%E4%B8%8B%E8%BD%BD%E5%8A%A8%E6%80%81%E6%96%87%E4%BB%B6%E8%AF%B4%E6%98%8E)
[怎样使用Aria?](#使用) [怎样使用Aria?](#使用)
@ -29,8 +30,8 @@ Aria有以下特点:
[![Download](https://api.bintray.com/packages/arialyy/maven/AriaApi/images/download.svg)](https://bintray.com/arialyy/maven/AriaApi/_latestVersion) [![Download](https://api.bintray.com/packages/arialyy/maven/AriaApi/images/download.svg)](https://bintray.com/arialyy/maven/AriaApi/_latestVersion)
[![Download](https://api.bintray.com/packages/arialyy/maven/AriaCompiler/images/download.svg)](https://bintray.com/arialyy/maven/AriaCompiler/_latestVersion) [![Download](https://api.bintray.com/packages/arialyy/maven/AriaCompiler/images/download.svg)](https://bintray.com/arialyy/maven/AriaCompiler/_latestVersion)
```java ```java
compile 'com.arialyy.aria:aria-core:3.4' compile 'com.arialyy.aria:aria-core:3.4.1'
annotationProcessor 'com.arialyy.aria:aria-compiler:3.4' annotationProcessor 'com.arialyy.aria:aria-compiler:3.4.1'
``` ```
如果出现android support,请将 `compile 'com.arialyy.aria:aria-core:<last-version>'`替换为 如果出现android support,请将 `compile 'com.arialyy.aria:aria-core:<last-version>'`替换为
``` ```
@ -98,13 +99,13 @@ protected void onCreate(Bundle savedInstanceState) {
### 版本日志 ### 版本日志
+ v_3.4 + v_3.4.1
- 优化大量代码 - 移除记录配置文件,改用数据库记录任务记录
- 重构Aria的ORM模型,提高了数据读取的可靠性和读写速度 - 上传配置添加io超时时间、缓存大小配置
- 现在可在任意类中使用Aria了,[使用方法](http://aria.laoyuyu.me/aria_doc/start/any_java.html) - 添加没有网络也会重试的开关
- 添加`window.location.replace("http://xxxx")`类型的网页重定向支持 - 修复多次删除记录的bug
- 支持gzip、deflate 压缩类型的输入流 - 文件长度现在可动态增加,详情见 https://aria.laoyuyu.me/aria_doc/start/config.html
- 添加`useServerFileName`,可使用服务端响应header的`Content-Disposition`携带的文件名 - 修复多module同时引用Aria导致打正式包出错的问题 https://github.com/AriaLyy/Aria/issues/240
[更多版本记录](https://github.com/AriaLyy/Aria/blob/master/DEV_LOG.md) [更多版本记录](https://github.com/AriaLyy/Aria/blob/master/DEV_LOG.md)

@ -34,11 +34,10 @@ android {
abortOnError false abortOnError false
} }
// sourceSets { // sourceSets {
// main.kotlin.srcDirs += 'src/main/kotlin' // main.kotlin.srcDirs += 'src/main/kotlin'
// main.java.srcDirs += 'src/main/java' // main.java.srcDirs += 'src/main/java'
// } // }
} }
dependencies { dependencies {
@ -52,9 +51,10 @@ dependencies {
compile 'com.arialyy.frame:MVVM2:2.2.0' compile 'com.arialyy.frame:MVVM2:2.2.0'
compile project(':Aria') compile project(':Aria')
compile project(':AriaCompiler') compile project(':AriaCompiler')
// compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" // compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
// compile 'com.arialyy.aria:aria-core:3.3.16' // compile 'com.arialyy.aria:aria-core:3.3.16'
// annotationProcessor 'com.arialyy.aria:aria-compiler:3.3.16' // annotationProcessor 'com.arialyy.aria:aria-compiler:3.3.16'
debugCompile 'com.amitshekhar.android:debug-db:1.0.0'
} }
repositories { repositories {
mavenCentral() mavenCentral()

@ -15,10 +15,10 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme.NoActionBar"> android:theme="@style/AppTheme.NoActionBar">
<!--android:name=".test.TestGroupActivity"--> <!--android:name=".test.TestGroupActivity"-->
<!--android:name=".test.AnyRunActivity"-->
<!--android:name=".test.TestActivity"--> <!--android:name=".test.TestActivity"-->
<!--android:name=".MainActivity"-->
<activity <activity
android:name=".test.AnyRunActivity" android:name=".MainActivity"
android:label="@string/app_name"> android:label="@string/app_name">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>

@ -11,6 +11,15 @@
<!--注意,修改该配置文件中的属性会覆盖代码中所设置的属性--> <!--注意,修改该配置文件中的属性会覆盖代码中所设置的属性-->
<download> <download>
<!--是否开启动态文件,开启动态文件后初始化时将不占用磁盘空间,下载多少byte,占多少空间,效果见chrome的下载。-->
<!--注意:
1、使用该功能,将自动关闭多线程下载;
2、对于已经采用了多线程的任务,依然采用原来的下载方式;
3、原本参数是true,任务没下载完成,就参数改为false,那么没下载完成的任务还是会按照参数修改前的方式下载;只有新任务才会根据参数调用不同的下载方式。-->
<openDynamicFile value="true"/>
<!--断网的时候是否重试,true:断网也重试;false:断网不重试,直接走失败的回调-->
<notNetRetry value="true"/>
<!--设置下载线程,线程下载数改变后,新的下载任务才会生效,如果任务大小小于1m,该设置也不会生效--> <!--设置下载线程,线程下载数改变后,新的下载任务才会生效,如果任务大小小于1m,该设置也不会生效-->
<threadNum value="3"/> <threadNum value="3"/>
@ -48,6 +57,16 @@
</download> </download>
<upload> <upload>
<!--断网的时候是否重试,true:断网也重试;false:断网不重试,直接走失败的回调-->
<notNetRetry value="false"/>
<!--设置IO流读取时间,单位为毫秒,默认20000毫秒,该时间不能少于10000毫秒-->
<iOTimeOut value="10000"/>
<!--设置写文件buff大小,该数值大小不能小于2048,数值变小,速度会变慢-->
<buffSize value="8192"/>
<!--是否需要转换速度单位,转换完成后为:1b/s、1kb/s、1mb/s、1gb/s、1tb/s,如果不需要将返回byte长度--> <!--是否需要转换速度单位,转换完成后为:1b/s、1kb/s、1mb/s、1gb/s、1tb/s,如果不需要将返回byte长度-->
<convertSpeed value="true"/> <convertSpeed value="true"/>
@ -55,7 +74,7 @@
<maxTaskNum value="2"/> <maxTaskNum value="2"/>
<!--设置上传失败,重试次数,默认为10--> <!--设置上传失败,重试次数,默认为10-->
<reTryNum value="2"/> <reTryNum value="3"/>
<!--设置重试间隔,单位为毫秒--> <!--设置重试间隔,单位为毫秒-->
<reTryInterval value="2000"/> <reTryInterval value="2000"/>

@ -3,12 +3,9 @@ package com.arialyy.simple.test;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.simple.R; import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseActivity; import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.databinding.ActivityTestBinding; import com.arialyy.simple.databinding.ActivityTestBinding;
import java.util.List;
/** /**
* Created by laoyuyu on 2018/4/13. * Created by laoyuyu on 2018/4/13.
@ -18,7 +15,10 @@ public class AnyRunActivity extends BaseActivity<ActivityTestBinding> {
AnyRunnModule module; AnyRunnModule module;
String[] urls; String[] urls;
int index = 0; int index = 0;
String URL = "http://static.gaoshouyou.com/d/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk"; //String URL = "http://static.gaoshouyou.com/d/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk";
//String URL = "http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk";
private final String URL = "ftp://192.168.29.140:21/download/AriaPrj.rar";
//String URL = "https://dl.genymotion.com/releases/genymotion-2.12.1/genymotion-2.12.1-vbox.exe";
@Override protected int setLayoutId() { @Override protected int setLayoutId() {
return R.layout.activity_test; return R.layout.activity_test;
@ -40,15 +40,17 @@ public class AnyRunActivity extends BaseActivity<ActivityTestBinding> {
// module.start(urls[index]); // module.start(urls[index]);
// index++; // index++;
//} //}
module.start(URL); //for (int i = 0; i < 10; i++) {
List<AbsEntity> list = Aria.download(this).getTotalTaskList();
ALog.d(TAG, "size ==> " + list.size()); module.startFtp(URL);
//}
//List<AbsEntity> list = Aria.download(this).getTotalTaskList();
//ALog.d(TAG, "size ==> " + list.size());
break; break;
case R.id.stop: case R.id.stop:
//List<AbsEntity> list = Aria.download(this).getTotalTaskList(); //List<AbsEntity> list = Aria.download(this).getTotalTaskList();
// //
////module.stop(); module.stop(URL);
//module.stop(URL);
break; break;
case R.id.cancel: case R.id.cancel:

@ -62,16 +62,58 @@ public class AnyRunnModule {
L.d(TAG, "md5Code ==> " + CommonUtil.getFileMD5(new File(task.getDownloadPath()))); L.d(TAG, "md5Code ==> " + CommonUtil.getFileMD5(new File(task.getDownloadPath())));
} }
void start(String url) { void start(String url) {
mUrl = url; mUrl = url;
Aria.download(this) Aria.download(this)
.load(url) .load(url)
.addHeader("Accept-Encoding", "gzip") //.addHeader("Accept-Encoding", "gzip")
.setRequestMode(RequestEnum.GET) .setRequestMode(RequestEnum.GET)
.setFilePath(Environment.getExternalStorageDirectory().getPath() + "/ggsg1234.apk") .setFilePath(Environment.getExternalStorageDirectory().getPath() + "/ggsg123456.apk")
.resetState() //.resetState()
.start();
//String[] urls = new String[] {
// "http://cdn-s1.touchfound.net/1526449199142_3617.png",
// "http://cdn-s1.touchfound.net/mtVmResources/1526287158571.zip",
// "http://cdn-s1.touchfound.net/1526450206960_2186.png",
// "http://cdn-s1.touchfound.net/1526449199025_1476.png"
//};
//for (int i = 0, len = urls.length; i < len; i++){
//
// Aria.download(this)
// .load(urls[i])
// //.addHeader("Accept-Encoding", "gzip")
// .setRequestMode(RequestEnum.GET)
// .setFilePath(Environment.getExternalStorageDirectory().getPath() + "/ggsg123456.apk" + i)
// //.resetState()
// .start();
//}
}
void startFtp(String url) {
mUrl = url;
Aria.download(this)
.loadFtp(url)
.login("lao", "123456")
//.addHeader("Accept-Encoding", "gzip")
.setFilePath(Environment.getExternalStorageDirectory().getPath() + "/")
//.resetState()
.start(); .start();
//String[] urls = new String[] {
// "http://cdn-s1.touchfound.net/1526449199142_3617.png",
// "http://cdn-s1.touchfound.net/mtVmResources/1526287158571.zip",
// "http://cdn-s1.touchfound.net/1526450206960_2186.png",
// "http://cdn-s1.touchfound.net/1526449199025_1476.png"
//};
//for (int i = 0, len = urls.length; i < len; i++){
//
// Aria.download(this)
// .load(urls[i])
// //.addHeader("Accept-Encoding", "gzip")
// .setRequestMode(RequestEnum.GET)
// .setFilePath(Environment.getExternalStorageDirectory().getPath() + "/ggsg123456.apk" + i)
// //.resetState()
// .start();
//}
} }
void stop(String url) { void stop(String url) {

@ -21,9 +21,9 @@ public class TestActivity extends BaseActivity<ActivityTestBinding> {
String TAG = "TestActivity"; String TAG = "TestActivity";
//String URL = "http://58.210.9.131/tpk/sipgt//TDLYZTGH.tpk"; //chunked 下载 //String URL = "http://58.210.9.131/tpk/sipgt//TDLYZTGH.tpk"; //chunked 下载
//private final String URL = "ftp://192.168.1.3:21/download//AriaPrj.rar"; //private final String URL = "ftp://192.168.1.3:21/download//AriaPrj.rar";
private final String FILE_PATH = "/mnt/sdcard/SDK_Demo-release.apk"; private final String FILE_PATH = "/mnt/sdcard/AriaPrj.rar";
//private final String URL = "ftp://192.168.29.140:21/aa//你好"; //private final String URL = "ftp://192.168.29.140:21/aa//你好";
private final String URL = "http://192.168.29.140:5000/upload/"; private final String URL = "ftp://192.168.29.140:21/upload/";
@Override protected int setLayoutId() { @Override protected int setLayoutId() {
return R.layout.activity_test; return R.layout.activity_test;
@ -76,18 +76,17 @@ public class TestActivity extends BaseActivity<ActivityTestBinding> {
switch (view.getId()) { switch (view.getId()) {
case R.id.start: case R.id.start:
Aria.upload(this) Aria.upload(this)
.load(FILE_PATH) .loadFtp(FILE_PATH)
.login("lao", "123456")
.setUploadUrl(URL) .setUploadUrl(URL)
.setRequestMode(RequestEnum.POST)
.setExtendField("韩寒哈大双") .setExtendField("韩寒哈大双")
.setAttachment("file")
.start(); .start();
break; break;
case R.id.stop: case R.id.stop:
Aria.upload(this).load(FILE_PATH).stop(); Aria.upload(this).loadFtp(FILE_PATH).stop();
break; break;
case R.id.cancel: case R.id.cancel:
Aria.upload(this).load(FILE_PATH).cancel(); Aria.upload(this).loadFtp(FILE_PATH).cancel();
break; break;
} }
} }

@ -192,6 +192,12 @@ class Configuration {
* 通用任务配置 * 通用任务配置
*/ */
abstract static class BaseTaskConfig extends BaseConfig { abstract static class BaseTaskConfig extends BaseConfig {
/**
* 设置写文件buff大小该数值大小不能小于2048数值变小下载速度会变慢
*/
int buffSize = 8192;
/** /**
* 进度刷新间隔默认1秒 * 进度刷新间隔默认1秒
*/ */
@ -231,6 +237,16 @@ class Configuration {
*/ */
String queueMod = "wait"; String queueMod = "wait";
/**
* 断网的时候是否重试{@code true}断网也重试{@code false}断网不重试直接走失败的回调
*/
boolean notNetRetry = false;
/**
* 设置IO流读取时间单位为毫秒默认20000毫秒该时间不能少于10000毫秒
*/
int iOTimeOut = 20 * 1000;
public long getUpdateInterval() { public long getUpdateInterval() {
return updateInterval; return updateInterval;
} }
@ -303,20 +319,43 @@ class Configuration {
saveKey("connectTimeOut", String.valueOf(connectTimeOut)); saveKey("connectTimeOut", String.valueOf(connectTimeOut));
return this; return this;
} }
public boolean isNotNetRetry() {
return notNetRetry;
}
public BaseTaskConfig setNotNetRetry(boolean notNetRetry) {
this.notNetRetry = notNetRetry;
saveKey("notNetRetry", String.valueOf(notNetRetry));
return this;
}
public int getIOTimeOut() {
return iOTimeOut;
}
public BaseTaskConfig setIOTimeOut(int iOTimeOut) {
this.iOTimeOut = iOTimeOut;
saveKey("iOTimeOut", String.valueOf(iOTimeOut));
return this;
}
public int getBuffSize() {
return buffSize;
}
public BaseTaskConfig setBuffSize(int buffSize) {
this.buffSize = buffSize;
saveKey("buffSize", String.valueOf(buffSize));
return this;
}
} }
/** /**
* 下载配置 * 下载配置
*/ */
public static class DownloadConfig extends BaseTaskConfig { public static class DownloadConfig extends BaseTaskConfig {
/**
* 设置IO流读取时间单位为毫秒默认20000毫秒该时间不能少于10000毫秒
*/
int iOTimeOut = 20 * 1000;
/**
* 设置写文件buff大小该数值大小不能小于2048数值变小下载速度会变慢
*/
int buffSize = 8192;
/** /**
* 设置https ca 证书信息path 为assets目录下的CA证书完整路径 * 设置https ca 证书信息path 为assets目录下的CA证书完整路径
*/ */
@ -335,6 +374,26 @@ class Configuration {
*/ */
int maxSpeed = 0; int maxSpeed = 0;
/**
* 是否开启动态文件开启动态文件后初始化时将不占用磁盘空间下载多少byte占多少空间效果见chrome的下载
* 注意
* 1使用该功能将自动关闭多线程下载
* 2对于已经采用了多线程的任务依然采用原来的下载方式
* 3原本参数是true任务没下载完成就参数改为false那么没下载完成的任务还是会按照参数修改前的方式下载只有新任务才会根据参数调用不同的下载方式
* {@code true}使用
*/
boolean openDynamicFile = true;
public DownloadConfig setOpenDynamicFile(boolean openDynamicFile) {
this.openDynamicFile = openDynamicFile;
saveKey("openDynamicFile", String.valueOf(openDynamicFile));
return this;
}
public boolean isOpenDynamicFile() {
return openDynamicFile;
}
public DownloadConfig setMaxTaskNum(int maxTaskNum) { public DownloadConfig setMaxTaskNum(int maxTaskNum) {
oldMaxTaskNum = this.maxTaskNum; oldMaxTaskNum = this.maxTaskNum;
this.maxTaskNum = maxTaskNum; this.maxTaskNum = maxTaskNum;
@ -343,10 +402,6 @@ class Configuration {
return this; return this;
} }
public int getIOTimeOut() {
return iOTimeOut;
}
public int getMaxSpeed() { public int getMaxSpeed() {
return maxSpeed; return maxSpeed;
} }
@ -363,22 +418,6 @@ class Configuration {
saveKey("threadNum", String.valueOf(threadNum)); saveKey("threadNum", String.valueOf(threadNum));
} }
public DownloadConfig setIOTimeOut(int iOTimeOut) {
this.iOTimeOut = iOTimeOut;
saveKey("iOTimeOut", String.valueOf(iOTimeOut));
return this;
}
public int getBuffSize() {
return buffSize;
}
public DownloadConfig setBuffSize(int buffSize) {
this.buffSize = buffSize;
saveKey("buffSize", String.valueOf(buffSize));
return this;
}
public String getCaPath() { public String getCaPath() {
return caPath; return caPath;
} }

@ -68,10 +68,11 @@ public class UploadTask extends AbsNormalTask<UploadTaskEntity> {
} }
@Override public void cancel() { @Override public void cancel() {
if (!mUtil.isRunning()) { if (mUtil.isRunning()) {
mUtil.cancel();
} else {
mListener.onCancel(); mListener.onCancel();
} }
mUtil.cancel();
} }
@Override public String getTaskName() { @Override public String getTaskName() {

@ -39,7 +39,7 @@ task clean(type: Delete) {
ext { ext {
userOrg = 'arialyy' userOrg = 'arialyy'
groupId = 'com.arialyy.aria' groupId = 'com.arialyy.aria'
publishVersion = '3.4' publishVersion = '3.4.1'
// publishVersion = '1.0.3' //FTP插件 // publishVersion = '1.0.3' //FTP插件
repoName='maven' repoName='maven'
desc = 'android 下载框架' desc = 'android 下载框架'

Loading…
Cancel
Save