pull/330/head
laoyuyu 7 years ago
commit 788c1398e0
  1. 1
      .gitignore
  2. 7
      Aria/build.gradle
  3. 94
      Aria/src/main/java/com/arialyy/aria/core/Aria.java
  4. 143
      Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
  5. 148
      Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java
  6. 77
      Aria/src/main/java/com/arialyy/aria/core/ErrorEntity.java
  7. 9
      Aria/src/main/java/com/arialyy/aria/core/FtpUrlEntity.java
  8. 47
      Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java
  9. 2
      Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
  10. 48
      Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
  11. 51
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java
  12. 62
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
  13. 17
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpInfoThread.java
  14. 8
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpThreadTask.java
  15. 6
      Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java
  16. 31
      Aria/src/main/java/com/arialyy/aria/core/common/CompleteInfo.java
  17. 18
      Aria/src/main/java/com/arialyy/aria/core/common/IUtil.java
  18. 19
      Aria/src/main/java/com/arialyy/aria/core/common/OnFileInfoCallback.java
  19. 18
      Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java
  20. 66
      Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java
  21. 139
      Aria/src/main/java/com/arialyy/aria/core/delegate/HttpHeaderDelegate.java
  22. 97
      Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java
  23. 4
      Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java
  24. 184
      Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java
  25. 183
      Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java
  26. 35
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java
  27. 25
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java
  28. 2
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java
  29. 206
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
  30. 9
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java
  31. 38
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java
  32. 104
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
  33. 116
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java
  34. 11
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java
  35. 82
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java
  36. 98
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
  37. 103
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
  38. 190
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java
  39. 34
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
  40. 43
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
  41. 20
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java
  42. 33
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java
  43. 36
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java
  44. 7
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java
  45. 4
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java
  46. 128
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
  47. 111
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
  48. 15
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java
  49. 44
      Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGEWrapper.java
  50. 44
      Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGSTEWrapper.java
  51. 65
      Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGTEWrapper.java
  52. 46
      Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DTEWrapper.java
  53. 151
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsDownloadTarget.java
  54. 8
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java
  55. 17
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java
  56. 8
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java
  57. 216
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
  58. 170
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java
  59. 65
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java
  60. 6
      Aria/src/main/java/com/arialyy/aria/core/inf/IEntity.java
  61. 43
      Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java
  62. 52
      Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java
  63. 44
      Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java
  64. 2
      Aria/src/main/java/com/arialyy/aria/core/inf/IUploadListener.java
  65. 169
      Aria/src/main/java/com/arialyy/aria/core/manager/DGTEFactory.java
  66. 98
      Aria/src/main/java/com/arialyy/aria/core/manager/DGTEntityFactory.java
  67. 45
      Aria/src/main/java/com/arialyy/aria/core/manager/DTEFactory.java
  68. 46
      Aria/src/main/java/com/arialyy/aria/core/manager/IGTEFactory.java
  69. 6
      Aria/src/main/java/com/arialyy/aria/core/manager/INormalTEFactory.java
  70. 118
      Aria/src/main/java/com/arialyy/aria/core/manager/TEManager.java
  71. 86
      Aria/src/main/java/com/arialyy/aria/core/manager/TaskManager.java
  72. 48
      Aria/src/main/java/com/arialyy/aria/core/manager/UTEFactory.java
  73. 7
      Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java
  74. 2
      Aria/src/main/java/com/arialyy/aria/core/queue/DownloadGroupTaskQueue.java
  75. 2
      Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java
  76. 2
      Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java
  77. 32
      Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java
  78. 14
      Aria/src/main/java/com/arialyy/aria/core/upload/AbsUploadTarget.java
  79. 133
      Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java
  80. 4
      Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java
  81. 116
      Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java
  82. 8
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadEntity.java
  83. 29
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java
  84. 46
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java
  85. 15
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpFileInfoThread.java
  86. 6
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java
  87. 22
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java
  88. 7
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/SimpleUploadUtil.java
  89. 10
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/Uploader.java
  90. 47
      Aria/src/main/java/com/arialyy/aria/core/upload/wrapper/UTEWrapper.java
  91. 163
      Aria/src/main/java/com/arialyy/aria/orm/AbsDelegate.java
  92. 27
      Aria/src/main/java/com/arialyy/aria/orm/AbsWrapper.java
  93. 62
      Aria/src/main/java/com/arialyy/aria/orm/ActionPolicy.java
  94. 18
      Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java
  95. 93
      Aria/src/main/java/com/arialyy/aria/orm/DatabaseContext.java
  96. 111
      Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java
  97. 249
      Aria/src/main/java/com/arialyy/aria/orm/DbUtil.java
  98. 221
      Aria/src/main/java/com/arialyy/aria/orm/DelegateCommon.java
  99. 512
      Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java
  100. 69
      Aria/src/main/java/com/arialyy/aria/orm/DelegateManager.java
  101. Some files were not shown because too many files have changed in this diff Show More

1
.gitignore vendored

@ -14,3 +14,4 @@
.idea .idea
/cache /cache
*.log *.log
uml

@ -16,6 +16,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
lintOptions {
abortOnError false
}
} }
dependencies { dependencies {
@ -23,8 +26,8 @@ dependencies {
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:appcompat-v7:23.1.1'
compile project(':AriaAnnotations') compile project(':AriaAnnotations')
// compile 'com.arialyy.aria:aria-ftp-plug:1.0.3' compile 'com.arialyy.aria:aria-ftp-plug:1.0.3'
compile project(':AriaFtpPlug') // compile project(':AriaFtpPlug')
} }
apply from: 'bintray-release.gradle' apply from: 'bintray-release.gradle'

@ -17,15 +17,8 @@
package com.arialyy.aria.core; package com.arialyy.aria.core;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Application;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.Fragment;
import android.app.Service;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
import android.widget.PopupWindow;
import com.arialyy.aria.core.download.DownloadReceiver; import com.arialyy.aria.core.download.DownloadReceiver;
import com.arialyy.aria.core.upload.UploadReceiver; import com.arialyy.aria.core.upload.UploadReceiver;
@ -51,6 +44,24 @@ import com.arialyy.aria.core.upload.UploadReceiver;
* .start(); * .start();
* </code> * </code>
* </pre> * </pre>
*
* 如果你需要在ActivityServiceApplicationDialogFragmentFragmentPopupWindowDialog
* 之外的java中使用Aria那么你应该在Application或Activity初始化的时候调用{@link #init(Context)}对Aria进行初始化
* 然后才能使用{@link #download(Object)}{@link #upload(Object)}
*
* <pre>
* <code>
* Aria.init(getContext());
*
* Aria.download(this)
* .load(URL) //下载地址,必填
* //文件保存路径,必填
* .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk")
* .start();
*
* </code>
*
* </pre>
*/ */
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) public class Aria { @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) public class Aria {
@ -60,52 +71,53 @@ import com.arialyy.aria.core.upload.UploadReceiver;
/** /**
* 初始化下载 * 初始化下载
* *
* @param obj 支持类型有ActivityServiceApplicationDialogFragmentFragmentPopupWindowDialog * @param context 支持类型有ActivityServiceApplicationDialogFragmentFragmentPopupWindowDialog
*/ */
public static DownloadReceiver download(Object obj) { public static DownloadReceiver download(Context context) {
return get(obj).download(obj); return get(context).download(context);
} }
/** /**
* 初始化上传 * 初始化上传
* *
* @param obj 支持类型有ActivityServiceApplicationDialogFragmentFragmentPopupWindowDialog * @param context 支持类型有ActivityServiceApplicationDialogFragmentFragmentPopupWindowDialog
*/
public static UploadReceiver upload(Context context) {
return get(context).upload(context);
}
/**
* 在任意对象中初始化下载前提是你需要在Application或Activity初始化的时候调用{@link #init(Context)}对Aria进行初始化
*
* @param obj 任意对象
*/
public static DownloadReceiver download(Object obj) {
return AriaManager.getInstance().download(obj);
}
/**
* 在任意对象中初始化上传前提是你需要在Application或Activity初始化的时候调用{@link #init(Context)}对Aria进行初始化
*
* @param obj 任意对象
*/ */
public static UploadReceiver upload(Object obj) { public static UploadReceiver upload(Object obj) {
return get(obj).upload(obj); return AriaManager.getInstance().upload(obj);
} }
/** /**
* 处理通用事件 * 处理通用事件
*
* @param obj 支持类型有ActivityServiceApplicationDialogFragmentFragmentPopupWindowDialog
*/ */
public static AriaManager get(Object obj) { public static AriaManager get(Context context) {
if (obj instanceof Activity || obj instanceof Service || obj instanceof Application) { return AriaManager.getInstance(context);
return AriaManager.getInstance((Context) obj); }
} else if (obj instanceof DialogFragment) {
DialogFragment dialog = (DialogFragment) obj; /**
return AriaManager.getInstance( * 初始化Aria如果你需要在ActivityServiceApplicationDialogFragmentFragmentPopupWindowDialog
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? dialog.getContext() * 之外的java中使用Aria那么你应该在Application或Activity初始化的时候调用本方法对Aria进行初始化
: dialog.getActivity()); * 只需要初始化一次就可以
} else if (obj instanceof android.support.v4.app.Fragment) { * {@link #download(Object)}{@link #upload(Object)}
android.support.v4.app.Fragment fragment = (android.support.v4.app.Fragment) obj; */
return AriaManager.getInstance( public static AriaManager init(Context context) {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? fragment.getContext() return AriaManager.getInstance(context);
: fragment.getActivity());
} else if (obj instanceof Fragment) {
Fragment fragment = (Fragment) obj;
return AriaManager.getInstance(
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? fragment.getContext()
: fragment.getActivity());
} else if (obj instanceof PopupWindow) {
PopupWindow popupWindow = (PopupWindow) obj;
return AriaManager.getInstance(popupWindow.getContentView().getContext());
} else if (obj instanceof Dialog) {
Dialog dialog = (Dialog) obj;
return AriaManager.getInstance(dialog.getContext());
} else {
throw new IllegalArgumentException("不支持的类型");
}
} }
} }

@ -20,13 +20,11 @@ import android.annotation.TargetApi;
import android.app.Activity; import android.app.Activity;
import android.app.Application; import android.app.Application;
import android.app.Dialog; import android.app.Dialog;
import android.app.Service;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.widget.PopupWindow; import android.widget.PopupWindow;
import com.arialyy.aria.core.command.ICmd; import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.common.QueueMod; import com.arialyy.aria.core.common.QueueMod;
@ -41,8 +39,9 @@ import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadReceiver; import com.arialyy.aria.core.upload.UploadReceiver;
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.orm.DbUtil; import com.arialyy.aria.orm.DelegateWrapper;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.AriaCrashHandler;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -75,12 +74,14 @@ import org.xml.sax.SAXException;
private List<ICmd> mCommands = new ArrayList<>(); private List<ICmd> mCommands = new ArrayList<>();
private Configuration.DownloadConfig mDConfig; private Configuration.DownloadConfig mDConfig;
private Configuration.UploadConfig mUConfig; private Configuration.UploadConfig mUConfig;
private Configuration.AppConfig mAConfig;
private AriaManager(Context context) { private AriaManager(Context context) {
DbUtil.init(context.getApplicationContext()); DelegateWrapper.init(context.getApplicationContext());
APP = context.getApplicationContext(); APP = context.getApplicationContext();
regAppLifeCallback(context); regAppLifeCallback(context);
initConfig(); initConfig();
initAria();
} }
public static AriaManager getInstance(Context context) { public static AriaManager getInstance(Context context) {
@ -92,34 +93,53 @@ import org.xml.sax.SAXException;
return INSTANCE; return INSTANCE;
} }
public Map<String, AbsReceiver> getReceiver() { static AriaManager getInstance() {
return mReceivers; if (INSTANCE == null) {
throw new NullPointerException("请在Application或Activity初始化时调用一次Aria.init(context)方法进行初始化操作");
}
return INSTANCE;
} }
/** private void initAria() {
* 设置Aria 日志级别 if (mAConfig.getUseAriaCrashHandler()) {
* Thread.setDefaultUncaughtExceptionHandler(new AriaCrashHandler());
* @param level {@link ALog#LOG_LEVEL_VERBOSE} }
*/ mAConfig.setLogLevel(mAConfig.getLogLevel());
public void setLogLevel(int level) { }
ALog.LOG_LEVEL = level;
public Map<String, AbsReceiver> getReceiver() {
return mReceivers;
} }
/** /**
* 设置上传任务的执行队列类型 * 设置上传任务的执行队列类型后续版本会删除该api请使用
* <pre>
* <code>
* Aria.get(this).getUploadConfig().setQueueMod(mod.tag)
* </code>
* </pre>
* *
* @param mod {@link QueueMod} * @param mod {@link QueueMod}
* @deprecated 后续版本会删除该api
*/ */
@Deprecated
public AriaManager setUploadQueueMod(QueueMod mod) { public AriaManager setUploadQueueMod(QueueMod mod) {
mUConfig.setQueueMod(mod.tag); mUConfig.setQueueMod(mod.tag);
return this; return this;
} }
/** /**
* 设置下载任务的执行队列类型 * 设置下载任务的执行队列类型后续版本会删除该api请使用
* <pre>
* <code>
* Aria.get(this).getDownloadConfig().setQueueMod(mod.tag)
* </code>
* </pre>
* *
* @param mod {@link QueueMod} * @param mod {@link QueueMod}
* @deprecated 后续版本会删除该api
*/ */
@Deprecated
public AriaManager setDownloadQueueMod(QueueMod mod) { public AriaManager setDownloadQueueMod(QueueMod mod) {
mDConfig.setQueueMod(mod.tag); mDConfig.setQueueMod(mod.tag);
return this; return this;
@ -151,6 +171,13 @@ import org.xml.sax.SAXException;
return mUConfig; return mUConfig;
} }
/**
* 获取APP配置
*/
public Configuration.AppConfig getAppConfig() {
return mAConfig;
}
/** /**
* 设置命令 * 设置命令
*/ */
@ -201,22 +228,6 @@ import org.xml.sax.SAXException;
return (receiver instanceof UploadReceiver) ? (UploadReceiver) receiver : null; return (receiver instanceof UploadReceiver) ? (UploadReceiver) receiver : null;
} }
/**
* 获取Aria下载错误日志
*
* @return 如果错误日志不存在则返回空否则返回错误日志列表
*/
public List<ErrorEntity> getErrorLog() {
return DbEntity.findAllData(ErrorEntity.class);
}
/**
* 清楚错误日志
*/
public void cleanLog() {
DbEntity.clean(ErrorEntity.class);
}
/** /**
* 删除任务记录 * 删除任务记录
* *
@ -244,6 +255,7 @@ import org.xml.sax.SAXException;
final String key = getKey(isDownload, obj); final String key = getKey(isDownload, obj);
IReceiver receiver = mReceivers.get(key); IReceiver receiver = mReceivers.get(key);
boolean needRmReceiver = false; boolean needRmReceiver = false;
// 监控Dialog、fragment、popupWindow的生命周期
final WidgetLiftManager widgetLiftManager = new WidgetLiftManager(); final WidgetLiftManager widgetLiftManager = new WidgetLiftManager();
if (obj instanceof Dialog) { if (obj instanceof Dialog) {
needRmReceiver = widgetLiftManager.handleDialogLift((Dialog) obj); needRmReceiver = widgetLiftManager.handleDialogLift((Dialog) obj);
@ -270,7 +282,8 @@ import org.xml.sax.SAXException;
/** /**
* 不允许在"onDestroy""finish""onStop"这三个方法中添加注册器 * 不允许在"onDestroy""finish""onStop"这三个方法中添加注册器
*/ */
private AbsReceiver checkTarget(String key, AbsReceiver receiver, Object obj, boolean needRmReceiver) { private AbsReceiver checkTarget(String key, AbsReceiver receiver, Object obj,
boolean needRmReceiver) {
StackTraceElement[] stack = Thread.currentThread().getStackTrace(); StackTraceElement[] stack = Thread.currentThread().getStackTrace();
int i = 0; int i = 0;
for (StackTraceElement e : stack) { for (StackTraceElement e : stack) {
@ -288,8 +301,8 @@ import org.xml.sax.SAXException;
"onStop"); "onStop");
if (isDestroyed) { if (isDestroyed) {
ALog.w(TAG, ALog.e(TAG,
"请不要在Activity或Fragment的onDestroy、finish、onStop等方法中调用Aria,Aria的unRegister会在Activity页面销毁时自动执行"); "请不要在Activity或Fragment的onDestroy、finish、onStop等方法中注册Aria,Aria的unRegister会在Activity页面销毁时自动执行");
} }
if (obj instanceof Activity && isDestroyed) { if (obj instanceof Activity && isDestroyed) {
@ -309,45 +322,33 @@ import org.xml.sax.SAXException;
*/ */
private String getKey(boolean isDownload, Object obj) { private String getKey(boolean isDownload, Object obj) {
String clsName = obj.getClass().getName(); String clsName = obj.getClass().getName();
String key = ""; String key;
if (!(obj instanceof Activity)) { if (obj instanceof DialogFragment) {
if (obj instanceof DialogFragment) { key = clsName + "_" + ((DialogFragment) obj).getActivity().getClass().getName();
key = clsName + "_" + ((DialogFragment) obj).getActivity().getClass().getName(); } else if (obj instanceof android.app.DialogFragment) {
} else if (obj instanceof android.app.DialogFragment) { key = clsName + "_" + ((android.app.DialogFragment) obj).getActivity().getClass().getName();
key = clsName + "_" + ((android.app.DialogFragment) obj).getActivity().getClass().getName(); } else if (obj instanceof android.support.v4.app.Fragment) {
} else if (obj instanceof android.support.v4.app.Fragment) { key = clsName + "_" + ((Fragment) obj).getActivity().getClass().getName();
key = clsName + "_" + ((Fragment) obj).getActivity().getClass().getName(); } else if (obj instanceof android.app.Fragment) {
} else if (obj instanceof android.app.Fragment) { key = clsName + "_" + ((android.app.Fragment) obj).getActivity().getClass().getName();
key = clsName + "_" + ((android.app.Fragment) obj).getActivity().getClass().getName(); } else if (obj instanceof Dialog) {
} else if (obj instanceof Dialog) { Activity activity = ((Dialog) obj).getOwnerActivity();
Activity activity = ((Dialog) obj).getOwnerActivity(); if (activity != null) {
if (activity != null) { key = clsName + "_" + activity.getClass().getName();
key = clsName + "_" + activity.getClass().getName(); } else {
} else {
key = clsName;
}
} else if (obj instanceof PopupWindow) {
Context context = ((PopupWindow) obj).getContentView().getContext();
if (context instanceof Activity) {
key = clsName + "_" + context.getClass().getName();
} else {
key = clsName;
}
} else if (obj instanceof Service) {
key = clsName; key = clsName;
} else if (obj instanceof Application) { }
} else if (obj instanceof PopupWindow) {
Context context = ((PopupWindow) obj).getContentView().getContext();
if (context instanceof Activity) {
key = clsName + "_" + context.getClass().getName();
} else {
key = clsName; key = clsName;
} }
} } else {
if (obj instanceof Activity || obj instanceof Service) {
key = clsName;
} else if (obj instanceof Application) {
key = clsName; key = clsName;
} }
if (TextUtils.isEmpty(key)) { key += (isDownload ? DOWNLOAD : UPLOAD) + obj.hashCode();
throw new IllegalArgumentException("未知类型");
}
key += isDownload ? DOWNLOAD : UPLOAD;
return key; return key;
} }
@ -377,6 +378,7 @@ import org.xml.sax.SAXException;
} }
mDConfig = Configuration.DownloadConfig.getInstance(); mDConfig = Configuration.DownloadConfig.getInstance();
mUConfig = Configuration.UploadConfig.getInstance(); mUConfig = Configuration.UploadConfig.getInstance();
mAConfig = Configuration.AppConfig.getInstance();
if (tempDir.exists()) { if (tempDir.exists()) {
File newDir = new File(APP.getFilesDir().getPath() + DOWNLOAD_TEMP_DIR); File newDir = new File(APP.getFilesDir().getPath() + DOWNLOAD_TEMP_DIR);
newDir.mkdirs(); newDir.mkdirs();
@ -406,8 +408,8 @@ import org.xml.sax.SAXException;
private void regAppLifeCallback(Context context) { private void regAppLifeCallback(Context context) {
Context app = context.getApplicationContext(); Context app = context.getApplicationContext();
if (app instanceof Application) { if (app instanceof Application) {
LifeCallback mLifeCallback = new LifeCallback(); LifeCallback lifeCallback = new LifeCallback();
((Application) app).registerActivityLifecycleCallbacks(mLifeCallback); ((Application) app).registerActivityLifecycleCallbacks(lifeCallback);
} }
} }
@ -478,6 +480,7 @@ import org.xml.sax.SAXException;
@Override public void onActivityDestroyed(Activity activity) { @Override public void onActivityDestroyed(Activity activity) {
destroySchedulerListener(activity); destroySchedulerListener(activity);
// TODO: 2018/4/11 维护一个activity堆栈,应用被kill,activity会回调onDestroy方法,需要考虑server后台情况
} }
} }
} }

@ -28,9 +28,10 @@ import org.xml.sax.helpers.DefaultHandler;
class ConfigHelper extends DefaultHandler { class ConfigHelper extends DefaultHandler {
private final String TAG = "ConfigHelper"; private final String TAG = "ConfigHelper";
private boolean isDownloadConfig = false, isUploadConfig; private boolean isDownloadConfig = false, isUploadConfig = false, isAppConfig = false;
private Configuration.DownloadConfig mDownloadConfig = Configuration.DownloadConfig.getInstance(); private Configuration.DownloadConfig mDownloadConfig = Configuration.DownloadConfig.getInstance();
private Configuration.UploadConfig mUploadConfig = Configuration.UploadConfig.getInstance(); private Configuration.UploadConfig mUploadConfig = Configuration.UploadConfig.getInstance();
private Configuration.AppConfig mAppConfig = Configuration.AppConfig.getInstance();
@Override public void startDocument() throws SAXException { @Override public void startDocument() throws SAXException {
super.startDocument(); super.startDocument();
@ -43,10 +44,17 @@ class ConfigHelper extends DefaultHandler {
if (qName.equals("download")) { if (qName.equals("download")) {
isDownloadConfig = true; isDownloadConfig = true;
isUploadConfig = false; isUploadConfig = false;
isAppConfig = false;
} else if (qName.equals("upload")) { } else if (qName.equals("upload")) {
isUploadConfig = true; isUploadConfig = true;
isDownloadConfig = false; isDownloadConfig = false;
isAppConfig = false;
} else if (qName.equals("app")) {
isUploadConfig = false;
isDownloadConfig = false;
isAppConfig = true;
} }
if (isDownloadConfig || isUploadConfig) { if (isDownloadConfig || isUploadConfig) {
String value = attributes.getValue("value"); String value = attributes.getValue("value");
@ -90,17 +98,46 @@ class ConfigHelper extends DefaultHandler {
loadUpdateInterval(value); loadUpdateInterval(value);
break; break;
} }
} else if (isAppConfig) {
String value = attributes.getValue("value");
switch (qName) {
case "useAriaCrashHandler":
loadUseAriaCrashHandler(value);
break;
case "logLevel":
loadLogLevel(value);
break;
}
} }
} }
private void loadUpdateInterval(String value) { private void loadLogLevel(String value) {
long temp = 1000; int level;
if (!TextUtils.isEmpty(value)) { try {
temp = Long.parseLong(value); level = Integer.parseInt(value);
if (temp <= 0) { } catch (NumberFormatException e) {
temp = 1000; e.printStackTrace();
} level = ALog.LOG_LEVEL_VERBOSE;
}
if (level < ALog.LOG_LEVEL_VERBOSE || level > ALog.LOG_CLOSE) {
ALog.w(TAG, "level【" + level + "】错误");
mAppConfig.logLevel = ALog.LOG_LEVEL_VERBOSE;
} else {
mAppConfig.logLevel = level;
}
}
private void loadUseAriaCrashHandler(String value) {
if (checkBoolean(value)) {
mAppConfig.useAriaCrashHandler = Boolean.parseBoolean(value);
} else {
ALog.w(TAG, "useAriaCrashHandler【" + value + "】错误");
mAppConfig.useAriaCrashHandler = true;
} }
}
private void loadUpdateInterval(String value) {
long temp = checkLong(value) ? Long.parseLong(value) : 1000;
if (isDownloadConfig) { if (isDownloadConfig) {
mDownloadConfig.updateInterval = temp; mDownloadConfig.updateInterval = temp;
} }
@ -124,17 +161,18 @@ class ConfigHelper extends DefaultHandler {
} }
private void loadMaxSpeed(String value) { private void loadMaxSpeed(String value) {
double maxSpeed = 0.0; int maxSpeed = checkInt(value) ? Integer.parseInt(value) : 0;
if (!TextUtils.isEmpty(value)) {
maxSpeed = Double.parseDouble(value);
}
if (isDownloadConfig) { if (isDownloadConfig) {
mDownloadConfig.msxSpeed = maxSpeed; mDownloadConfig.maxSpeed = maxSpeed;
} }
} }
private void loadConvertSpeed(String value) { private void loadConvertSpeed(String value) {
boolean open = Boolean.parseBoolean(value); boolean open = true;
if (checkBoolean(value)) {
open = Boolean.parseBoolean(value);
}
if (isDownloadConfig) { if (isDownloadConfig) {
mDownloadConfig.isConvertSpeed = open; mDownloadConfig.isConvertSpeed = open;
} }
@ -144,10 +182,7 @@ class ConfigHelper extends DefaultHandler {
} }
private void loadReTryInterval(String value) { private void loadReTryInterval(String value) {
int time = 2 * 1000; int time = checkInt(value) ? Integer.parseInt(value) : 2 * 1000;
if (!TextUtils.isEmpty(value)) {
time = Integer.parseInt(value);
}
if (time < 2 * 1000) { if (time < 2 * 1000) {
time = 2 * 1000; time = 2 * 1000;
@ -166,10 +201,7 @@ class ConfigHelper extends DefaultHandler {
} }
private void loadBuffSize(String value) { private void loadBuffSize(String value) {
int buffSize = 8192; int buffSize = checkInt(value) ? Integer.parseInt(value) : 8192;
if (!TextUtils.isEmpty(value)) {
buffSize = Integer.parseInt(value);
}
if (buffSize < 2048) { if (buffSize < 2048) {
buffSize = 2048; buffSize = 2048;
@ -181,10 +213,7 @@ class ConfigHelper extends DefaultHandler {
} }
private void loadIOTimeout(String value) { private void loadIOTimeout(String value) {
int time = 10 * 1000; int time = checkInt(value) ? Integer.parseInt(value) : 10 * 1000;
if (!TextUtils.isEmpty(value)) {
time = Integer.parseInt(value);
}
if (time < 10 * 1000) { if (time < 10 * 1000) {
time = 10 * 1000; time = 10 * 1000;
@ -196,10 +225,7 @@ class ConfigHelper extends DefaultHandler {
} }
private void loadConnectTime(String value) { private void loadConnectTime(String value) {
int time = 5 * 1000; int time = checkInt(value) ? Integer.parseInt(value) : 5 * 1000;
if (!TextUtils.isEmpty(value)) {
time = Integer.parseInt(value);
}
if (isDownloadConfig) { if (isDownloadConfig) {
mDownloadConfig.connectTimeOut = time; mDownloadConfig.connectTimeOut = time;
@ -210,10 +236,7 @@ class ConfigHelper extends DefaultHandler {
} }
private void loadReTry(String value) { private void loadReTry(String value) {
int num = 0; int num = checkInt(value) ? Integer.parseInt(value) : 0;
if (!TextUtils.isEmpty(value)) {
num = Integer.parseInt(value);
}
if (isDownloadConfig) { if (isDownloadConfig) {
mDownloadConfig.reTryNum = num; mDownloadConfig.reTryNum = num;
@ -224,10 +247,7 @@ class ConfigHelper extends DefaultHandler {
} }
private void loadMaxQueue(String value) { private void loadMaxQueue(String value) {
int num = 2; int num = checkInt(value) ? Integer.parseInt(value) : 2;
if (!TextUtils.isEmpty(value)) {
num = Integer.parseInt(value);
}
if (num < 1) { if (num < 1) {
ALog.w(TAG, "任务队列数不能小于 1"); ALog.w(TAG, "任务队列数不能小于 1");
num = 2; num = 2;
@ -241,10 +261,7 @@ class ConfigHelper extends DefaultHandler {
} }
private void loadThreadNum(String value) { private void loadThreadNum(String value) {
int num = 3; int num = checkInt(value) ? Integer.parseInt(value) : 3;
if (!TextUtils.isEmpty(value)) {
num = Integer.parseInt(value);
}
if (num < 1) { if (num < 1) {
ALog.e(TAG, "下载线程数不能小于 1"); ALog.e(TAG, "下载线程数不能小于 1");
num = 1; num = 1;
@ -254,6 +271,52 @@ class ConfigHelper extends DefaultHandler {
} }
} }
/**
* 检查是否int值是否合法
*
* @return {@code true} 合法
*/
private boolean checkInt(String value) {
if (TextUtils.isEmpty(value)) {
return false;
}
try {
Integer l = Integer.parseInt(value);
return true;
} catch (NumberFormatException e) {
e.printStackTrace();
return false;
}
}
/**
* 检查是否long值是否合法
*
* @return {@code true} 合法
*/
private boolean checkLong(String value) {
if (TextUtils.isEmpty(value)) {
return false;
}
try {
Long l = Long.parseLong(value);
return true;
} catch (NumberFormatException e) {
e.printStackTrace();
return false;
}
}
/**
* 检查boolean值是否合法
*
* @return {@code true} 合法
*/
private boolean checkBoolean(String value) {
return !TextUtils.isEmpty(value) && (value.equalsIgnoreCase("true") || value.equalsIgnoreCase(
"false"));
}
@Override public void characters(char[] ch, int start, int length) throws SAXException { @Override public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length); super.characters(ch, start, length);
} }
@ -266,5 +329,6 @@ class ConfigHelper extends DefaultHandler {
super.endDocument(); super.endDocument();
mDownloadConfig.saveAll(); mDownloadConfig.saveAll();
mUploadConfig.saveAll(); mUploadConfig.saveAll();
mAppConfig.saveAll();
} }
} }

@ -1,77 +0,0 @@
/*
* 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;
import com.arialyy.aria.orm.DbEntity;
/**
* Created by Aria.Lao on 2017/8/29.
* 错误实体
*/
public class ErrorEntity extends DbEntity {
/**
* 插入时间
*/
public long insertTime;
/**
* 错误信息
*/
public String err;
/**
* 任务名
*/
public String taskName;
/**
*任务类型
*/
public String taskType;
/**
* 提示
*/
public String msg;
/**
* 任务key
*/
public String key;
@Override public String toString() {
return "ErrorEntity{"
+ "insertTime="
+ insertTime
+ ", err='"
+ err
+ '\''
+ ", taskName='"
+ taskName
+ '\''
+ ", taskType='"
+ taskType
+ '\''
+ ", msg='"
+ msg
+ '\''
+ ", key='"
+ key
+ '\''
+ '}';
}
}

@ -24,7 +24,10 @@ import java.net.InetAddress;
* ftp url 信息链接实体 * ftp url 信息链接实体
*/ */
public class FtpUrlEntity implements Cloneable { public class FtpUrlEntity implements Cloneable {
/**
* ftp://127.0.0.1:21/download/AriaPrj.zip
* remotePath便是download/AriaPrj.zip
*/
public String remotePath; public String remotePath;
public String account; public String account;
@ -35,12 +38,12 @@ public class FtpUrlEntity implements Cloneable {
public String url; public String url;
/** /**
* ftp协议 * ftp协议ftp
*/ */
public String protocol; public String protocol;
/** /**
* 用户 * 登录的用户
*/ */
public String user; public String user;
/** /**

@ -16,13 +16,7 @@
package com.arialyy.aria.core.command.normal; package com.arialyy.aria.core.command.normal;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
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.upload.UploadTaskEntity;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil;
import java.util.List;
/** /**
* Created by AriaL on 2017/6/27. * Created by AriaL on 2017/6/27.
@ -44,46 +38,5 @@ public class CancelAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
@Override public void executeCmd() { @Override public void executeCmd() {
removeAll(); removeAll();
if (mTaskEntity instanceof DownloadTaskEntity
|| mTaskEntity instanceof DownloadGroupTaskEntity) {
handleDownloadRemove();
handleDownloadGroupRemove();
} else if (mTaskEntity instanceof UploadTaskEntity) {
handleUploadRemove();
handleUploadRemove();
}
}
/**
* 处理下载任务组的删除操作
*/
private void handleDownloadGroupRemove() {
List<DownloadGroupTaskEntity> allEntity = DbEntity.findAllData(DownloadGroupTaskEntity.class);
if (allEntity == null || allEntity.size() == 0) return;
for (DownloadGroupTaskEntity entity : allEntity) {
CommonUtil.delDownloadGroupTaskConfig(removeFile, entity);
}
}
/**
* 处理上传的删除
*/
private void handleUploadRemove() {
List<UploadTaskEntity> allEntity = DbEntity.findAllData(UploadTaskEntity.class);
if (allEntity == null || allEntity.size() == 0) return;
for (UploadTaskEntity entity : allEntity) {
CommonUtil.delUploadTaskConfig(removeFile, entity);
}
}
/**
* 处理下载的删除
*/
private void handleDownloadRemove() {
List<DownloadTaskEntity> allEntity = DbEntity.findAllData(DownloadTaskEntity.class);
if (allEntity == null || allEntity.size() == 0) return;
for (DownloadTaskEntity entity : allEntity) {
CommonUtil.delDownloadTaskConfig(removeFile, entity);
}
} }
} }

@ -42,7 +42,7 @@ public class CancelCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
task = createTask(); task = createTask();
} }
if (task != null) { if (task != null) {
mTaskEntity.removeFile = removeFile; mTaskEntity.setRemoveFile(removeFile);
if (!TextUtils.isEmpty(mTargetName)) { if (!TextUtils.isEmpty(mTargetName)) {
task.setTargetName(mTargetName); task.setTargetName(mTargetName);
} }

@ -3,12 +3,15 @@ package com.arialyy.aria.core.command.normal;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.download.wrapper.DGTEWrapper;
import com.arialyy.aria.core.download.wrapper.DTEWrapper;
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.DownloadGroupTaskQueue; import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.core.queue.DownloadTaskQueue; import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.core.queue.UploadTaskQueue; import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.core.upload.UploadTaskEntity; import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.core.upload.wrapper.UTEWrapper;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
@ -53,29 +56,32 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
* @param type {@code 1}单任务下载任务{@code 2}任务组下载任务{@code 3} 单任务上传任务 * @param type {@code 1}单任务下载任务{@code 2}任务组下载任务{@code 3} 单任务上传任务
*/ */
private List<AbsTaskEntity> findTaskData(int type) { private List<AbsTaskEntity> findTaskData(int type) {
// TODO: 2018/4/20 需要测试
List<AbsTaskEntity> tempList = new ArrayList<>(); List<AbsTaskEntity> tempList = new ArrayList<>();
switch (type) { if (type == 1) {
case 1: List<DTEWrapper> wrappers = DbEntity.findRelationData(DTEWrapper.class,
List<DownloadTaskEntity> dTaskEntity = "DownloadTaskEntity.isGroupTask=? and DownloadTaskEntity.state!=?", "false", "1");
DbEntity.findDatas(DownloadTaskEntity.class, "isGroupTask=?", "false"); if (wrappers != null && !wrappers.isEmpty()) {
if (dTaskEntity != null && !dTaskEntity.isEmpty()) { for (DTEWrapper w : wrappers) {
tempList.addAll(dTaskEntity); tempList.add(w.taskEntity);
} }
break; }
case 2: } else if (type == 2) {
List<DownloadGroupTaskEntity> groupTask = List<DGTEWrapper> wrappers =
DbEntity.findAllData(DownloadGroupTaskEntity.class); DbEntity.findRelationData(DGTEWrapper.class, "DownloadGroupTaskEntity.state!=?", "1");
if (groupTask != null && !groupTask.isEmpty()) { if (wrappers != null && !wrappers.isEmpty()) {
tempList.addAll(groupTask); for (DGTEWrapper w : wrappers) {
tempList.add(w.taskEntity);
} }
break; }
case 3: } else if (type == 3) {
List<UploadTaskEntity> uTaskEntity = List<UTEWrapper> wrappers =
DbEntity.findDatas(UploadTaskEntity.class, "isGroupTask=?", "false"); DbEntity.findRelationData(UTEWrapper.class, "UploadTaskEntity.state!=?", "1");
if (uTaskEntity != null && !uTaskEntity.isEmpty()) { if (wrappers != null && !wrappers.isEmpty()) {
tempList.addAll(uTaskEntity); for (UTEWrapper w : wrappers) {
tempList.add(w.taskEntity);
} }
break; }
} }
return tempList; return tempList;
} }
@ -123,8 +129,8 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
*/ */
private void resumeEntity(AbsTaskEntity te) { private void resumeEntity(AbsTaskEntity te) {
if (te instanceof DownloadTaskEntity) { if (te instanceof DownloadTaskEntity) {
if (te.requestType == AbsTaskEntity.D_FTP || te.requestType == AbsTaskEntity.U_FTP) { if (te.getRequestType() == AbsTaskEntity.D_FTP || te.getRequestType() == AbsTaskEntity.U_FTP) {
te.urlEntity = CommonUtil.getFtpUrlInfo(te.getEntity().getKey()); te.setUrlEntity(CommonUtil.getFtpUrlInfo(te.getEntity().getKey()));
} }
mQueue = DownloadTaskQueue.getInstance(); mQueue = DownloadTaskQueue.getInstance();
} else if (te instanceof UploadTaskEntity) { } else if (te instanceof UploadTaskEntity) {

@ -21,6 +21,8 @@ import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.QueueMod; import com.arialyy.aria.core.common.QueueMod;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.download.wrapper.DGTEWrapper;
import com.arialyy.aria.core.download.wrapper.DTEWrapper;
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;
@ -28,6 +30,7 @@ import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.core.queue.DownloadTaskQueue; import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.core.queue.UploadTaskQueue; import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.core.upload.UploadTaskEntity; import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.core.upload.wrapper.UTEWrapper;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
@ -53,6 +56,7 @@ 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) {
@ -77,7 +81,6 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
|| task.getState() == IEntity.STATE_OTHER || task.getState() == IEntity.STATE_OTHER
|| task.getState() == IEntity.STATE_POST_PRE || task.getState() == IEntity.STATE_POST_PRE
|| task.getState() == IEntity.STATE_COMPLETE) { || task.getState() == IEntity.STATE_COMPLETE) {
//startTask();
resumeTask(); resumeTask();
} else { } else {
sendWaitState(); sendWaitState();
@ -85,7 +88,6 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
} }
} else { } else {
if (!task.isRunning()) { if (!task.isRunning()) {
//startTask();
resumeTask(); resumeTask();
} }
} }
@ -113,29 +115,32 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
} }
private List<AbsTaskEntity> findWaitData(int type) { private List<AbsTaskEntity> findWaitData(int type) {
// TODO: 2018/4/20 需要测试
List<AbsTaskEntity> waitList = new ArrayList<>(); List<AbsTaskEntity> waitList = new ArrayList<>();
switch (type) { if (type == 1) {
case 1: List<DTEWrapper> wrappers = DbEntity.findRelationData(DTEWrapper.class,
List<DownloadTaskEntity> dEntity = "DownloadTaskEntity.isGroupTask=? and DownloadTaskEntity.state=?", "false", "3");
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=? and state=?", "", "3"); if (wrappers != null && !wrappers.isEmpty()) {
if (dEntity != null && !dEntity.isEmpty()) { for (DTEWrapper w : wrappers) {
waitList.addAll(dEntity); waitList.add(w.taskEntity);
} }
break; }
case 2: } else if (type == 2) {
List<DownloadGroupTaskEntity> dgEntity = List<DGTEWrapper> wrappers =
DbEntity.findDatas(DownloadGroupTaskEntity.class, "state=?", "3"); DbEntity.findRelationData(DGTEWrapper.class, "DownloadGroupTaskEntity.state=?", "3");
if (dgEntity != null && !dgEntity.isEmpty()) { if (wrappers != null && !wrappers.isEmpty()) {
waitList.addAll(dgEntity); for (DGTEWrapper w : wrappers) {
waitList.add(w.taskEntity);
} }
break; }
case 3: } else if (type == 3) {
List<UploadTaskEntity> uEntity = List<UTEWrapper> wrappers = DbEntity.findRelationData(UTEWrapper.class,
DbEntity.findDatas(UploadTaskEntity.class, "state=?", "3"); "UploadTaskEntity.state=?", "3");
if (uEntity != null && !uEntity.isEmpty()) { if (wrappers != null && !wrappers.isEmpty()) {
waitList.addAll(uEntity); for (UTEWrapper w : wrappers) {
waitList.add(w.taskEntity);
} }
break; }
} }
return waitList; return waitList;
} }
@ -146,8 +151,8 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
AbsTask task = getTask(te.getEntity()); AbsTask task = getTask(te.getEntity());
if (task != null) continue; if (task != null) continue;
if (te instanceof DownloadTaskEntity) { if (te instanceof DownloadTaskEntity) {
if (te.requestType == AbsTaskEntity.D_FTP || te.requestType == AbsTaskEntity.U_FTP) { if (te.getRequestType() == AbsTaskEntity.D_FTP || te.getRequestType() == AbsTaskEntity.U_FTP) {
te.urlEntity = CommonUtil.getFtpUrlInfo(te.getEntity().getKey()); te.setUrlEntity(CommonUtil.getFtpUrlInfo(te.getEntity().getKey()));
} }
mQueue = DownloadTaskQueue.getInstance(); mQueue = DownloadTaskQueue.getInstance();
} else if (te instanceof UploadTaskEntity) { } else if (te instanceof UploadTaskEntity) {

@ -18,11 +18,13 @@ package com.arialyy.aria.core.common;
import android.content.Context; 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.DownloadTaskEntity; 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.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.CommonUtil;
@ -36,12 +38,13 @@ import java.util.concurrent.Executors;
/** /**
* Created by AriaL on 2017/7/1. * Created by AriaL on 2017/7/1.
* 文件下载 * 任务处理
*/ */
public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>> public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable, IUtil { implements Runnable, IUtil {
public static final String STATE = "_state_"; public static final String STATE = "_state_";
public static final String RECORD = "_record_"; public static final String RECORD = "_record_";
protected static final long SUB_LEN = 1024 * 1024;
private final String TAG = "AbsFileer"; private final String TAG = "AbsFileer";
protected IEventListener mListener; protected IEventListener mListener;
@ -49,7 +52,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
protected ENTITY mEntity; protected ENTITY mEntity;
protected File mConfigFile;//信息配置文件 protected File mConfigFile;//信息配置文件
protected Context mContext; protected Context mContext;
protected File mTempFile; //下载的文件 protected File mTempFile; //文件
protected boolean isNewTask = true; protected boolean isNewTask = true;
protected StateConstance mConstance; protected StateConstance mConstance;
private ExecutorService mFixedThreadPool; private ExecutorService mFixedThreadPool;
@ -64,7 +67,6 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
/** /**
* 小于1m的文件不启用多线程 * 小于1m的文件不启用多线程
*/ */
private static final long SUB_LEN = 1024 * 1024;
private Timer mTimer; private Timer mTimer;
private long mUpdateInterval = 1000; private long mUpdateInterval = 1000;
@ -77,7 +79,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
} }
public void setNewTask(boolean newTask) { public void setNewTask(boolean newTask) {
mTaskEntity.isNewTask = newTask; mTaskEntity.setNewTask(newTask);
} }
@Override public void setMaxSpeed(double maxSpeed) { @Override public void setMaxSpeed(double maxSpeed) {
@ -89,10 +91,6 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
} }
} }
public StateConstance getConstance() {
return mConstance;
}
@Override public void run() { @Override public void run() {
if (mConstance.isRunning) { if (mConstance.isRunning) {
return; return;
@ -101,7 +99,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
} }
/** /**
* 开始下载流程 * 开始流程
*/ */
private void startFlow() { private void startFlow() {
mConstance.resetState(); mConstance.resetState();
@ -109,13 +107,13 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
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; mConstance.THREAD_NUM = mTotalThreadNum;
handleNoSupportBP(); handleNoSupportBP();
} else { } else {
mTotalThreadNum = isNewTask ? (getNewTaskThreadNum()) : mStartThreadNum; mTotalThreadNum = isNewTask ? (mStartThreadNum = setNewTaskThreadNum()) : mStartThreadNum;
mConstance.THREAD_NUM = mTotalThreadNum; mConstance.THREAD_NUM = mTotalThreadNum;
handleBreakpoint(); handleBreakpoint();
} }
@ -125,13 +123,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
/** /**
* 设置新任务的最大线程数 * 设置新任务的最大线程数
*/ */
protected int getNewTaskThreadNum() { protected abstract int setNewTaskThreadNum();
final int num =
mEntity.getFileSize() <= SUB_LEN || mTaskEntity.requestType == AbsTaskEntity.D_FTP_DIR ? 1
: AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum();
mStartThreadNum = num;
return num;
}
/** /**
* 启动进度获取定时器 * 启动进度获取定时器
@ -165,13 +157,12 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
* *
* @param interval 单位毫秒不能小于0 * @param interval 单位毫秒不能小于0
*/ */
protected long setUpdateInterval(long interval) { protected void setUpdateInterval(long interval) {
if (interval < 0) { if (interval < 0) {
ALog.w(TAG, "更新间隔不能小于0,默认为1000毫秒"); ALog.w(TAG, "更新间隔不能小于0,默认为1000毫秒");
return 1000; return;
} }
mUpdateInterval = interval; mUpdateInterval = interval;
return interval;
} }
@Override public long getFileSize() { @Override public long getFileSize() {
@ -203,9 +194,11 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
} }
} }
if (mTaskEntity instanceof DownloadTaskEntity) { if (mTaskEntity instanceof DownloadTaskEntity) {
CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, (DownloadTaskEntity) mTaskEntity); CommonUtil.delDownloadTaskConfig(mTaskEntity.isRemoveFile(),
(DownloadEntity) mTaskEntity.getEntity());
} else if (mTaskEntity instanceof UploadTaskEntity) { } else if (mTaskEntity instanceof UploadTaskEntity) {
CommonUtil.delUploadTaskConfig(mTaskEntity.removeFile, (UploadTaskEntity) mTaskEntity); CommonUtil.delUploadTaskConfig(mTaskEntity.isRemoveFile(),
(UploadEntity) mTaskEntity.getEntity());
} }
} }
@ -236,13 +229,6 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
start(); start();
} }
/**
* 返回该下载器的
*/
public IEventListener getListener() {
return mListener;
}
/** /**
* 检查任务是否是新任务新任务条件 * 检查任务是否是新任务新任务条件
* 1文件不存在 * 1文件不存在
@ -296,7 +282,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
/** /**
* 恢复记录地址 * 恢复记录地址
* *
* @return true 表示下载完成 * @return {@code true}任务已完成
*/ */
private boolean resumeRecordLocation(int i, long startL, long endL) { private boolean resumeRecordLocation(int i, long startL, long endL) {
mConstance.CURRENT_LOCATION += endL - startL; mConstance.CURRENT_LOCATION += endL - startL;
@ -332,7 +318,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
config.START_LOCATION = startL; config.START_LOCATION = startL;
config.END_LOCATION = endL; config.END_LOCATION = endL;
config.CONFIG_FILE_PATH = mConfigFile.getPath(); config.CONFIG_FILE_PATH = mConfigFile.getPath();
config.SUPPORT_BP = mTaskEntity.isSupportBP; config.SUPPORT_BP = mTaskEntity.isSupportBP();
config.TASK_ENTITY = mTaskEntity; config.TASK_ENTITY = mTaskEntity;
return selectThreadTask(config); return selectThreadTask(config);
} }
@ -349,8 +335,8 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
recordL[i] = -1; recordL[i] = -1;
} }
int rl = 0; int rl = 0;
if (isNewTask) { if (isNewTask && !handleNewTask()) {
handleNewTask(); 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;
@ -404,13 +390,15 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
mFixedThreadPool.execute(task); mFixedThreadPool.execute(task);
} }
} }
mTaskEntity.isNewTask = false; mTaskEntity.setNewTask(false);
} }
/** /**
* 处理新任务 * 处理新任务
*
* @return {@code true}创建新任务失败
*/ */
protected abstract void handleNewTask(); protected abstract boolean handleNewTask();
/** /**
* 处理不支持断点的下载 * 处理不支持断点的下载
@ -424,7 +412,7 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
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.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);
if (task == null) return; if (task == null) return;

@ -82,7 +82,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
ALog.i(TAG, s); ALog.i(TAG, s);
boolean isExist = files.length != 0; boolean isExist = files.length != 0;
if (!isExist && !isUpload) { if (!isExist && !isUpload) {
failDownload("文件不存在,任务链接【" + mTaskEntity.urlEntity.url + "】,remotePath:" + remotePath, failDownload("文件不存在,任务链接【" + mTaskEntity.getUrlEntity().url + "】,remotePath:" + remotePath,
false); false);
int i = remotePath.lastIndexOf(File.separator); int i = remotePath.lastIndexOf(File.separator);
FTPFile[] files1; FTPFile[] files1;
@ -111,14 +111,14 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
if (!FTPReply.isPositiveCompletion(reply)) { if (!FTPReply.isPositiveCompletion(reply)) {
if (isUpload) { if (isUpload) {
//服务器上没有该文件路径,表示该任务为新的上传任务 //服务器上没有该文件路径,表示该任务为新的上传任务
mTaskEntity.isNewTask = true; mTaskEntity.setNewTask(true);
} else { } else {
client.disconnect(); client.disconnect();
failDownload("获取文件信息错误,错误码为:" + reply + ",msg:" + client.getReplyString(), true); failDownload("获取文件信息错误,错误码为:" + reply + ",msg:" + client.getReplyString(), true);
return; return;
} }
} }
mTaskEntity.code = reply; mTaskEntity.setCode(reply);
if (mSize != 0 && !isUpload) { if (mSize != 0 && !isUpload) {
mEntity.setFileSize(mSize); mEntity.setFileSize(mSize);
} }
@ -164,15 +164,16 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
*/ */
private FTPClient createFtpClient() { private FTPClient createFtpClient() {
FTPClient client = null; FTPClient client = null;
final FtpUrlEntity urlEntity = mTaskEntity.urlEntity; final FtpUrlEntity urlEntity = mTaskEntity.getUrlEntity();
try { try {
Pattern p = Pattern.compile(Regular.REG_IP_V4); Pattern p = Pattern.compile(Regular.REG_IP_V4);
Matcher m = p.matcher(urlEntity.hostName); Matcher m = p.matcher(urlEntity.hostName);
if (m.find() && m.groupCount() > 0) { if (m.find() && m.groupCount() > 0) {
client = new FTPClient(); client = new FTPClient();
InetAddress ip = InetAddress.getByName(urlEntity.hostName); InetAddress ip = InetAddress.getByName(urlEntity.hostName);
client.setConnectTimeout(10000); // 连接10s超时
client.connect(ip, Integer.parseInt(urlEntity.port)); client.connect(ip, Integer.parseInt(urlEntity.port));
mTaskEntity.urlEntity.validAddr = ip; mTaskEntity.getUrlEntity().validAddr = ip;
} else { } else {
InetAddress[] ips = InetAddress.getAllByName(urlEntity.hostName); InetAddress[] ips = InetAddress.getAllByName(urlEntity.hostName);
client = connect(new FTPClient(), ips, 0, Integer.parseInt(urlEntity.port)); client = connect(new FTPClient(), ips, 0, Integer.parseInt(urlEntity.port));
@ -211,10 +212,10 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码 // 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
charSet = "UTF-8"; charSet = "UTF-8";
reply = client.sendCommand("OPTS UTF8", "ON"); reply = client.sendCommand("OPTS UTF8", "ON");
if (!TextUtils.isEmpty(mTaskEntity.charSet) || (!FTPReply.isPositiveCompletion(reply) if (!TextUtils.isEmpty(mTaskEntity.getCharSet()) || (!FTPReply.isPositiveCompletion(reply)
&& reply != FTPReply.COMMAND_OK)) { && reply != FTPReply.COMMAND_OK)) {
ALog.i(TAG, "FTP 服务器不支持开启UTF8编码,尝试使用Aria手动设置的编码"); ALog.i(TAG, "FTP 服务器不支持开启UTF8编码,尝试使用Aria手动设置的编码");
charSet = mTaskEntity.charSet; charSet = mTaskEntity.getCharSet();
} }
client.setControlEncoding(charSet); client.setControlEncoding(charSet);
client.setDataTimeout(10 * 1000); client.setDataTimeout(10 * 1000);
@ -233,7 +234,7 @@ public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY ext
private FTPClient connect(FTPClient client, InetAddress[] ips, int index, int port) { private FTPClient connect(FTPClient client, InetAddress[] ips, int index, int port) {
try { try {
client.connect(ips[index], port); client.connect(ips[index], port);
mTaskEntity.urlEntity.validAddr = ips[index]; mTaskEntity.getUrlEntity().validAddr = ips[index];
return client; return client;
} catch (IOException e) { } catch (IOException e) {
//e.printStackTrace(); //e.printStackTrace();

@ -51,7 +51,7 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
*/ */
protected FTPClient createClient() { protected FTPClient createClient() {
FTPClient client = null; FTPClient client = null;
final FtpUrlEntity urlEntity = mTaskEntity.urlEntity; final FtpUrlEntity urlEntity = mTaskEntity.getUrlEntity();
if (urlEntity.validAddr == null) { if (urlEntity.validAddr == null) {
try { try {
InetAddress[] ips = InetAddress.getAllByName(urlEntity.hostName); InetAddress[] ips = InetAddress.getAllByName(urlEntity.hostName);
@ -93,9 +93,9 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
} }
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码 // 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
charSet = "UTF-8"; charSet = "UTF-8";
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion( if (!TextUtils.isEmpty(mTaskEntity.getCharSet()) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) { client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet; charSet = mTaskEntity.getCharSet();
} }
client.setControlEncoding(charSet); client.setControlEncoding(charSet);
client.setDataTimeout(10 * 1000); client.setDataTimeout(10 * 1000);
@ -114,7 +114,7 @@ public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTI
private FTPClient connect(FTPClient client, InetAddress[] ips, int index, int port) { private FTPClient connect(FTPClient client, InetAddress[] ips, int index, int port) {
try { try {
client.connect(ips[index], port); client.connect(ips[index], port);
mTaskEntity.urlEntity.validAddr = ips[index]; mTaskEntity.getUrlEntity().validAddr = ips[index];
return client; return client;
} catch (IOException e) { } catch (IOException e) {
try { try {

@ -86,7 +86,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
mEntity = mTaskEntity.getEntity(); mEntity = mTaskEntity.getEntity();
mConfigFPath = info.CONFIG_FILE_PATH; mConfigFPath = info.CONFIG_FILE_PATH;
mBufSize = manager.getDownloadConfig().getBuffSize(); mBufSize = manager.getDownloadConfig().getBuffSize();
setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed()); setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxSpeed());
mTaskType = getTaskType(); mTaskType = getTaskType();
mLastSaveTime = System.currentTimeMillis(); mLastSaveTime = System.currentTimeMillis();
mConfigThreadPool = Executors.newCachedThreadPool(); mConfigThreadPool = Executors.newCachedThreadPool();
@ -200,7 +200,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
try { try {
if (ex != null) { if (ex != null) {
ALog.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex)); ALog.e(TAG, msg + "\n" + ALog.getExceptionString(ex));
} else { } else {
ALog.e(TAG, msg); ALog.e(TAG, msg);
} }
@ -210,7 +210,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
} else { } else {
ALog.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败"); ALog.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
mListener.onFail(true); mListener.onFail(true);
ErrorHelp.saveError(mTaskType, mEntity, "", CommonUtil.getPrintException(ex)); ErrorHelp.saveError(TAG, "", ALog.getExceptionString(ex));
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();

@ -0,0 +1,31 @@
/*
* 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;
/**
* Created by AriaL on 2018/3/3.
* 获取文件信息完成后 回调给下载线程的信息
*/
public class CompleteInfo {
/**
* 自定义的状态码
*/
public int code;
public CompleteInfo(int code) {
this.code = code;
}
}

@ -18,7 +18,7 @@ package com.arialyy.aria.core.common;
/** /**
* Created by lyy on 2016/10/31. * Created by lyy on 2016/10/31.
* 抽象的下载接口 * 任务功能接口
*/ */
public interface IUtil { public interface IUtil {
@ -28,39 +28,39 @@ public interface IUtil {
long getFileSize(); long getFileSize();
/** /**
* 获取当前下载位置 * 获取当前位置
*/ */
long getCurrentLocation(); long getCurrentLocation();
/** /**
* 是否正在下载 * 任务是否正在执行
* *
* @return true, 正在下载 * @return {@code true} 任务正在执行
*/ */
boolean isRunning(); boolean isRunning();
/** /**
* 取消下载 * 取消
*/ */
void cancel(); void cancel();
/** /**
* 停止下载 * 停止
*/ */
void stop(); void stop();
/** /**
* 开始下载 * 开始
*/ */
void start(); void start();
/** /**
* 从上次断点恢复下载 * 从上次断点恢复
*/ */
void resume(); void resume();
/** /**
* 设置最大下载速度 * 设置最大速度
*/ */
void setMaxSpeed(double maxSpeed); void setMaxSpeed(double maxSpeed);
} }

@ -1,12 +1,27 @@
/*
* 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; package com.arialyy.aria.core.common;
public interface OnFileInfoCallback { public interface OnFileInfoCallback {
/** /**
* 处理完成 * 处理完成
* *
* @param code 状态码 * @param info 一些回调的信息
*/ */
void onComplete(String url, int code); void onComplete(String url, CompleteInfo info);
/** /**
* 请求失败 * 请求失败

@ -13,22 +13,20 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core; package com.arialyy.aria.core.common;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
/** /**
* Created by lyy on 2017/10/17. * Created by laoyuyu on 2018/3/21.
* Url 映射表 * 任务上传或下载的记录
*/ */
public class UrlMapping extends DbEntity { class TaskRecord extends DbEntity {
/** /**
* 各实体对应的key * 任务线程数
*/ */
public String key; public int threadNum;
//public int re
/**
* 链接
*/
public String url;
} }

@ -0,0 +1,66 @@
/*
* 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.delegate;
import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.core.inf.ITarget;
import com.arialyy.aria.util.ALog;
/**
* Created by laoyuyu on 2018/3/9.
* ftp 委托
*/
public class FtpDelegate<TARGET extends ITarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements IFtpTarget<TARGET> {
private static final String TAG = "FtpDelegate";
private ENTITY mEntity;
private TASK_ENTITY mTaskEntity;
private TARGET mTarget;
public FtpDelegate(TARGET target, TASK_ENTITY taskEntity) {
mTarget = target;
mTaskEntity = taskEntity;
mEntity = mTaskEntity.getEntity();
}
@Override public TARGET charSet(String charSet) {
if (TextUtils.isEmpty(charSet)) return mTarget;
mTaskEntity.setCharSet(charSet);
return mTarget;
}
@Override public TARGET login(String userName, String password) {
return login(userName, password, null);
}
@Override public TARGET login(String userName, String password, String account) {
if (TextUtils.isEmpty(userName)) {
ALog.e(TAG, "用户名不能为null");
return mTarget;
} else if (TextUtils.isEmpty(password)) {
ALog.e(TAG, "密码不能为null");
return mTarget;
}
mTaskEntity.getUrlEntity().needLogin = true;
mTaskEntity.getUrlEntity().user = userName;
mTaskEntity.getUrlEntity().password = password;
mTaskEntity.getUrlEntity().account = account;
return mTarget;
}
}

@ -0,0 +1,139 @@
/*
* 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.delegate;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IHttpHeaderTarget;
import com.arialyy.aria.core.inf.ITarget;
import com.arialyy.aria.util.ALog;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Created by laoyuyu on 2018/3/9.
* HTTP header参数设置委托类
*/
public class HttpHeaderDelegate<TARGET extends ITarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements IHttpHeaderTarget<TARGET> {
private static final String TAG = "HttpHeaderDelegate";
private ENTITY mEntity;
private TASK_ENTITY mTaskEntity;
private TARGET mTarget;
public HttpHeaderDelegate(TARGET target, TASK_ENTITY taskEntity) {
mTarget = target;
mTaskEntity = taskEntity;
mEntity = mTaskEntity.getEntity();
}
/**
* 给url请求添加Header数据
* 如果新的header数据和数据保存的不一致则更新数据库中对应的header数据
*
* @param key header对应的key
* @param value header对应的value
*/
@Override
public TARGET addHeader(@NonNull String key, @NonNull String value) {
if (TextUtils.isEmpty(key)) {
ALog.w(TAG, "设置header失败,header对应的key不能为null");
return mTarget;
} else if (TextUtils.isEmpty(value)) {
ALog.w(TAG, "设置header失败,header对应的value不能为null");
return mTarget;
}
if (mTaskEntity.getHeaders().get(key) == null) {
mTaskEntity.getHeaders().put(key, value);
} else if (!mTaskEntity.getHeaders().get(key).equals(value)) {
mTaskEntity.getHeaders().put(key, value);
}
return mTarget;
}
/**
* 给url请求添加一组header数据
* 如果新的header数据和数据保存的不一致则更新数据库中对应的header数据
*
* @param headers 一组http header数据
*/
@Override
public TARGET addHeaders(@NonNull Map<String, String> headers) {
if (headers.size() == 0) {
ALog.w(TAG, "设置header失败,map没有header数据");
return mTarget;
}
/*
两个map比较逻辑
1比对key是否相同
2如果key相同比对value是否相同
3只有当上面两个步骤中key value都相同时才能任务两个map数据一致
*/
boolean mapEquals = false;
if (mTaskEntity.getHeaders().size() == headers.size()) {
int i = 0;
Set<String> keys = mTaskEntity.getHeaders().keySet();
for (String key : keys) {
if (headers.containsKey(key)) {
i++;
} else {
break;
}
}
if (i == mTaskEntity.getHeaders().size()) {
int j = 0;
Collection<String> values = mTaskEntity.getHeaders().values();
for (String value : values) {
if (headers.containsValue(value)) {
j++;
} else {
break;
}
}
if (j == mTaskEntity.getHeaders().size()) {
mapEquals = true;
}
}
}
if (!mapEquals) {
mTaskEntity.getHeaders().clear();
Set<String> keys = headers.keySet();
for (String key : keys) {
mTaskEntity.getHeaders().put(key, headers.get(key));
}
}
return mTarget;
}
/**
* 设置请求类型POST或GET默认为在GET
* 只试用于HTTP请求
*
* @param requestEnum {@link RequestEnum}
*/
@Override
public TARGET setRequestMode(RequestEnum requestEnum) {
mTaskEntity.setRequestEnum(requestEnum);
return mTarget;
}
}

@ -0,0 +1,97 @@
/*
* 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.download;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.util.CommonUtil;
/**
* Created by lyy on 2017/2/28.
*/
abstract class AbsDownloadTarget<TARGET extends AbsTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
extends AbsTarget<TARGET, ENTITY, TASK_ENTITY> {
static final int HTTP = 1;
static final int FTP = 2;
//HTTP任务组
static final int GROUP_HTTP = 3;
//FTP文件夹
static final int GROUP_FTP_DIR = 4;
/**
* 设置的文件保存路径的临时变量
*/
String mTempFilePath;
/**
* 将任务设置为最高优先级任务最高优先级任务有以下特点
* 1在下载队列中有且只有一个最高优先级任务
* 2最高优先级任务会一直存在直到用户手动暂停或任务完成
* 3任务调度器不会暂停最高优先级任务
* 4用户手动暂停或任务完成后第二次重新执行该任务该命令将失效
* 5如果下载队列中已经满了则会停止队尾的任务当高优先级任务完成后该队尾任务将自动执行
* 6把任务设置为最高优先级任务后将自动执行任务不需要重新调用start()启动任务
*/
protected void setHighestPriority() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity,
NormalCmdFactory.TASK_HIGHEST_PRIORITY, checkTaskType()))
.exe();
}
}
/**
* 添加任务
*/
public void add() {
if (checkEntity()) {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE,
checkTaskType()))
.exe();
}
}
/**
* 获取任务文件大小
*
* @return 文件大小
*/
public long getFileSize() {
return getSize();
}
/**
* 获取单位转换后的文件大小
*
* @return 文件大小{@code xxx mb}
*/
public String getConvertFileSize() {
return getConvertSize();
}
/**
* 设置target类型
*
* @return {@link #HTTP}{@link #FTP}{@link #GROUP_HTTP}{@link #GROUP_FTP_DIR}
*/
protected abstract int getTargetType();
}

@ -150,11 +150,11 @@ class BaseDListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<
} }
private void saveData(int state, long location) { private void saveData(int state, long location) {
mTaskEntity.state = state; mTaskEntity.setState(state);
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) {
mTaskEntity.deleteData(); mEntity.deleteData();
return; return;
} else if (mEntity.isComplete()) { } else if (mEntity.isComplete()) {
mEntity.setCompleteTime(System.currentTimeMillis()); mEntity.setCompleteTime(System.currentTimeMillis());

@ -16,32 +16,31 @@
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsDownloadTarget; import android.util.Log;
import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.manager.SubTaskManager; import com.arialyy.aria.core.manager.SubTaskManager;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.ALog;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* Created by Aria.Lao on 2017/7/26. * Created by Aria.Lao on 2017/7/26.
*/ */
abstract class BaseGroupTarget<TARGET extends AbsTarget, TASK_ENTITY extends AbsGroupTaskEntity> abstract class BaseGroupTarget<TARGET extends BaseGroupTarget>
extends AbsDownloadTarget<TARGET, DownloadGroupEntity, TASK_ENTITY> { extends AbsDownloadTarget<TARGET, DownloadGroupEntity, DownloadGroupTaskEntity> {
List<String> mUrls = new ArrayList<>(); /**
* 组任务名
*/
String mGroupName; String mGroupName;
/** /**
* 子任务文件名 * 文件夹临时路径
*/ */
private List<String> mSubTaskFileName = new ArrayList<>(); String mDirPathTemp;
/** /**
* 是否已经设置了文件路径 * 是否需要修改路径
*/ */
private boolean isSetDirPathed = false; boolean needModifyPath = false;
private SubTaskManager mSubTaskManager; private SubTaskManager mSubTaskManager;
@ -63,10 +62,24 @@ abstract class BaseGroupTarget<TARGET extends AbsTarget, TASK_ENTITY extends Abs
public TARGET setGroupAlias(String alias) { public TARGET setGroupAlias(String alias) {
if (TextUtils.isEmpty(alias)) return (TARGET) this; if (TextUtils.isEmpty(alias)) return (TARGET) this;
mEntity.setAlias(alias); mEntity.setAlias(alias);
mEntity.update();
return (TARGET) this; return (TARGET) this;
} }
@Override public boolean taskExists() {
return DownloadGroupTaskQueue.getInstance().getTask(mEntity.getGroupName()) != null;
}
/**
* 设置任务组的文件夹路径该api后续会删除
*
* @param groupDirPath 任务组保存文件夹路径
* @deprecated {@link #setDirPath(String)} 请使用这个api
*/
@Deprecated
public TARGET setDownloadDirPath(String groupDirPath) {
return setDirPath(groupDirPath);
}
/** /**
* 设置任务组的文件夹路径在Aria中任务组的所有子任务都会下载到以任务组组名的文件夹中 * 设置任务组的文件夹路径在Aria中任务组的所有子任务都会下载到以任务组组名的文件夹中
* groupDirPath = "/mnt/sdcard/download/group_test" * groupDirPath = "/mnt/sdcard/download/group_test"
@ -84,130 +97,69 @@ abstract class BaseGroupTarget<TARGET extends AbsTarget, TASK_ENTITY extends Abs
* } * }
* </pre> * </pre>
* *
* @param groupDirPath 任务组保存文件夹路径 * @param dirPath 任务组保存文件夹路径
*/ */
public TARGET setDownloadDirPath(String groupDirPath) { public TARGET setDirPath(String dirPath) {
if (TextUtils.isEmpty(groupDirPath)) { mDirPathTemp = dirPath;
throw new NullPointerException("任务组文件夹保存路径不能为null");
}
isSetDirPathed = true;
if (mEntity.getDirPath().equals(groupDirPath)) return (TARGET) this;
File file = new File(groupDirPath);
if (file.exists() && file.isFile()) {
throw new IllegalArgumentException("路径不能为文件");
}
if (!file.exists()) {
file.mkdirs();
}
mEntity.setDirPath(groupDirPath);
if (!TextUtils.isEmpty(mEntity.getDirPath())) {
reChangeDirPath(groupDirPath);
} else {
mEntity.setSubTasks(createSubTask());
}
mEntity.update();
return (TARGET) this; return (TARGET) this;
} }
@Override public boolean isRunning() {
DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(mEntity.getKey());
return task != null && task.isRunning();
}
/** /**
* 改变任务组文件夹路径修改文件夹路径会将子任务所有路径更换 * 改变任务组文件夹路径修改文件夹路径会将子任务所有路径更换
* *
* @param newDirPath 新的文件夹路径 * @param newDirPath 新的文件夹路径
*/ */
private void reChangeDirPath(String newDirPath) { void reChangeDirPath(String newDirPath) {
List<DownloadEntity> subTask = mEntity.getSubTask(); List<DownloadTaskEntity> subTasks = mTaskEntity.getSubTaskEntities();
if (subTask != null && !subTask.isEmpty()) { if (subTasks != null && !subTasks.isEmpty()) {
for (DownloadEntity entity : subTask) { for (DownloadTaskEntity dte : subTasks) {
String oldPath = entity.getDownloadPath(); DownloadEntity de = dte.getEntity();
String newPath = newDirPath + "/" + entity.getFileName(); String oldPath = de.getDownloadPath();
String newPath = newDirPath + "/" + de.getFileName();
File file = new File(oldPath); File file = new File(oldPath);
file.renameTo(new File(newPath)); if (file.exists()) {
DbEntity.exeSql("UPDATE DownloadEntity SET downloadPath='" file.renameTo(new File(newPath));
+ newPath }
+ "' WHERE downloadPath='" de.setDownloadPath(newPath);
+ oldPath dte.setKey(newPath);
+ "'"); de.save();
DbEntity.exeSql( dte.save();
"UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'");
} }
} else {
mEntity.setSubTasks(createSubTask());
} }
} }
/** /**
* 设置子任务文件名该方法必须在{@link #setDownloadDirPath(String)}之后调用否则不生效 * 检查并设置文件夹路径
* *
* @see #setSubFileName(List) * @return {@code true} 合法
*/
@Deprecated public TARGET setSubTaskFileName(List<String> subTaskFileName) {
return setSubFileName(subTaskFileName);
}
/**
* 设置子任务文件名该方法必须在{@link #setDownloadDirPath(String)}之后调用否则不生效
*/ */
public TARGET setSubFileName(List<String> subTaskFileName) { boolean checkDirPath() {
if (subTaskFileName == null || subTaskFileName.isEmpty()) return (TARGET) this; if (TextUtils.isEmpty(mDirPathTemp)) {
mSubTaskFileName.addAll(subTaskFileName); ALog.e(TAG, "文件夹路径不能为null");
if (mUrls.size() != subTaskFileName.size()) { return false;
throw new IllegalArgumentException("下载链接数必须要和保存路径的数量一致"); } else if (!mDirPathTemp.startsWith("/")) {
ALog.e(TAG, "文件夹路径【" + mDirPathTemp + "】错误");
return false;
} }
if (isSetDirPathed) { File file = new File(mDirPathTemp);
List<DownloadEntity> entities = mEntity.getSubTask(); if (file.isFile()) {
int i = 0; ALog.e(TAG, "路径【" + mDirPathTemp + "】是文件,请设置文件夹路径");
for (DownloadEntity entity : entities) { return false;
if (i < mSubTaskFileName.size()) {
String newName = mSubTaskFileName.get(i);
updateSubFileName(entity, newName);
}
i++;
}
} }
return (TARGET) this;
}
/** if (TextUtils.isEmpty(mEntity.getDirPath()) || !mEntity.getDirPath().equals(mDirPathTemp)) {
* 更新子任务文件名 if (!file.exists()) {
*/ file.mkdirs();
private void updateSubFileName(DownloadEntity entity, String newName) {
if (!newName.equals(entity.getFileName())) {
String oldPath = mEntity.getDirPath() + "/" + entity.getFileName();
String newPath = mEntity.getDirPath() + "/" + newName;
File oldFile = new File(oldPath);
if (oldFile.exists()) {
oldFile.renameTo(new File(newPath));
} }
CommonUtil.renameDownloadConfig(oldFile.getName(), newName); needModifyPath = true;
DbEntity.exeSql( mEntity.setDirPath(mDirPathTemp);
"UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'");
entity.setDownloadPath(newPath);
entity.setFileName(newName);
entity.update();
} }
}
/** return true;
* 创建子任务
*/
private List<DownloadEntity> createSubTask() {
List<DownloadEntity> list = new ArrayList<>();
for (int i = 0, len = mUrls.size(); i < len; i++) {
DownloadEntity entity = new DownloadEntity();
entity.setUrl(mUrls.get(i));
String fileName =
mSubTaskFileName.isEmpty() ? createFileName(entity.getUrl()) : mSubTaskFileName.get(i);
entity.setDownloadPath(mEntity.getDirPath() + "/" + fileName);
entity.setGroupName(mGroupName);
entity.setGroupChild(true);
entity.setFileName(fileName);
entity.insert();
list.add(entity);
}
return list;
} }
} }

@ -0,0 +1,183 @@
/*
* 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.download;
import android.text.TextUtils;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
/**
* Created by Aria.Lao on 2017/7/26.
*/
abstract class BaseNormalTarget<TARGET extends BaseNormalTarget>
extends AbsDownloadTarget<TARGET, DownloadEntity, DownloadTaskEntity> {
/**
* 资源地址
*/
protected String url;
/**
* 通过地址初始化target
*/
void initTarget(String url, String targetName, boolean refreshInfo) {
this.url = url;
mTargetName = targetName;
mTaskEntity = TEManager.getInstance().getTEntity(DownloadTaskEntity.class, url);
mEntity = mTaskEntity.getEntity();
mTaskEntity.setRefreshInfo(refreshInfo);
if (mEntity != null) {
mTempFilePath = mEntity.getDownloadPath();
}
}
/**
* 将任务设置为最高优先级任务最高优先级任务有以下特点
* 1在下载队列中有且只有一个最高优先级任务
* 2最高优先级任务会一直存在直到用户手动暂停或任务完成
* 3任务调度器不会暂停最高优先级任务
* 4用户手动暂停或任务完成后第二次重新执行该任务该命令将失效
* 5如果下载队列中已经满了则会停止队尾的任务当高优先级任务完成后该队尾任务将自动执行
* 6把任务设置为最高优先级任务后将自动执行任务不需要重新调用start()启动任务
*/
@Override public void setHighestPriority() {
super.setHighestPriority();
}
/**
* 下载任务是否存在
*
* @return {@code true}任务存在
*/
@Override public boolean taskExists() {
return DownloadTaskQueue.getInstance().getTask(mEntity.getUrl()) != null;
}
/**
* 获取下载实体
*/
public DownloadEntity getDownloadEntity() {
return mEntity;
}
/**
* 是否在下载该api后续版本会删除
*
* @deprecated {@link #isRunning()}
*/
@Deprecated public boolean isDownloading() {
return isRunning();
}
/**
* 是否在下载
*
* @return {@code true}任务正在下载
*/
@Override public boolean isRunning() {
DownloadTask task = DownloadTaskQueue.getInstance().getTask(mEntity.getKey());
return task != null && task.isRunning();
}
/**
* 检查下载实体判断实体是否合法
* 合法标准为
* 1下载路径不为null并且下载路径是正常的http或ftp路径
* 2保存路径不为null并且保存路径是android文件系统路径
* 3保存路径不能重复
*
* @return {@code true}合法
*/
@Override protected boolean checkEntity() {
boolean b = getTargetType() < GROUP_HTTP && checkUrl() && checkFilePath();
if (b) {
mEntity.save();
mTaskEntity.save();
}
return b;
}
/**
* 检查并设置普通任务的文件保存路径
*
* @return {@code true}保存路径合法
*/
private boolean checkFilePath() {
String filePath = mTempFilePath;
if (TextUtils.isEmpty(filePath)) {
ALog.e(TAG, "下载失败,文件保存路径为null");
return false;
} else if (!filePath.startsWith("/")) {
ALog.e(TAG, "下载失败,文件保存路径【" + filePath + "】错误");
return false;
}
File file = new File(filePath);
if (file.isDirectory()) {
if (getTargetType() == HTTP) {
ALog.e(TAG, "下载失败,保存路径【" + filePath + "】不能为文件夹,路径需要是完整的文件路径,如:/mnt/sdcard/game.zip");
return false;
} else if (getTargetType() == FTP) {
filePath += mEntity.getFileName();
}
}
mEntity.setFileName(file.getName());
//设置文件保存路径,如果新文件路径和就文件路径不同,则修改路径
if (!filePath.equals(mEntity.getDownloadPath())) {
if (DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=?", filePath)) {
ALog.e(TAG, "下载失败,保存路径【" + filePath + "】已经被其它任务占用,请设置其它保存路径");
return false;
}
File oldFile = new File(mEntity.getDownloadPath());
File newFile = new File(filePath);
mEntity.setDownloadPath(filePath);
mEntity.setFileName(newFile.getName());
mTaskEntity.setKey(filePath);
//mTaskEntity.update();
if (oldFile.exists()) {
oldFile.renameTo(newFile);
CommonUtil.renameDownloadConfig(oldFile.getName(), newFile.getName());
}
}
return true;
}
/**
* 检查普通任务的下载地址
*
* @return {@code true}地址合法
*/
private boolean checkUrl() {
final String url = mEntity.getUrl();
if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "下载失败,url为null");
return false;
} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
ALog.e(TAG, "下载失败,url【" + url + "】错误");
return false;
}
int index = url.indexOf("://");
if (index == -1) {
ALog.e(TAG, "下载失败,url【" + url + "】不合法");
return false;
}
return true;
}
}

@ -21,8 +21,9 @@ import android.os.Parcelable;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsNormalEntity; import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.orm.Foreign; import com.arialyy.aria.orm.ActionPolicy;
import com.arialyy.aria.orm.Primary; import com.arialyy.aria.orm.annotation.Foreign;
import com.arialyy.aria.orm.annotation.Primary;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
/** /**
@ -30,33 +31,30 @@ import com.arialyy.aria.util.CommonUtil;
* 下载实体 * 下载实体
*/ */
public class DownloadEntity extends AbsNormalEntity implements Parcelable { public class DownloadEntity extends AbsNormalEntity implements Parcelable {
@Primary private String downloadPath = ""; //保存路径 @Primary private String downloadPath; //保存路径
/** /**
* 所属任务组 * 所属任务组
*/ */
@Foreign(table = DownloadGroupEntity.class, column = "groupName") private String groupName = ""; @Foreign(parent = DownloadGroupEntity.class, column = "groupName",
onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
private String groupName;
/** /**
* 下载任务实体的key * 从服务器的返回信息中获取的文件md5信息如果服务器没有返回则不会设置该信息
*/
@Foreign(table = DownloadTaskEntity.class, column = "key") private String taskKey = "";
/**
* 通过{@link AbsTaskEntity#md5Key}从服务器的返回信息中获取的文件md5信息如果服务器没有返回则不会设置该信息
* 如果你已经设置了该任务的MD5信息Aria也不会从服务器返回的信息中获取该信息 * 如果你已经设置了该任务的MD5信息Aria也不会从服务器返回的信息中获取该信息
*/ */
private String md5Code = ""; private String md5Code;
/** /**
* 通过{@link AbsTaskEntity#dispositionKey}从服务器的返回信息中获取的文件描述信息 * 从服务器的返回信息中获取的文件描述信息
*/ */
private String disposition = ""; private String disposition;
/** /**
* 从disposition获取到的文件名如果可以获取到则会赋值到这个字段 * 从disposition获取到的文件名如果可以获取到则会赋值到这个字段
*/ */
private String serverFileName = ""; private String serverFileName;
@Override public String getKey() { @Override public String getKey() {
return getUrl(); return getUrl();
@ -101,13 +99,6 @@ public class DownloadEntity extends AbsNormalEntity implements Parcelable {
this.groupName = groupName; this.groupName = groupName;
} }
/**
* {@link #getUrl()}
*/
@Deprecated public String getDownloadUrl() {
return getUrl();
}
public String getDownloadPath() { public String getDownloadPath() {
return downloadPath; return downloadPath;
} }
@ -117,8 +108,6 @@ public class DownloadEntity extends AbsNormalEntity implements Parcelable {
return this; return this;
} }
@Override public DownloadEntity clone() throws CloneNotSupportedException { @Override public DownloadEntity clone() throws CloneNotSupportedException {
return (DownloadEntity) super.clone(); return (DownloadEntity) super.clone();
} }

@ -18,8 +18,7 @@ package com.arialyy.aria.core.download;
import android.os.Parcel; import android.os.Parcel;
import com.arialyy.aria.core.inf.AbsGroupEntity; import com.arialyy.aria.core.inf.AbsGroupEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.orm.OneToMany; import com.arialyy.aria.orm.annotation.Ignore;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
@ -28,22 +27,24 @@ import java.util.List;
*/ */
public class DownloadGroupEntity extends AbsGroupEntity { public class DownloadGroupEntity extends AbsGroupEntity {
@OneToMany(table = DownloadEntity.class, key = "groupName") private List<DownloadEntity> subtask = @Ignore private List<DownloadEntity> subEntities;
new ArrayList<>();
/** /**
* 任务组下载文件的文件夹地址 * 任务组下载文件的文件夹地址
* *
* @see DownloadGroupTarget#setDownloadDirPath(String) * @see DownloadGroupTarget#setDirPath(String)
*/ */
private String dirPath = ""; private String dirPath;
public List<DownloadEntity> getSubTask() { /**
return subtask; * 子任务实体列表
*/
public List<DownloadEntity> getSubEntities() {
return subEntities;
} }
public void setSubTasks(List<DownloadEntity> subTasks) { public void setSubEntities(List<DownloadEntity> subTasks) {
this.subtask = subTasks; this.subEntities = subTasks;
} }
public String getDirPath() { public String getDirPath() {
@ -71,13 +72,13 @@ 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.subtask); dest.writeTypedList(this.subEntities);
dest.writeString(this.dirPath); dest.writeString(this.dirPath);
} }
protected DownloadGroupEntity(Parcel in) { protected DownloadGroupEntity(Parcel in) {
super(in); super(in);
this.subtask = in.createTypedArrayList(DownloadEntity.CREATOR); this.subEntities = in.createTypedArrayList(DownloadEntity.CREATOR);
this.dirPath = in.readString(); this.dirPath = in.readString();
} }

@ -86,7 +86,7 @@ class DownloadGroupListener
private void saveCurrentLocation() { private void saveCurrentLocation() {
long location = 0; long location = 0;
for (DownloadEntity e : mEntity.getSubTask()) { for (DownloadEntity e : mEntity.getSubEntities()) {
location += e.getCurrentProgress(); location += e.getCurrentProgress();
} }
mEntity.setCurrentProgress(location); mEntity.setCurrentProgress(location);

@ -15,45 +15,53 @@
*/ */
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import com.arialyy.aria.core.inf.IEntity; import android.text.TextUtils;
import com.arialyy.aria.core.manager.TEManager; import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* Created by AriaL on 2017/6/29. * Created by AriaL on 2017/6/29.
* 下载任务组 * 下载任务组
*/ */
public class DownloadGroupTarget public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
extends BaseGroupTarget<DownloadGroupTarget, DownloadGroupTaskEntity> { /**
private final String TAG = "DownloadGroupTarget"; * 子任务下载地址
*/
private List<String> mUrls = new ArrayList<>();
/**
* 子任务文件名
*/
private List<String> mSubNameTemp = new ArrayList<>();
DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) { DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) {
this.mTargetName = targetName; this.mTargetName = targetName;
if (groupEntity.getUrls() != null && !groupEntity.getUrls().isEmpty()) { if (groupEntity.getUrls() != null && !groupEntity.getUrls().isEmpty()) {
this.mUrls.addAll(groupEntity.getUrls()); this.mUrls.addAll(groupEntity.getUrls());
} }
mGroupName = CommonUtil.getMd5Code(groupEntity.getUrls()); init();
mTaskEntity = TEManager.getInstance().getTEntity(DownloadGroupTaskEntity.class, mGroupName);
if (mTaskEntity == null) {
mTaskEntity =
TEManager.getInstance().createTEntity(DownloadGroupTaskEntity.class, groupEntity);
}
mEntity = mTaskEntity.entity;
} }
DownloadGroupTarget(List<String> urls, String targetName) { DownloadGroupTarget(List<String> urls, String targetName) {
this.mTargetName = targetName; this.mTargetName = targetName;
this.mUrls = urls; this.mUrls = urls;
mGroupName = CommonUtil.getMd5Code(urls); init();
mTaskEntity = TEManager.getInstance().getTEntity(DownloadGroupTaskEntity.class, mGroupName); }
if (mTaskEntity == null) {
mTaskEntity = TEManager.getInstance().createGTEntity(DownloadGroupTaskEntity.class, mUrls); private void init() {
mGroupName = CommonUtil.getMd5Code(mUrls);
mTaskEntity = TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, mUrls);
mEntity = mTaskEntity.getEntity();
if (mEntity != null) {
mDirPathTemp = mEntity.getDirPath();
} }
mEntity = mTaskEntity.entity;
} }
/** /**
@ -71,7 +79,6 @@ public class DownloadGroupTarget
} }
if (mEntity.getFileSize() <= 1 || mEntity.getFileSize() != fileSize) { if (mEntity.getFileSize() <= 1 || mEntity.getFileSize() != fileSize) {
mEntity.setFileSize(fileSize); mEntity.setFileSize(fileSize);
mEntity.update();
} }
return this; return this;
} }
@ -80,16 +87,165 @@ public class DownloadGroupTarget
* 如果你是使用{@link DownloadReceiver#load(DownloadGroupEntity)}进行下载操作那么你需要设置任务组的下载地址 * 如果你是使用{@link DownloadReceiver#load(DownloadGroupEntity)}进行下载操作那么你需要设置任务组的下载地址
*/ */
public DownloadGroupTarget setGroupUrl(List<String> urls) { public DownloadGroupTarget setGroupUrl(List<String> urls) {
CheckUtil.checkDownloadUrls(urls);
mUrls.clear(); mUrls.clear();
mUrls.addAll(urls); mUrls.addAll(urls);
mEntity.setGroupName(CommonUtil.getMd5Code(urls));
mEntity.update();
return this; return this;
} }
@Override public boolean isRunning() { /**
DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(mEntity.getKey()); * 设置子任务文件名该方法必须在{@link #setDirPath(String)}之后调用否则不生效
return task != null && task.isRunning(); *
* @deprecated {@link #setSubFileName(List)} 请使用该api
*/
@Deprecated public DownloadGroupTarget setSubTaskFileName(List<String> subTaskFileName) {
return setSubFileName(subTaskFileName);
}
/**
* 设置子任务文件名该方法必须在{@link #setDirPath(String)}之后调用否则不生效
*/
public DownloadGroupTarget setSubFileName(List<String> subTaskFileName) {
if (subTaskFileName == null || subTaskFileName.isEmpty()) {
ALog.e(TAG, "修改子任务的文件名失败:列表为null");
return this;
}
if (subTaskFileName.size() != mTaskEntity.getSubTaskEntities().size()) {
ALog.e(TAG, "修改子任务的文件名失败:子任务文件名列表数量和子任务的数量不匹配");
return this;
}
mSubNameTemp.clear();
mSubNameTemp.addAll(subTaskFileName);
return this;
}
@Override protected int getTargetType() {
return GROUP_HTTP;
}
@Override protected boolean checkEntity() {
if (getTargetType() == GROUP_HTTP) {
if (!checkDirPath()) {
return false;
}
if (!checkSubName()) {
return false;
}
if (!checkUrls()) {
return false;
}
mEntity.save();
mTaskEntity.save();
if (needModifyPath) {
reChangeDirPath(mDirPathTemp);
}
if (!mSubNameTemp.isEmpty()) {
updateSingleSubFileName();
}
return true;
}
return false;
}
/**
* 更新所有改动的子任务文件名
*/
private void updateSingleSubFileName() {
List<DownloadTaskEntity> entities = mTaskEntity.getSubTaskEntities();
int i = 0;
for (DownloadTaskEntity entity : entities) {
if (i < mSubNameTemp.size()) {
String newName = mSubNameTemp.get(i);
updateSingleSubFileName(entity, newName);
}
i++;
}
}
/**
* 检查urls是否合法并删除不合法的子任务
*
* @return {@code true} 合法
*/
private boolean checkUrls() {
if (mUrls.isEmpty()) {
ALog.e(TAG, "下载失败,子任务下载列表为null");
return false;
}
Set<Integer> delItem = new HashSet<>();
int i = 0;
for (String url : mUrls) {
if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "子任务url为null,即将删除该子任务。");
delItem.add(i);
continue;
} else if (!url.startsWith("http")) {
//} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
ALog.e(TAG, "子任务url【" + url + "】错误,即将删除该子任务。");
delItem.add(i);
continue;
}
int index = url.indexOf("://");
if (index == -1) {
ALog.e(TAG, "子任务url【" + url + "】不合法,即将删除该子任务。");
delItem.add(i);
continue;
}
i++;
}
for (int index : delItem) {
mUrls.remove(index);
if (mSubNameTemp != null && !mSubNameTemp.isEmpty()) {
mSubNameTemp.remove(index);
}
}
mEntity.setGroupName(CommonUtil.getMd5Code(mUrls));
return true;
}
/**
* 更新单个子任务文件名
*/
private void updateSingleSubFileName(DownloadTaskEntity taskEntity, String newName) {
DownloadEntity entity = taskEntity.getEntity();
if (!newName.equals(entity.getFileName())) {
String oldPath = mEntity.getDirPath() + "/" + entity.getFileName();
String newPath = mEntity.getDirPath() + "/" + newName;
File oldFile = new File(oldPath);
if (oldFile.exists()) {
oldFile.renameTo(new File(newPath));
}
CommonUtil.renameDownloadConfig(oldFile.getName(), newName);
entity.setDownloadPath(newPath);
taskEntity.setKey(newPath);
entity.setFileName(newName);
entity.update();
}
}
/**
* 如果用户设置了子任务文件名检查子任务文件名
*
* @return {@code true} 合法
*/
private boolean checkSubName() {
if (mSubNameTemp == null || mSubNameTemp.isEmpty()) {
return true;
}
if (mUrls.size() != mSubNameTemp.size()) {
ALog.e(TAG, "子任务文件名必须和子任务数量一致");
return false;
}
return true;
} }
} }

@ -41,7 +41,7 @@ public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity> {
mOutHandler = outHandler; mOutHandler = outHandler;
mContext = AriaManager.APP; mContext = AriaManager.APP;
mListener = new DownloadGroupListener(this, mOutHandler); mListener = new DownloadGroupListener(this, mOutHandler);
switch (taskEntity.requestType) { switch (taskEntity.getRequestType()) {
case AbsTaskEntity.D_HTTP: case AbsTaskEntity.D_HTTP:
mUtil = new DownloadGroupUtil(mListener, mTaskEntity); mUtil = new DownloadGroupUtil(mListener, mTaskEntity);
break; break;
@ -71,15 +71,17 @@ public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity> {
@Override public void stop() { @Override public void stop() {
if (!mUtil.isRunning()) { if (!mUtil.isRunning()) {
mListener.onStop(getCurrentProgress()); mListener.onStop(getCurrentProgress());
} else {
mUtil.stop();
} }
mUtil.stop();
} }
@Override public void cancel() { @Override public void cancel() {
if (!mUtil.isRunning()) { if (!mUtil.isRunning()) {
mListener.onCancel(); mListener.onCancel();
} else {
mUtil.cancel();
} }
mUtil.cancel();
} }
@Override public String getTaskName() { @Override public String getTaskName() {
@ -116,7 +118,6 @@ public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity> {
public DownloadGroupTask build() { public DownloadGroupTask build() {
DownloadGroupTask task = new DownloadGroupTask(taskEntity, outHandler); DownloadGroupTask task = new DownloadGroupTask(taskEntity, outHandler);
task.setTargetName(targetName); task.setTargetName(targetName);
taskEntity.save();
return task; return task;
} }
} }

@ -16,24 +16,48 @@
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import com.arialyy.aria.core.inf.AbsGroupTaskEntity; import com.arialyy.aria.core.inf.AbsGroupTaskEntity;
import com.arialyy.aria.orm.OneToOne; import com.arialyy.aria.orm.ActionPolicy;
import com.arialyy.aria.orm.annotation.Foreign;
import com.arialyy.aria.orm.annotation.Ignore;
import com.arialyy.aria.orm.annotation.Primary;
import java.util.List;
/** /**
* Created by AriaL on 2017/7/1. * Created by AriaL on 2017/7/1.
* 任务组的任务实体
*/ */
public class DownloadGroupTaskEntity extends AbsGroupTaskEntity<DownloadGroupEntity> { public class DownloadGroupTaskEntity extends AbsGroupTaskEntity<DownloadGroupEntity> {
@OneToOne(table = DownloadGroupEntity.class, key = "groupName") public DownloadGroupEntity entity; @Ignore private DownloadGroupEntity entity;
@Ignore private List<DownloadTaskEntity> subTaskEntities;
@Primary
@Foreign(parent = DownloadGroupEntity.class, column = "groupName",
onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
private String key;
@Override public DownloadGroupEntity getEntity() { @Override public DownloadGroupEntity getEntity() {
return entity; return entity;
} }
public void setEntity(DownloadGroupEntity entity) {
this.entity = entity;
}
public List<DownloadTaskEntity> getSubTaskEntities() {
return subTaskEntities;
}
public void setSubTaskEntities(List<DownloadTaskEntity> subTaskEntities) {
this.subTaskEntities = subTaskEntities;
}
@Override public String getKey() {
return key;
}
public void save(DownloadGroupEntity groupEntity){ public void setKey(String key) {
key = groupEntity.getKey(); this.key = key;
entity = groupEntity;
groupEntity.save();
save();
} }
} }

@ -22,13 +22,15 @@ import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.command.normal.CancelAllCmd; import com.arialyy.aria.core.command.normal.CancelAllCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory; import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.ProxyHelper; import com.arialyy.aria.core.common.ProxyHelper;
import com.arialyy.aria.core.download.wrapper.DGEWrapper;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsReceiver; import com.arialyy.aria.core.inf.AbsReceiver;
import com.arialyy.aria.core.inf.AbsTarget; import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers; import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers;
import com.arialyy.aria.core.scheduler.DownloadSchedulers; import com.arialyy.aria.core.scheduler.DownloadSchedulers;
import com.arialyy.aria.core.scheduler.ISchedulerListener;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList; import java.util.ArrayList;
@ -41,7 +43,6 @@ import java.util.Set;
*/ */
public class DownloadReceiver extends AbsReceiver { public class DownloadReceiver extends AbsReceiver {
private final String TAG = "DownloadReceiver"; private final String TAG = "DownloadReceiver";
public ISchedulerListener<DownloadTask> listener;
/** /**
* 设置最大下载速度单位kb * 设置最大下载速度单位kb
@ -49,8 +50,8 @@ public class DownloadReceiver extends AbsReceiver {
* *
* @param maxSpeed 为0表示不限速 * @param maxSpeed 为0表示不限速
*/ */
@Deprecated public void setMaxSpeed(double maxSpeed) { @Deprecated public void setMaxSpeed(int maxSpeed) {
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().setMsxSpeed(maxSpeed); AriaManager.getInstance(AriaManager.APP).getDownloadConfig().setMaxSpeed(maxSpeed);
} }
/** /**
@ -108,14 +109,25 @@ public class DownloadReceiver extends AbsReceiver {
* </pre> * </pre>
*/ */
@Deprecated public DownloadTarget load(@NonNull String url, boolean refreshInfo) { @Deprecated public DownloadTarget load(@NonNull String url, boolean refreshInfo) {
url = CheckUtil.checkUrl(url); CheckUtil.checkUrlInvalidThrow(url);
return new DownloadTarget(url, targetName, refreshInfo); return new DownloadTarget(url, targetName, refreshInfo);
} }
/** /**
* 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组 * 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组
*
* @param urls 任务组子任务下载地址列表
* @deprecated {@link #loadGroup(DownloadGroupEntity)}
*/ */
@Deprecated
public DownloadGroupTarget load(List<String> urls) { public DownloadGroupTarget load(List<String> urls) {
return loadGroup(urls);
}
/**
* 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组
*/
public DownloadGroupTarget loadGroup(List<String> urls) {
CheckUtil.checkDownloadUrls(urls); CheckUtil.checkDownloadUrls(urls);
return new DownloadGroupTarget(urls, targetName); return new DownloadGroupTarget(urls, targetName);
} }
@ -165,17 +177,29 @@ public class DownloadReceiver extends AbsReceiver {
* @param refreshInfo 是否刷新下载信息 * @param refreshInfo 是否刷新下载信息
*/ */
public FtpDownloadTarget loadFtp(@NonNull String url, boolean refreshInfo) { public FtpDownloadTarget loadFtp(@NonNull String url, boolean refreshInfo) {
url = CheckUtil.checkUrl(url); CheckUtil.checkUrlInvalidThrow(url);
return new FtpDownloadTarget(url, targetName, refreshInfo); return new FtpDownloadTarget(url, targetName, refreshInfo);
} }
/** /**
* 使用任务组实体执行任务组的实体执行任务组的下载操作 * 使用任务组实体执行任务组的实体执行任务组的下载操作后续版本会删除该api
* *
* @param groupEntity 如果加载的任务实体没有子项的下载地址 * @param groupEntity 如果加载的任务实体没有子项的下载地址
* 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址 * 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址
* @deprecated 请使用 {@link #loadGroup(DownloadGroupEntity)}
*/ */
@Deprecated
public DownloadGroupTarget load(DownloadGroupEntity groupEntity) { public DownloadGroupTarget load(DownloadGroupEntity groupEntity) {
return loadGroup(groupEntity);
}
/**
* 使用任务组实体执行任务组的实体执行任务组的下载操作
*
* @param groupEntity 如果加载的任务实体没有子项的下载地址
* 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址
*/
public DownloadGroupTarget loadGroup(DownloadGroupEntity groupEntity) {
return new DownloadGroupTarget(groupEntity, targetName); return new DownloadGroupTarget(groupEntity, targetName);
} }
@ -183,7 +207,7 @@ public class DownloadReceiver extends AbsReceiver {
* 加载ftp文件夹下载地址 * 加载ftp文件夹下载地址
*/ */
public FtpDirDownloadTarget loadFtpDir(@NonNull String dirUrl) { public FtpDirDownloadTarget loadFtpDir(@NonNull String dirUrl) {
dirUrl = CheckUtil.checkUrl(dirUrl); CheckUtil.checkUrlInvalidThrow(dirUrl);
return new FtpDirDownloadTarget(dirUrl, targetName); return new FtpDirDownloadTarget(dirUrl, targetName);
} }
@ -207,6 +231,7 @@ public class DownloadReceiver extends AbsReceiver {
/** /**
* 取消注册如果是Activity或fragmentAria会界面销毁时自动调用该方法 * 取消注册如果是Activity或fragmentAria会界面销毁时自动调用该方法
* 如果在activity中一定要调用该方法那么请在onDestroy()中调用
* 如果是Dialog或popupwindow需要你在撤销界面时调用该方法 * 如果是Dialog或popupwindow需要你在撤销界面时调用该方法
*/ */
@Override public void unRegister() { @Override public void unRegister() {
@ -232,44 +257,59 @@ public class DownloadReceiver extends AbsReceiver {
@Override public void destroy() { @Override public void destroy() {
targetName = null; targetName = null;
listener = null;
} }
/** /**
* 通过下载链接获取下载实体 * 通过下载链接获取下载实体
*
* @return 如果url错误或查找不到数据则返回null
*/ */
public DownloadEntity getDownloadEntity(String downloadUrl) { public DownloadEntity getDownloadEntity(String downloadUrl) {
downloadUrl = CheckUtil.checkUrl(downloadUrl); if (CheckUtil.checkUrl(downloadUrl)) {
return null;
}
return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl); return DbEntity.findFirst(DownloadEntity.class, "url=? and isGroupChild='false'", downloadUrl);
} }
/** /**
* 通过下载链接获取保存在数据库的下载任务实体 * 通过下载地址和文件保存路径获取下载任务实体
*
* @param downloadUrl 下载地址
* @return 如果url错误或查找不到数据则返回null
*/ */
public DownloadTaskEntity getDownloadTask(String downloadUrl) { public DownloadTaskEntity getDownloadTask(String downloadUrl) {
downloadUrl = CheckUtil.checkUrl(downloadUrl); if (CheckUtil.checkUrl(downloadUrl)) {
DownloadEntity entity = getDownloadEntity(downloadUrl); return null;
if (entity == null || TextUtils.isEmpty(entity.getDownloadPath())) return null; }
return DbEntity.findFirst(DownloadTaskEntity.class, "key=? and isGroupTask='false'", return TEManager.getInstance().getTEntity(DownloadTaskEntity.class, downloadUrl);
entity.getDownloadPath());
} }
/** /**
* 通过下载链接获取保存在数据库的下载任务组实体 * 通过下载链接获取保存在数据库的下载任务组实体
*
* @param urls 任务组子任务下载地址列表
* @return 返回对应的任务组实体如果查找不到对应的数据或子任务列表为null返回null
*/ */
public DownloadGroupTaskEntity getDownloadGroupTask(List<String> urls) { public DownloadGroupTaskEntity getGroupTask(List<String> urls) {
CheckUtil.checkDownloadUrls(urls); if (urls == null || urls.isEmpty()) {
String hashCode = CommonUtil.getMd5Code(urls); ALog.e(TAG, "获取任务组实体失败:任务组子任务下载地址列表为null");
return DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", hashCode); return null;
}
return TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, urls);
} }
/** /**
* 通过任务组key获取任务组实体 * 获取FTP文件夹下载任务实体
* 如果是httpkey为所有子任务下载地址拼接后取md5 *
* 如果是ftpkey为ftp服务器的文件夹路径 * @param dirUrl FTP文件夹本地下载路径
* @return 返回对应的任务组实体如果查找不到对应的数据或路径为null返回null
*/ */
public DownloadGroupTaskEntity getDownloadGroupTask(String key) { public DownloadGroupTaskEntity getFtpDirTask(String dirUrl) {
return DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", key); if (TextUtils.isEmpty(dirUrl)) {
ALog.e(TAG, "获取FTP文件夹实体失败:下载路径为null");
return null;
}
return TEManager.getInstance().getFDTEntity(DownloadGroupTaskEntity.class, dirUrl);
} }
/** /**
@ -307,15 +347,25 @@ public class DownloadReceiver extends AbsReceiver {
/** /**
* 获取任务组列表 * 获取任务组列表
*
* @return 如果没有任务组列表则返回null
*/ */
public List<DownloadGroupEntity> getGroupTaskList() { public List<DownloadGroupEntity> getGroupTaskList() {
return DownloadEntity.findAllData(DownloadGroupEntity.class); List<DGEWrapper> wrappers = DbEntity.findRelationData(DGEWrapper.class);
if (wrappers == null || wrappers.isEmpty()) {
return null;
}
List<DownloadGroupEntity> entities = new ArrayList<>();
for (DGEWrapper wrapper : wrappers) {
entities.add(wrapper.groupEntity);
}
return entities;
} }
/** /**
* 获取普通任务和任务组的任务列表 * 获取普通任务和任务组的任务列表
*/ */
public List<AbsEntity> getTotleTaskList() { public List<AbsEntity> getTotalTaskList() {
List<AbsEntity> list = new ArrayList<>(); List<AbsEntity> list = new ArrayList<>();
List<DownloadEntity> simpleTask = getTaskList(); List<DownloadEntity> simpleTask = getTaskList();
List<DownloadGroupEntity> groupTask = getGroupTaskList(); List<DownloadGroupEntity> groupTask = getGroupTaskList();

@ -16,35 +16,25 @@
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils; import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.inf.AbsDownloadTarget; import com.arialyy.aria.core.delegate.HttpHeaderDelegate;
import com.arialyy.aria.core.manager.TEManager; import com.arialyy.aria.core.inf.IHttpHeaderTarget;
import com.arialyy.aria.core.queue.DownloadTaskQueue; import java.util.Map;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
/** /**
* Created by lyy on 2016/12/5. * Created by lyy on 2016/12/5.
* https://github.com/AriaLyy/Aria * https://github.com/AriaLyy/Aria
*/ */
public class DownloadTarget public class DownloadTarget extends BaseNormalTarget<DownloadTarget>
extends AbsDownloadTarget<DownloadTarget, DownloadEntity, DownloadTaskEntity> { implements IHttpHeaderTarget<DownloadTarget> {
protected String url; private HttpHeaderDelegate<DownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate;
DownloadTarget(DownloadEntity entity, String targetName) { DownloadTarget(DownloadEntity entity, String targetName) {
this(entity, targetName, false); this(entity, targetName, false);
} }
DownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) { DownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) {
this.url = entity.getUrl(); this(entity.getUrl(), targetName, refreshInfo);
mTargetName = targetName;
mTaskEntity = TEManager.getInstance().getTEntity(DownloadTaskEntity.class, url);
if (mTaskEntity == null) {
mTaskEntity = TEManager.getInstance().createTEntity(DownloadTaskEntity.class, entity);
}
mEntity = mTaskEntity.entity;
mTaskEntity.refreshInfo = refreshInfo;
} }
DownloadTarget(String url, String targetName) { DownloadTarget(String url, String targetName) {
@ -52,14 +42,8 @@ public class DownloadTarget
} }
DownloadTarget(String url, String targetName, boolean refreshInfo) { DownloadTarget(String url, String targetName, boolean refreshInfo) {
this.url = url; initTarget(url, targetName, refreshInfo);
mTargetName = targetName; mDelegate = new HttpHeaderDelegate<>(this, mTaskEntity);
mTaskEntity = TEManager.getInstance().getTEntity(DownloadTaskEntity.class, url);
if (mTaskEntity == null) {
mTaskEntity = TEManager.getInstance().createTEntity(DownloadTaskEntity.class, url);
}
mEntity = mTaskEntity.entity;
mTaskEntity.refreshInfo = refreshInfo;
} }
/** /**
@ -69,31 +53,20 @@ public class DownloadTarget
* *
* @param use {@code true} 使用 * @param use {@code true} 使用
*/ */
@Deprecated public DownloadTarget useServerFileName(boolean use) { public DownloadTarget useServerFileName(boolean use) {
mTaskEntity.useServerFileName = use; mTaskEntity.setUseServerFileName(use);
return this; return this;
} }
/** /**
* 将任务设置为最高优先级任务最高优先级任务有以下特点 * 设置文件存储路径
* 1在下载队列中有且只有一个最高优先级任务 * 该api后续版本会删除
* 2最高优先级任务会一直存在直到用户手动暂停或任务完成
* 3任务调度器不会暂停最高优先级任务
* 4用户手动暂停或任务完成后第二次重新执行该任务该命令将失效
* 5如果下载队列中已经满了则会停止队尾的任务当高优先级任务完成后该队尾任务将自动执行
* 6把任务设置为最高优先级任务后将自动执行任务不需要重新调用start()启动任务
*/
@Override public void setHighestPriority() {
super.setHighestPriority();
}
/**
* 下载任务是否存在
* *
* @return {@code true}任务存在 * @param downloadPath 文件保存路径
* @deprecated {@link #setFilePath(String)} 请使用这个api
*/ */
@Override public boolean taskExists() { @Deprecated public DownloadTarget setDownloadPath(@NonNull String downloadPath) {
return DownloadTaskQueue.getInstance().getTask(mEntity.getUrl()) != null; return setFilePath(downloadPath);
} }
/** /**
@ -101,38 +74,13 @@ public class DownloadTarget
* 原文件路径 /mnt/sdcard/test.zip * 原文件路径 /mnt/sdcard/test.zip
* 如果需要将test.zip改为game.zip只需要重新设置文件路径为/mnt/sdcard/game.zip * 如果需要将test.zip改为game.zip只需要重新设置文件路径为/mnt/sdcard/game.zip
* *
* @param downloadPath 路径必须为文件路径不能为文件夹路径 * @param filePath 路径必须为文件路径不能为文件夹路径
*/ */
public DownloadTarget setDownloadPath(@NonNull String downloadPath) { public DownloadTarget setFilePath(@NonNull String filePath) {
if (TextUtils.isEmpty(downloadPath)) { mTempFilePath = filePath;
throw new IllegalArgumentException("文件保持路径不能为null");
}
File file = new File(downloadPath);
if (file.isDirectory()) {
throw new IllegalArgumentException("保存路径不能为文件夹,路径需要是完整的文件路径,如:/mnt/sdcard/game.zip");
}
if (!downloadPath.equals(mEntity.getDownloadPath())) {
if (!mTaskEntity.refreshInfo && DbEntity.checkDataExist(DownloadEntity.class,
"downloadPath=?", downloadPath)) {
throw new IllegalArgumentException("保存路径【" + downloadPath + "】已经被其它任务占用,请设置其它保存路径");
}
File oldFile = new File(mEntity.getDownloadPath());
File newFile = new File(downloadPath);
if (TextUtils.isEmpty(mEntity.getDownloadPath()) || oldFile.renameTo(newFile)) {
mEntity.setDownloadPath(downloadPath);
mEntity.setFileName(newFile.getName());
mTaskEntity.key = downloadPath;
mTaskEntity.update();
CommonUtil.renameDownloadConfig(oldFile.getName(), newFile.getName());
}
}
return this; return this;
} }
public DownloadEntity getDownloadEntity() {
return mEntity;
}
/** /**
* 从header中获取文件描述信息 * 从header中获取文件描述信息
*/ */
@ -140,17 +88,19 @@ public class DownloadTarget
return mEntity.getDisposition(); return mEntity.getDisposition();
} }
/** @Override protected int getTargetType() {
* 是否在下载 return HTTP;
* }
* @deprecated {@link #isRunning()}
*/ @Override public DownloadTarget addHeader(@NonNull String key, @NonNull String value) {
public boolean isDownloading() { return mDelegate.addHeader(key, value);
return isRunning(); }
@Override public DownloadTarget addHeaders(Map<String, String> headers) {
return mDelegate.addHeaders(headers);
} }
@Override public boolean isRunning() { @Override public DownloadTarget setRequestMode(RequestEnum requestEnum) {
DownloadTask task = DownloadTaskQueue.getInstance().getTask(mEntity.getKey()); return mDelegate.setRequestMode(requestEnum);
return task != null && task.isRunning();
} }
} }

@ -18,7 +18,6 @@ package com.arialyy.aria.core.download;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.download.downloader.SimpleDownloadUtil; import com.arialyy.aria.core.download.downloader.SimpleDownloadUtil;
@ -78,16 +77,12 @@ public class DownloadTask extends AbsNormalTask<DownloadTaskEntity> {
} }
/** /**
* 任务下载状态 * 是否真正下载
* *
* @see DownloadTask#isRunning() * @return {@code true} 真正下载
*/ */
@Deprecated public boolean isDownloading() {
return mUtil.isRunning();
}
@Override public boolean isRunning() { @Override public boolean isRunning() {
return isDownloading(); return mUtil.isRunning();
} }
public DownloadEntity getDownloadEntity() { public DownloadEntity getDownloadEntity() {

@ -16,31 +16,51 @@
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import com.arialyy.aria.core.inf.AbsNormalTaskEntity; import com.arialyy.aria.core.inf.AbsNormalTaskEntity;
import com.arialyy.aria.orm.NoNull; import com.arialyy.aria.orm.ActionPolicy;
import com.arialyy.aria.orm.OneToOne; 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;
/** /**
* Created by lyy on 2017/1/23. * Created by lyy on 2017/1/23.
* 下载任务实体 * 下载任务实体和下载实体为一对一关系下载实体删除任务实体自动删除
*/ */
public class DownloadTaskEntity extends AbsNormalTaskEntity<DownloadEntity> { public class DownloadTaskEntity extends AbsNormalTaskEntity<DownloadEntity> {
@OneToOne(table = DownloadEntity.class, key = "downloadPath") public DownloadEntity entity; @Ignore private DownloadEntity entity;
/** /**
* 任务的url * 任务的url
*/ */
@NoNull public String url = ""; @NoNull private String url;
/** /**
* 所属的任务组组名如果不属于任务组则为null * 所属的任务组组名如果不属于任务组则为null
*/ */
public String groupName = ""; @Foreign(parent = DownloadGroupTaskEntity.class, column = "key",
onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
private String groupName;
/**
* 是否是chunk模式
*/
private boolean isChunked = false;
/** /**
* 该任务是否属于任务组 * 该任务是否属于任务组
*/ */
public boolean isGroupTask = false; private boolean isGroupTask = false;
/**
* Task实体对应的key
*/
@Primary
@Foreign(parent = DownloadEntity.class, column = "downloadPath",
onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE)
private String key;
public DownloadTaskEntity() { public DownloadTaskEntity() {
} }
@ -49,13 +69,47 @@ public class DownloadTaskEntity extends AbsNormalTaskEntity<DownloadEntity> {
return entity; return entity;
} }
public void save(DownloadEntity entity) { @Override public String getKey() {
return key;
}
public String getUrl() {
return url;
}
public String getGroupName() {
return groupName;
}
public boolean isChunked() {
return isChunked;
}
public boolean isGroupTask() {
return isGroupTask;
}
public void setEntity(DownloadEntity entity) {
this.entity = entity; this.entity = entity;
if (entity != null) { }
url = entity.getUrl();
key = entity.getDownloadPath(); public void setUrl(String url) {
entity.save(); this.url = url;
} }
save();
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public void setChunked(boolean chunked) {
isChunked = chunked;
}
public void setGroupTask(boolean groupTask) {
isGroupTask = groupTask;
}
public void setKey(String key) {
this.key = key;
} }
} }

@ -16,18 +16,19 @@
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.delegate.FtpDelegate;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.core.manager.TEManager; import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.ALog;
/** /**
* Created by Aria.Lao on 2017/7/26. * Created by Aria.Lao on 2017/7/26.
* ftp文件夹下载 * ftp文件夹下载
*/ */
public class FtpDirDownloadTarget public class FtpDirDownloadTarget extends BaseGroupTarget<FtpDirDownloadTarget>
extends BaseGroupTarget<FtpDirDownloadTarget, DownloadGroupTaskEntity> { implements IFtpTarget<FtpDirDownloadTarget> {
private final String TAG = "FtpDirDownloadTarget"; private FtpDelegate<FtpDirDownloadTarget, DownloadGroupEntity, DownloadGroupTaskEntity> mDelegate;
FtpDirDownloadTarget(String url, String targetName) { FtpDirDownloadTarget(String url, String targetName) {
mTargetName = targetName; mTargetName = targetName;
@ -36,57 +37,68 @@ public class FtpDirDownloadTarget
private void init(String key) { private void init(String key) {
mGroupName = key; mGroupName = key;
mTaskEntity = TEManager.getInstance().getTEntity(DownloadGroupTaskEntity.class, key); mTaskEntity = TEManager.getInstance().getFDTEntity(DownloadGroupTaskEntity.class, key);
if (mTaskEntity == null) { mTaskEntity.setRequestType(AbsTaskEntity.D_FTP_DIR);
mTaskEntity = TEManager.getInstance().createTEntity(DownloadGroupTaskEntity.class, key); mEntity = mTaskEntity.getEntity();
if (mEntity != null) {
mDirPathTemp = mEntity.getDirPath();
} }
mTaskEntity.requestType = AbsTaskEntity.D_FTP_DIR; mDelegate = new FtpDelegate<>(this, mTaskEntity);
mEntity = mTaskEntity.entity;
} }
/** @Override protected int getTargetType() {
* 设置字符编码 return GROUP_FTP_DIR;
*/
public FtpDirDownloadTarget charSet(String charSet) {
if (TextUtils.isEmpty(charSet)) return this;
mTaskEntity.charSet = charSet;
return this;
} }
/** @Override protected boolean checkEntity() {
* ftp 用户登录信息 boolean b = getTargetType() == GROUP_FTP_DIR && checkDirPath() && checkUrl();
* if (b) {
* @param userName ftp用户名 mEntity.save();
* @param password ftp用户密码 mTaskEntity.save();
*/ if (mTaskEntity.getSubTaskEntities() != null) {
public FtpDirDownloadTarget login(String userName, String password) { //初始化子项的登录信息
return login(userName, password, null); for (DownloadTaskEntity entity : mTaskEntity.getSubTaskEntities()) {
entity.getUrlEntity().needLogin = mTaskEntity.getUrlEntity().needLogin;
entity.getUrlEntity().account = mTaskEntity.getUrlEntity().account;
entity.getUrlEntity().user = mTaskEntity.getUrlEntity().user;
entity.getUrlEntity().password = mTaskEntity.getUrlEntity().password;
}
}
}
return b;
} }
/** /**
* ftp 用户登录信息 * 检查普通任务的下载地址
* *
* @param userName ftp用户名 * @return {@code true}地址合法
* @param password ftp用户密码
* @param account ftp账号
*/ */
public FtpDirDownloadTarget login(String userName, String password, String account) { private boolean checkUrl() {
if (TextUtils.isEmpty(userName)) { final String url = mGroupName;
ALog.e(TAG, "用户名不能为null"); if (TextUtils.isEmpty(url)) {
return this; ALog.e(TAG, "下载失败,url为null");
} else if (TextUtils.isEmpty(password)) { return false;
ALog.e(TAG, "密码不能为null"); } else if (!url.startsWith("ftp")) {
return this; ALog.e(TAG, "下载失败,url【" + url + "】错误");
return false;
} }
mTaskEntity.urlEntity.needLogin = true; int index = url.indexOf("://");
mTaskEntity.urlEntity.user = userName; if (index == -1) {
mTaskEntity.urlEntity.password = password; ALog.e(TAG, "下载失败,url【" + url + "】不合法");
mTaskEntity.urlEntity.account = account; return false;
return this; }
return true;
}
@Override public FtpDirDownloadTarget charSet(String charSet) {
return mDelegate.charSet(charSet);
}
@Override public FtpDirDownloadTarget login(String userName, String password) {
return mDelegate.login(userName, password);
} }
@Override public boolean isRunning() { @Override public FtpDirDownloadTarget login(String userName, String password, String account) {
DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(mEntity.getKey()); return mDelegate.login(userName, password, account);
return task != null && task.isRunning();
} }
} }

@ -16,22 +16,21 @@
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils; import com.arialyy.aria.core.delegate.FtpDelegate;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.util.ALog; import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.io.File;
/** /**
* Created by lyy on 2016/12/5. * Created by lyy on 2016/12/5.
* https://github.com/AriaLyy/Aria * https://github.com/AriaLyy/Aria
*/ */
public class FtpDownloadTarget extends DownloadTarget { public class FtpDownloadTarget extends BaseNormalTarget<FtpDownloadTarget>
private final String TAG = "FtpDownloadTarget"; implements IFtpTarget<FtpDownloadTarget> {
private FtpDelegate<FtpDownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate;
FtpDownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) { FtpDownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) {
super(entity, targetName, refreshInfo); this(entity.getUrl(), targetName, refreshInfo);
init(refreshInfo);
} }
FtpDownloadTarget(String url, String targetName) { FtpDownloadTarget(String url, String targetName) {
@ -39,16 +38,29 @@ public class FtpDownloadTarget extends DownloadTarget {
} }
FtpDownloadTarget(String url, String targetName, boolean refreshInfo) { FtpDownloadTarget(String url, String targetName, boolean refreshInfo) {
super(url, targetName); initTarget(url, targetName, refreshInfo);
init(refreshInfo); init(refreshInfo);
} }
private void init(boolean refreshInfo) { private void init(boolean refreshInfo) {
int lastIndex = url.lastIndexOf("/"); int lastIndex = url.lastIndexOf("/");
mEntity.setFileName(url.substring(lastIndex + 1, url.length())); mEntity.setFileName(url.substring(lastIndex + 1, url.length()));
mTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(url); mTaskEntity.setUrlEntity(CommonUtil.getFtpUrlInfo(url));
mTaskEntity.refreshInfo = refreshInfo; mTaskEntity.setRefreshInfo(refreshInfo);
mTaskEntity.requestType = AbsTaskEntity.D_FTP; mTaskEntity.setRequestType(AbsTaskEntity.D_FTP);
mDelegate = new FtpDelegate<>(this, mTaskEntity);
}
/**
* 设置文件保存文件夹路径
*
* @param filePath 文件保存路径
* @deprecated {@link #setFilePath(String)} 请使用这个api
*/
@Deprecated
public FtpDownloadTarget setDownloadPath(@NonNull String filePath) {
return setFilePath(filePath);
} }
/** /**
@ -57,69 +69,26 @@ public class FtpDownloadTarget extends DownloadTarget {
* 1如果保存路径是该文件的保存路径/mnt/sdcard/file.zip则使用路径中的文件名file.zip * 1如果保存路径是该文件的保存路径/mnt/sdcard/file.zip则使用路径中的文件名file.zip
* 2如果保存路径是文件夹路径/mnt/sdcard/则使用FTP服务器该文件的文件名 * 2如果保存路径是文件夹路径/mnt/sdcard/则使用FTP服务器该文件的文件名
* *
* @param downloadPath 路径必须为文件路径不能为文件夹路径 * @param filePath 路径必须为文件路径不能为文件夹路径
*/ */
@Override public FtpDownloadTarget setDownloadPath(@NonNull String downloadPath) { public FtpDownloadTarget setFilePath(@NonNull String filePath) {
if (TextUtils.isEmpty(downloadPath)) { mTempFilePath = filePath;
throw new IllegalArgumentException("文件保持路径不能为null");
}
File file = new File(downloadPath);
if (file.isDirectory()) {
downloadPath += mEntity.getFileName();
}
if (!downloadPath.equals(mEntity.getDownloadPath())) {
File oldFile = new File(mEntity.getDownloadPath());
File newFile = new File(downloadPath);
if (TextUtils.isEmpty(mEntity.getDownloadPath()) || oldFile.renameTo(newFile)) {
mEntity.setDownloadPath(downloadPath);
mEntity.setFileName(newFile.getName());
mTaskEntity.key = downloadPath;
mEntity.update();
mTaskEntity.update();
CommonUtil.renameDownloadConfig(oldFile.getName(), newFile.getName());
}
}
return this; return this;
} }
/** @Override protected int getTargetType() {
* 设置字符编码 return FTP;
*/
public FtpDownloadTarget charSet(String charSet) {
if (TextUtils.isEmpty(charSet)) return this;
mTaskEntity.charSet = charSet;
return this;
} }
/** @Override public FtpDownloadTarget charSet(String charSet) {
* ftp 用户登录信息 return mDelegate.charSet(charSet);
*
* @param userName ftp用户名
* @param password ftp用户密码
*/
public FtpDownloadTarget login(String userName, String password) {
return login(userName, password, null);
} }
/** @Override public FtpDownloadTarget login(String userName, String password) {
* ftp 用户登录信息 return mDelegate.login(userName, password);
* }
* @param userName ftp用户名
* @param password ftp用户密码 @Override public FtpDownloadTarget login(String userName, String password, String account) {
* @param account ftp账号 return mDelegate.login(userName, password, account);
*/
public FtpDownloadTarget login(String userName, String password, String account) {
if (TextUtils.isEmpty(userName)) {
ALog.e(TAG, "用户名不能为null");
return this;
} else if (TextUtils.isEmpty(password)) {
ALog.e(TAG, "密码不能为null");
return this;
}
mTaskEntity.urlEntity.needLogin = true;
mTaskEntity.urlEntity.user = userName;
mTaskEntity.urlEntity.password = password;
mTaskEntity.urlEntity.account = account;
return this;
} }
} }

@ -16,20 +16,17 @@
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.AriaManager;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; 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.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.orm.DbEntity;
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.NetUtils; import com.arialyy.aria.util.NetUtils;
import java.io.File; import java.io.File;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Timer; import java.util.Timer;
@ -73,65 +70,31 @@ public abstract class AbsGroupUtil implements IUtil {
Map<String, DownloadTaskEntity> mFailMap = new HashMap<>(); Map<String, DownloadTaskEntity> mFailMap = new HashMap<>();
/** /**
* 下载器映射表key为下载地址 * 该任务组对应的所有任务
*/ */
private Map<String, Downloader> mDownloaderMap = new HashMap<>(); private Map<String, DownloadTaskEntity> mTasksMap = new HashMap<>();
/** /**
* 该任务组对应的所有任务 * 下载器映射表key为下载地址
*/ */
private Map<String, DownloadTaskEntity> mTasksMap = new HashMap<>(); private Map<String, Downloader> mDownloaderMap = new HashMap<>();
/** /**
* 是否需要读取文件长度{@code true}需要 * 是否需要读取文件长度{@code true}需要
*/ */
boolean isNeedLoadFileSize = true; boolean isNeedLoadFileSize = true;
//已经完成的任务数 //已经完成的任务数
private int mCompleteNum = 0; int mCompleteNum = 0;
//失败的任务数
private int mFailNum = 0;
//停止的任务数 //停止的任务数
private int mStopNum = 0; private int mStopNum = 0;
//实际的下载任务数
int mActualTaskNum = 0;
//初始化完成的任务数
int mInitNum = 0;
// 初始化失败的任务数
int mInitFailNum = 0;
//任务组大小 //任务组大小
int mGroupSize = 0; int mGroupSize = 0;
long mUpdateInterval = 1000; private long mUpdateInterval = 1000;
AbsGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity groupEntity) { AbsGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity groupEntity) {
mListener = listener; mListener = listener;
mGTEntity = groupEntity; mGTEntity = groupEntity;
mExePool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); mExePool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
List<DownloadTaskEntity> tasks =
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mGTEntity.key);
if (tasks != null && !tasks.isEmpty()) {
for (DownloadTaskEntity te : tasks) {
te.removeFile = mGTEntity.removeFile;
if (te.getEntity() == null) continue;
mTasksMap.put(te.getEntity().getUrl(), te);
}
}
mGroupSize = mGTEntity.entity.getSubTask().size();
mTotalLen = groupEntity.getEntity().getFileSize();
isNeedLoadFileSize = mTotalLen <= 1;
for (DownloadEntity entity : mGTEntity.entity.getSubTask()) {
File file = new File(entity.getDownloadPath());
if (entity.getState() == IEntity.STATE_COMPLETE && file.exists()) {
mCompleteNum++;
mCurrentLocation += entity.getFileSize();
} else {
mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
mCurrentLocation += file.exists() ? entity.getCurrentProgress() : 0;
mActualTaskNum++;
}
if (isNeedLoadFileSize) {
mTotalLen += entity.getFileSize();
}
}
updateFileSize();
mUpdateInterval = mUpdateInterval =
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getUpdateInterval(); AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getUpdateInterval();
} }
@ -190,11 +153,9 @@ public abstract class AbsGroupUtil implements IUtil {
* @param url 子任务下载地址 * @param url 子任务下载地址
*/ */
public void cancelSubTask(String url) { public void cancelSubTask(String url) {
List<String> urls = mGTEntity.entity.getUrls(); Set<String> urls = mTasksMap.keySet();
if (urls != null && !urls.isEmpty() && urls.contains(url)) { if (!urls.isEmpty() && urls.contains(url)) {
urls.remove(url); DownloadTaskEntity det = mTasksMap.get(url);
DownloadTaskEntity det =
DbEntity.findFirst(DownloadTaskEntity.class, "url=? and isGroupTask='true'", url);
if (det != null) { if (det != null) {
mTotalLen -= det.getEntity().getFileSize(); mTotalLen -= det.getEntity().getFileSize();
mGroupSize--; mGroupSize--;
@ -260,7 +221,6 @@ public abstract class AbsGroupUtil implements IUtil {
@Override public void cancel() { @Override public void cancel() {
closeTimer(false); closeTimer(false);
mListener.onCancel();
onCancel(); onCancel();
if (!mExePool.isShutdown()) { if (!mExePool.isShutdown()) {
mExePool.shutdown(); mExePool.shutdown();
@ -273,38 +233,15 @@ public abstract class AbsGroupUtil implements IUtil {
dt.cancel(); dt.cancel();
} }
} }
delDownloadInfo(); clearState();
mGTEntity.deleteData(); CommonUtil.delDownloadGroupTaskConfig(mGTEntity.isRemoveFile(), mGTEntity.getEntity());
mListener.onCancel();
} }
public void onCancel() { public void onCancel() {
} }
/**
* 删除所有子任务的下载信息
*/
private void delDownloadInfo() {
List<DownloadTaskEntity> tasks =
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mGTEntity.key);
if (tasks != null && !tasks.isEmpty()) {
for (DownloadTaskEntity taskEntity : tasks) {
CommonUtil.delDownloadTaskConfig(mGTEntity.removeFile, taskEntity);
}
}
File dir = new File(mGTEntity.getEntity().getDirPath());
if (mGTEntity.removeFile) {
if (dir.exists()) {
dir.delete();
}
} else {
if (!mGTEntity.getEntity().isComplete()) {
dir.delete();
}
}
}
@Override public void stop() { @Override public void stop() {
closeTimer(false); closeTimer(false);
onStop(); onStop();
@ -325,10 +262,35 @@ public abstract class AbsGroupUtil implements IUtil {
} }
/**
* 预处理操作由于属性的不同http任务组在构造函数中就可以完成了
* 而FTP文件夹的需要获取完成所有子任务信息才算预处理完成
*/
protected void onPre() {
mListener.onPre();
mGroupSize = mGTEntity.getSubTaskEntities().size();
mTotalLen = mGTEntity.getEntity().getFileSize();
isNeedLoadFileSize = mTotalLen <= 1;
for (DownloadTaskEntity te : mGTEntity.getSubTaskEntities()) {
File file = new File(te.getKey());
if (te.getState() == IEntity.STATE_COMPLETE && file.exists()) {
mCompleteNum++;
mCurrentLocation += te.getEntity().getFileSize();
} else {
mExeMap.put(te.getUrl(), te);
mCurrentLocation += file.exists() ? te.getEntity().getCurrentProgress() : 0;
}
if (isNeedLoadFileSize) {
mTotalLen += te.getEntity().getFileSize();
}
mTasksMap.put(te.getUrl(), te);
}
updateFileSize();
}
@Override public void start() { @Override public void start() {
isRunning = true; isRunning = true;
mFailNum = 0; clearState();
mListener.onPre();
onStart(); onStart();
} }
@ -345,6 +307,11 @@ public abstract class AbsGroupUtil implements IUtil {
} }
private void clearState(){
mDownloaderMap.clear();
mFailMap.clear();
}
private void closeTimer(boolean isRunning) { private void closeTimer(boolean isRunning) {
this.isRunning = isRunning; this.isRunning = isRunning;
if (mTimer != null) { if (mTimer != null) {
@ -389,7 +356,7 @@ public abstract class AbsGroupUtil implements IUtil {
* *
* @param start 是否启动下载 * @param start 是否启动下载
*/ */
Downloader createChildDownload(DownloadTaskEntity taskEntity, boolean start) { private Downloader createChildDownload(DownloadTaskEntity taskEntity, boolean start) {
ChildDownloadListener listener = new ChildDownloadListener(taskEntity); ChildDownloadListener listener = new ChildDownloadListener(taskEntity);
Downloader dt = new Downloader(listener, taskEntity); Downloader dt = new Downloader(listener, taskEntity);
mDownloaderMap.put(taskEntity.getEntity().getUrl(), dt); mDownloaderMap.put(taskEntity.getEntity().getUrl(), dt);
@ -400,44 +367,6 @@ public abstract class AbsGroupUtil implements IUtil {
return dt; return dt;
} }
/**
* 创建子任务下载信息
*/
DownloadTaskEntity createChildDownloadTask(DownloadEntity entity) {
DownloadTaskEntity taskEntity = mTasksMap.get(entity.getUrl());
if (taskEntity != null) {
taskEntity.entity = entity;
if (getTaskType() == FTP_DIR) {
taskEntity.urlEntity = createFtpUrlEntity(entity);
}
mTasksMap.put(entity.getUrl(), taskEntity);
return taskEntity;
}
taskEntity = new DownloadTaskEntity();
taskEntity.entity = entity;
taskEntity.headers = mGTEntity.headers;
taskEntity.requestEnum = mGTEntity.requestEnum;
taskEntity.redirectUrlKey = mGTEntity.redirectUrlKey;
taskEntity.removeFile = mGTEntity.removeFile;
taskEntity.groupName = mGTEntity.key;
taskEntity.isGroupTask = true;
taskEntity.requestType = mGTEntity.requestType;
taskEntity.key = entity.getDownloadPath();
if (getTaskType() == FTP_DIR) {
taskEntity.urlEntity = createFtpUrlEntity(entity);
}
taskEntity.save();
mTasksMap.put(entity.getUrl(), taskEntity);
return taskEntity;
}
private FtpUrlEntity createFtpUrlEntity(DownloadEntity entity) {
FtpUrlEntity urlEntity = mGTEntity.urlEntity.clone();
urlEntity.url = entity.getUrl();
urlEntity.remotePath = CommonUtil.getRemotePath(entity.getUrl());
return urlEntity;
}
/** /**
* 子任务事件监听 * 子任务事件监听
*/ */
@ -498,7 +427,7 @@ public abstract class AbsGroupUtil implements IUtil {
mListener.onSubStop(subEntity); mListener.onSubStop(subEntity);
synchronized (AbsGroupUtil.class) { synchronized (AbsGroupUtil.class) {
mStopNum++; mStopNum++;
if (mStopNum + mCompleteNum + mInitFailNum + mFailNum >= mGroupSize) { if (mStopNum + mCompleteNum + mFailMap.size() == mGroupSize) {
closeTimer(false); closeTimer(false);
mListener.onStop(mCurrentLocation); mListener.onStop(mCurrentLocation);
} }
@ -515,13 +444,13 @@ public abstract class AbsGroupUtil implements IUtil {
saveData(IEntity.STATE_COMPLETE, subEntity.getFileSize()); saveData(IEntity.STATE_COMPLETE, subEntity.getFileSize());
handleSpeed(0); handleSpeed(0);
mListener.onSubComplete(subEntity); mListener.onSubComplete(subEntity);
synchronized (AbsGroupUtil.class) { synchronized (ChildDownloadListener.class) {
mCompleteNum++; mCompleteNum++;
//如果子任务完成的数量和总任务数一致,表示任务组任务已经完成 //如果子任务完成的数量和总任务数一致,表示任务组任务已经完成
if (mCompleteNum >= mGroupSize) { if (mCompleteNum >= mGroupSize) {
closeTimer(false); closeTimer(false);
mListener.onComplete(); mListener.onComplete();
} else if (mStopNum + mCompleteNum + mInitFailNum + mFailNum >= mGroupSize) { } else if (mFailMap.size() > 0 && mStopNum + mCompleteNum + mFailMap.size() >= mGroupSize) {
//如果子任务完成数量加上失败的数量和总任务数一致,则任务组停止下载 //如果子任务完成数量加上失败的数量和总任务数一致,则任务组停止下载
closeTimer(false); closeTimer(false);
mListener.onStop(mCurrentLocation); mListener.onStop(mCurrentLocation);
@ -537,20 +466,23 @@ public abstract class AbsGroupUtil implements IUtil {
} }
/** /**
* 失败后重试下载如果失败次数超过5次不再重试 * 重试下载
*/ */
private void reTry(boolean needRetry) { private void reTry(boolean needRetry) {
synchronized (AriaManager.LOCK) { synchronized (ChildDownloadListener.class) {
if (subEntity.getFailNum() < 5 && isRunning && needRetry && NetUtils.isConnected( if (subEntity.getFailNum() < 5 && needRetry && NetUtils.isConnected(AriaManager.APP)) {
AriaManager.APP)) {
reStartTask(); reStartTask();
} else { } else {
mFailNum++; mFailMap.put(subTaskEntity.getUrl(), subTaskEntity);
mListener.onSubFail(subEntity); mListener.onSubFail(subEntity);
//如果失败的任务数大于实际的下载任务数,任务组停止下载 //如果失败的任务数大于实际的下载任务数,任务组停止下载
if (mFailNum >= mActualTaskNum) { if (mFailMap.size() >= mExeMap.size()) {
closeTimer(false); closeTimer(false);
mListener.onStop(mCurrentLocation); if (mFailMap.size() == mGroupSize) { //所有任务都失败了,则认为该任务组已经失败
mListener.onFail(true);
} else {
mListener.onStop(mCurrentLocation);
}
} }
} }
} }
@ -574,11 +506,11 @@ public abstract class AbsGroupUtil implements IUtil {
} }
private void saveData(int state, long location) { private void saveData(int state, long location) {
subTaskEntity.state = state; subTaskEntity.setState(state);
subEntity.setState(state); subEntity.setState(state);
subEntity.setComplete(state == IEntity.STATE_COMPLETE); subEntity.setComplete(state == IEntity.STATE_COMPLETE);
if (state == IEntity.STATE_CANCEL) { if (state == IEntity.STATE_CANCEL) {
subTaskEntity.deleteData(); subEntity.deleteData();
return; return;
} else if (subEntity.isComplete()) { } else if (subEntity.isComplete()) {
subEntity.setCompleteTime(System.currentTimeMillis()); subEntity.setCompleteTime(System.currentTimeMillis());

@ -15,18 +15,21 @@
*/ */
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import android.text.TextUtils;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.util.SSLContextUtil; import com.arialyy.aria.util.SSLContextUtil;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.ProtocolException; import java.net.ProtocolException;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.util.Set; import java.util.Set;
import java.util.zip.GZIPInputStream;
import java.util.zip.InflaterInputStream;
import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.SSLSocketFactory;
import org.apache.commons.net.ftp.FTPClient;
/** /**
* Created by lyy on 2017/1/18. * Created by lyy on 2017/1/18.
@ -34,6 +37,26 @@ import org.apache.commons.net.ftp.FTPClient;
*/ */
class ConnectionHelp { class ConnectionHelp {
/**
* 转换HttpUrlConnect的inputStream流
*
* @return {@link GZIPInputStream}{@link InflaterInputStream}
* @throws IOException
*/
static InputStream convertInputStream(HttpURLConnection connection) throws IOException {
String encoding = connection.getContentEncoding();
if (TextUtils.isEmpty(encoding)) {
return connection.getInputStream();
}
if (encoding.contains("gzip")) {
return new GZIPInputStream(connection.getInputStream());
} else if (encoding.contains("deflate")) {
return new InflaterInputStream(connection.getInputStream());
} else {
return connection.getInputStream();
}
}
/** /**
* 处理链接 * 处理链接
* *
@ -65,12 +88,12 @@ class ConnectionHelp {
*/ */
static HttpURLConnection setConnectParam(DownloadTaskEntity entity, HttpURLConnection conn) static HttpURLConnection setConnectParam(DownloadTaskEntity entity, HttpURLConnection conn)
throws ProtocolException { throws ProtocolException {
conn.setRequestMethod(entity.requestEnum.name); conn.setRequestMethod(entity.getRequestEnum().name);
Set<String> keys = null; Set<String> keys = null;
if (entity.headers != null && entity.headers.size() > 0) { if (entity.getHeaders() != null && entity.getHeaders().size() > 0) {
keys = entity.headers.keySet(); keys = entity.getHeaders().keySet();
for (String key : keys) { for (String key : keys) {
conn.setRequestProperty(key, entity.headers.get(key)); conn.setRequestProperty(key, entity.getHeaders().get(key));
} }
} }
if (keys == null || !keys.contains("Charset")) { if (keys == null || !keys.contains("Charset")) {
@ -86,6 +109,7 @@ class ConnectionHelp {
.append("image/jpeg, ") .append("image/jpeg, ")
.append("image/pjpeg, ") .append("image/pjpeg, ")
.append("image/webp, ") .append("image/webp, ")
.append("image/apng, ")
.append("application/xml, ") .append("application/xml, ")
.append("application/xaml+xml, ") .append("application/xaml+xml, ")
.append("application/xhtml+xml, ") .append("application/xhtml+xml, ")

@ -16,6 +16,7 @@
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import android.util.SparseArray; import android.util.SparseArray;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback; import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
@ -33,6 +34,7 @@ import java.util.concurrent.Executors;
public class DownloadGroupUtil extends AbsGroupUtil implements IUtil { public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
private final String TAG = "DownloadGroupUtil"; private final String TAG = "DownloadGroupUtil";
private ExecutorService mInfoPool; private ExecutorService mInfoPool;
private int mInitCompleteNum, mInitFailNum;
/** /**
* 文件信息回调组 * 文件信息回调组
@ -42,6 +44,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
public DownloadGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) { public DownloadGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) {
super(listener, taskEntity); super(listener, taskEntity);
mInfoPool = Executors.newCachedThreadPool(); mInfoPool = Executors.newCachedThreadPool();
onPre();
} }
@Override int getTaskType() { @Override int getTaskType() {
@ -64,26 +67,28 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
@Override protected void onStart() { @Override protected void onStart() {
super.onStart(); super.onStart();
if (mExeMap.size() == 0){ if (mCompleteNum == mGroupSize) {
mListener.onComplete();
return;
}
if (mExeMap.size() == 0) {
ALog.e(TAG, "任务组无可执行任务"); ALog.e(TAG, "任务组无可执行任务");
mListener.onFail(false); mListener.onFail(false);
return; return;
} }
Set<String> keys = mExeMap.keySet(); Set<String> keys = mExeMap.keySet();
int i = 0;
for (String key : keys) { for (String key : keys) {
DownloadTaskEntity taskEntity = mExeMap.get(key); DownloadTaskEntity taskEntity = mExeMap.get(key);
if (taskEntity != null) { if (taskEntity != null) {
if (taskEntity.getState() != IEntity.STATE_FAIL if (taskEntity.getState() != IEntity.STATE_FAIL
&& taskEntity.getState() != IEntity.STATE_WAIT) { && taskEntity.getState() != IEntity.STATE_WAIT) {
createChildDownload(taskEntity); createChildDownload(taskEntity);
i++;
} else { } else {
mInfoPool.execute(createFileInfoThread(taskEntity)); mInfoPool.execute(createFileInfoThread(taskEntity));
} }
} }
} }
if (i != 0 && i == mExeMap.size()) startRunningFlow();
if (mCurrentLocation == mTotalLen) { if (mCurrentLocation == mTotalLen) {
mListener.onComplete(); mListener.onComplete();
} }
@ -99,7 +104,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
callback = new OnFileInfoCallback() { callback = new OnFileInfoCallback() {
int failNum = 0; int failNum = 0;
@Override public void onComplete(String url, int code) { @Override public void onComplete(String url, CompleteInfo info) {
DownloadTaskEntity te = mExeMap.get(url); DownloadTaskEntity te = mExeMap.get(url);
if (te != null) { if (te != null) {
if (isNeedLoadFileSize) { if (isNeedLoadFileSize) {
@ -107,32 +112,32 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
} }
createChildDownload(te); createChildDownload(te);
} }
mInitNum++; mInitCompleteNum ++;
if (mInitNum + mInitFailNum >= mGTEntity.getEntity().getSubTask().size()
|| !isNeedLoadFileSize) { if (mInitCompleteNum + mInitFailNum >= mGroupSize || !isNeedLoadFileSize) {
startRunningFlow(); startRunningFlow();
updateFileSize(); updateFileSize();
} }
} }
@Override public void onFail(String url, String errorMsg, boolean needRetry) { @Override public void onFail(String url, String errorMsg, boolean needRetry) {
ALog.e(TAG, "任务【" + url + "】初始化失败。");
DownloadTaskEntity te = mExeMap.get(url); DownloadTaskEntity te = mExeMap.get(url);
if (te != null) { if (te != null) {
mFailMap.put(url, te); mFailMap.put(url, te);
mFileInfoCallbacks.put(te.hashCode(), this); mFileInfoCallbacks.put(te.hashCode(), this);
mExeMap.remove(url);
} }
//404链接不重试下载 //404链接不重试下载
if (failNum < 10 && !errorMsg.contains("错误码:404") && !errorMsg.contains( //if (failNum < 3 && !errorMsg.contains("错误码:404") && !errorMsg.contains(
"UnknownHostException")) { // "UnknownHostException")) {
mInfoPool.execute(createFileInfoThread(te)); // mInfoPool.execute(createFileInfoThread(te));
} else { //} else {
mInitFailNum++; // mInitFailNum++;
mActualTaskNum--; //}
if (mActualTaskNum < 0) mActualTaskNum = 0; //failNum++;
} mInitFailNum ++;
failNum++; if (mInitCompleteNum + mInitFailNum >= mGroupSize || !isNeedLoadFileSize) {
if (mInitNum + mInitFailNum >= mGTEntity.getEntity().getSubTask().size()
|| !isNeedLoadFileSize) {
startRunningFlow(); startRunningFlow();
updateFileSize(); updateFileSize();
} }

@ -44,14 +44,20 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getUpdateInterval()); AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getUpdateInterval());
} }
@Override protected int setNewTaskThreadNum() {
return mEntity.getFileSize() <= SUB_LEN || mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP_DIR
? 1
: AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum();
}
@Override protected void checkTask() { @Override protected void checkTask() {
mConfigFile = new File(CommonUtil.getFileConfigPath(true, mEntity.getFileName())); mConfigFile = new File(CommonUtil.getFileConfigPath(true, mEntity.getFileName()));
mTempFile = new File(mEntity.getDownloadPath()); mTempFile = new File(mEntity.getDownloadPath());
if (!mTaskEntity.isSupportBP) { if (!mTaskEntity.isSupportBP()) {
isNewTask = true; isNewTask = true;
return; return;
} }
if (mTaskEntity.isNewTask) { if (mTaskEntity.isNewTask()) {
isNewTask = true; isNewTask = true;
return; return;
} }
@ -67,20 +73,21 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
} }
} }
@Override protected void 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(mEntity.getFileSize());
return true;
} catch (IOException e) { } catch (IOException e) {
failDownload("下载失败【downloadUrl:" failDownload("下载失败【downloadUrl:"
+ mEntity.getUrl() + mEntity.getUrl()
+ "】\n【filePath:" + "】\n【filePath:"
+ mEntity.getDownloadPath() + mEntity.getDownloadPath()
+ "】\n" + "】\n"
+ CommonUtil.getPrintException(e)); + ALog.getExceptionString(e));
} finally { } finally {
if (file != null) { if (file != null) {
try { try {
@ -90,10 +97,11 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
} }
} }
} }
return false;
} }
@Override protected AbsThreadTask selectThreadTask(SubThreadConfig<DownloadTaskEntity> config) { @Override protected AbsThreadTask selectThreadTask(SubThreadConfig<DownloadTaskEntity> config) {
switch (mTaskEntity.requestType) { switch (mTaskEntity.getRequestType()) {
case AbsTaskEntity.D_FTP: case AbsTaskEntity.D_FTP:
case AbsTaskEntity.D_FTP_DIR: case AbsTaskEntity.D_FTP_DIR:
return new FtpThreadTask(mConstance, (IDownloadListener) mListener, config); return new FtpThreadTask(mConstance, (IDownloadListener) mListener, config);
@ -108,6 +116,6 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
ALog.e(TAG, errorMsg); ALog.e(TAG, errorMsg);
mConstance.isRunning = false; mConstance.isRunning = false;
mListener.onFail(false); mListener.onFail(false);
ErrorHelp.saveError("", mEntity, "", errorMsg); ErrorHelp.saveError(TAG, "", errorMsg);
} }
} }

@ -15,8 +15,8 @@
*/ */
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
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.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.util.ErrorHelp; import com.arialyy.aria.util.ErrorHelp;
@ -27,6 +27,8 @@ import java.util.Set;
* ftp文件夹下载工具 * ftp文件夹下载工具
*/ */
public class FtpDirDownloadUtil extends AbsGroupUtil { public class FtpDirDownloadUtil extends AbsGroupUtil {
private String TAG = "FtpDirDownloadUtil";
public FtpDirDownloadUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) { public FtpDirDownloadUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) {
super(listener, taskEntity); super(listener, taskEntity);
} }
@ -38,30 +40,35 @@ public class FtpDirDownloadUtil extends AbsGroupUtil {
@Override protected void onStart() { @Override protected void onStart() {
super.onStart(); super.onStart();
if (mGTEntity.getEntity().getFileSize() > 1) { if (mGTEntity.getEntity().getFileSize() > 1) {
onPre();
startDownload(); startDownload();
} else { } else {
new FtpDirInfoThread(mGTEntity, new OnFileInfoCallback() { new FtpDirInfoThread(mGTEntity, new OnFileInfoCallback() {
@Override public void onComplete(String url, int code) { @Override public void onComplete(String url, CompleteInfo info) {
if (code >= 200 && code < 300) { if (info.code >= 200 && info.code < 300) {
for (DownloadEntity entity : mGTEntity.entity.getSubTask()) { onPre();
mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
}
mActualTaskNum = mGTEntity.entity.getSubTask().size();
mGroupSize = mActualTaskNum;
mTotalLen = mGTEntity.entity.getFileSize();
startDownload(); startDownload();
} }
} }
@Override public void onFail(String url, String errorMsg, boolean needRetry) { @Override public void onFail(String url, String errorMsg, boolean needRetry) {
DownloadTaskEntity te = mExeMap.get(url);
if (te != null) {
mFailMap.put(url, te);
mExeMap.remove(url);
}
mListener.onFail(needRetry); mListener.onFail(needRetry);
ErrorHelp.saveError("D_FTP_DIR", mGTEntity.getEntity(), "", errorMsg); ErrorHelp.saveError(TAG, "", errorMsg);
} }
}).start(); }).start();
} }
} }
private void startDownload() { private void startDownload() {
if (mCompleteNum == mGroupSize) {
mListener.onComplete();
return;
}
int i = 0; int i = 0;
Set<String> keys = mExeMap.keySet(); Set<String> keys = mExeMap.keySet();
for (String key : keys) { for (String key : keys) {
@ -71,6 +78,10 @@ public class FtpDirDownloadUtil extends AbsGroupUtil {
i++; i++;
} }
} }
if (i == mExeMap.size()) startRunningFlow(); if (mExeMap.size() == 0) {
mListener.onComplete();
} else if (i == mExeMap.size()) {
startRunningFlow();
}
} }
} }

@ -17,10 +17,13 @@ package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.FtpUrlEntity; import com.arialyy.aria.core.FtpUrlEntity;
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.OnFileInfoCallback; import com.arialyy.aria.core.common.OnFileInfoCallback;
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;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
@ -37,7 +40,7 @@ class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DownloadGro
} }
@Override protected String setRemotePath() { @Override protected String setRemotePath() {
return mTaskEntity.urlEntity.remotePath; return mTaskEntity.getUrlEntity().remotePath;
} }
@Override protected void handleFile(String remotePath, FTPFile ftpFile) { @Override protected void handleFile(String remotePath, FTPFile ftpFile) {
@ -48,28 +51,43 @@ class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DownloadGro
@Override protected void onPreComplete(int code) { @Override protected void onPreComplete(int code) {
super.onPreComplete(code); super.onPreComplete(code);
mEntity.setFileSize(mSize); mEntity.setFileSize(mSize);
mCallback.onComplete(mEntity.getKey(), code); mCallback.onComplete(mEntity.getKey(), new CompleteInfo(code));
} }
/**
* FTP文件夹的子任务实体 在这生成
*/
private void addEntity(String remotePath, FTPFile ftpFile) { private void addEntity(String remotePath, FTPFile ftpFile) {
final FtpUrlEntity urlEntity = mTaskEntity.urlEntity; final FtpUrlEntity urlEntity = mTaskEntity.getUrlEntity().clone();
DownloadEntity entity = new DownloadEntity(); DownloadEntity entity = new DownloadEntity();
entity.setUrl(urlEntity.protocol + "://" + urlEntity.hostName + ":" + urlEntity.port + remotePath); entity.setUrl(
urlEntity.protocol + "://" + urlEntity.hostName + ":" + urlEntity.port + "/" + remotePath);
entity.setDownloadPath(mEntity.getDirPath() + "/" + remotePath); entity.setDownloadPath(mEntity.getDirPath() + "/" + remotePath);
int lastIndex = remotePath.lastIndexOf("/"); int lastIndex = remotePath.lastIndexOf("/");
String fileName = lastIndex < 0 ? CommonUtil.keyToHashKey(remotePath) String fileName = lastIndex < 0 ? CommonUtil.keyToHashKey(remotePath)
: remotePath.substring(lastIndex + 1, remotePath.length()); : remotePath.substring(lastIndex + 1, remotePath.length());
entity.setFileName(new String(fileName.getBytes(), Charset.forName(mTaskEntity.charSet))); entity.setFileName(new String(fileName.getBytes(), Charset.forName(mTaskEntity.getCharSet())));
entity.setGroupName(mEntity.getGroupName()); entity.setGroupName(mEntity.getGroupName());
entity.setGroupChild(true); entity.setGroupChild(true);
entity.setFileSize(ftpFile.getSize()); entity.setFileSize(ftpFile.getSize());
entity.insert(); entity.insert();
DownloadTaskEntity taskEntity = new DownloadTaskEntity();
taskEntity.setKey(entity.getDownloadPath());
taskEntity.setUrl(entity.getUrl());
taskEntity.setEntity(entity);
taskEntity.setGroupTask(true);
taskEntity.setGroupName(mEntity.getGroupName());
taskEntity.setRequestType(AbsTaskEntity.D_FTP);
urlEntity.url = entity.getUrl();
urlEntity.remotePath = remotePath;
taskEntity.setUrlEntity(urlEntity);
taskEntity.insert();
if (mEntity.getUrls() == null) { if (mEntity.getUrls() == null) {
mEntity.setUrls(new ArrayList<String>()); mEntity.setUrls(new ArrayList<String>());
} }
if (mEntity.getSubTask() == null) { mEntity.getSubEntities().add(entity);
mEntity.setSubTasks(new ArrayList<DownloadEntity>()); mTaskEntity.getSubTaskEntities().add(taskEntity);
}
mEntity.getSubTask().add(entity);
} }
} }

@ -16,6 +16,7 @@
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
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.OnFileInfoCallback; import com.arialyy.aria.core.common.OnFileInfoCallback;
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.download.DownloadTaskEntity;
@ -31,15 +32,15 @@ class FtpFileInfoThread extends AbsFtpInfoThread<DownloadEntity, DownloadTaskEnt
} }
@Override protected String setRemotePath() { @Override protected String setRemotePath() {
return mTaskEntity.urlEntity.remotePath; return mTaskEntity.getUrlEntity().remotePath;
} }
@Override protected void onPreComplete(int code) { @Override protected void onPreComplete(int code) {
super.onPreComplete(code); super.onPreComplete(code);
if (mSize != mTaskEntity.getEntity().getFileSize()) { if (mSize != mTaskEntity.getEntity().getFileSize()) {
mTaskEntity.isNewTask = true; mTaskEntity.setNewTask(true);
} }
mEntity.setFileSize(mSize); mEntity.setFileSize(mSize);
mCallback.onComplete(mEntity.getUrl(), code); mCallback.onComplete(mEntity.getUrl(), new CompleteInfo(code));
} }
} }

@ -34,7 +34,7 @@ import org.apache.commons.net.ftp.FTPReply;
* Ftp下载任务 * Ftp下载任务
*/ */
class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity> { class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity> {
private final String TAG = "FtpDownloadThreadTask"; private final String TAG = "FtpThreadTask";
FtpThreadTask(StateConstance constance, IDownloadListener listener, FtpThreadTask(StateConstance constance, IDownloadListener listener,
SubThreadConfig<DownloadTaskEntity> downloadInfo) { SubThreadConfig<DownloadTaskEntity> downloadInfo) {
@ -71,7 +71,7 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
return; return;
} }
String remotePath = String remotePath =
new String(mTaskEntity.urlEntity.remotePath.getBytes(charSet), SERVER_CHARSET); new String(mTaskEntity.getUrlEntity().remotePath.getBytes(charSet), SERVER_CHARSET);
ALog.i(TAG, "remotePath【" + remotePath + "】"); ALog.i(TAG, "remotePath【" + remotePath + "】");
is = client.retrieveFileStream(remotePath); is = client.retrieveFileStream(remotePath);
reply = client.getReplyCode(); reply = client.getReplyCode();

@ -17,13 +17,17 @@ package com.arialyy.aria.core.download.downloader;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
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.download.DownloadEntity; 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.util.ALog; import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.net.URLDecoder; import java.net.URLDecoder;
@ -54,7 +58,7 @@ class HttpFileInfoThread implements Runnable {
conn = ConnectionHelp.setConnectParam(mTaskEntity, conn); conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
conn.setRequestProperty("Range", "bytes=" + 0 + "-"); conn.setRequestProperty("Range", "bytes=" + 0 + "-");
conn.setConnectTimeout(mConnectTimeOut); conn.setConnectTimeout(mConnectTimeOut);
conn.setRequestMethod(mTaskEntity.requestEnum.name); //conn.setChunkedStreamingMode(0);
conn.connect(); conn.connect();
handleConnect(conn); handleConnect(conn);
} catch (IOException e) { } catch (IOException e) {
@ -63,7 +67,7 @@ class HttpFileInfoThread implements Runnable {
+ "】\n【filePath:" + "】\n【filePath:"
+ mEntity.getDownloadPath() + mEntity.getDownloadPath()
+ "】\n" + "】\n"
+ CommonUtil.getPrintException(e), true); + ALog.getExceptionString(e), true);
} finally { } finally {
if (conn != null) { if (conn != null) {
conn.disconnect(); conn.disconnect();
@ -74,62 +78,122 @@ class HttpFileInfoThread implements Runnable {
private void handleConnect(HttpURLConnection conn) throws IOException { private void handleConnect(HttpURLConnection conn) throws IOException {
long len = conn.getContentLength(); long len = conn.getContentLength();
if (len < 0) { if (len < 0) {
String temp = conn.getHeaderField(mTaskEntity.contentLength); String temp = conn.getHeaderField("Content-Length");
len = TextUtils.isEmpty(temp) ? -1 : Long.parseLong(temp); len = TextUtils.isEmpty(temp) ? -1 : Long.parseLong(temp);
// 某些服务,如果设置了conn.setRequestProperty("Range", "bytes=" + 0 + "-");
// 会返回 Content-Range: bytes 0-225427911/225427913
if (len < 0) {
temp = conn.getHeaderField("Content-Range");
if (TextUtils.isEmpty(temp)) {
len = -1;
} else {
int start = temp.indexOf("/");
len = Long.parseLong(temp.substring(start + 1, temp.length()));
}
}
} }
int code = conn.getResponseCode(); int code = conn.getResponseCode();
boolean isComplete = false; boolean end = false;
if (TextUtils.isEmpty(mEntity.getMd5Code())) { if (TextUtils.isEmpty(mEntity.getMd5Code())) {
String md5Code = conn.getHeaderField(mTaskEntity.md5Key); String md5Code = conn.getHeaderField("Content-MD5");
mEntity.setMd5Code(md5Code); mEntity.setMd5Code(md5Code);
} }
String disposition = conn.getHeaderField(mTaskEntity.dispositionKey);
boolean isChunked = false;
final String str = conn.getHeaderField("Transfer-Encoding");
if (!TextUtils.isEmpty(str) && str.equals("chunked")) {
isChunked = true;
}
//Map<String, List<String>> headers = conn.getHeaderFields(); //Map<String, List<String>> headers = conn.getHeaderFields();
if (!TextUtils.isEmpty(disposition)) { String disposition = conn.getHeaderField("Content-Disposition");
if (mTaskEntity.isUseServerFileName() && !TextUtils.isEmpty(disposition)) {
mEntity.setDisposition(CommonUtil.encryptBASE64(disposition)); mEntity.setDisposition(CommonUtil.encryptBASE64(disposition));
if (disposition.contains(mTaskEntity.dispositionFileKey)) { if (disposition.contains(";")) {
String[] infos = disposition.split("="); String[] infos = disposition.split(";");
mEntity.setServerFileName(URLDecoder.decode(infos[1], "utf-8")); for (String info : infos) {
if (info.startsWith("filename") && info.contains("=")) {
String[] temp = info.split("=");
if (temp.length > 1) {
String newName = URLDecoder.decode(temp[1], "utf-8");
mEntity.setServerFileName(newName);
fileRename(newName);
break;
}
}
}
} }
} }
mTaskEntity.code = code; mTaskEntity.setCode(code);
if (code == HttpURLConnection.HTTP_PARTIAL) { if (code == HttpURLConnection.HTTP_PARTIAL) {
if (!checkLen(len)) return; if (!checkLen(len) && !isChunked) {
return;
}
mEntity.setFileSize(len); mEntity.setFileSize(len);
mTaskEntity.isSupportBP = true; mTaskEntity.setSupportBP(true);
isComplete = true; end = true;
} else if (code == HttpURLConnection.HTTP_OK) { } else if (code == HttpURLConnection.HTTP_OK) {
if (!checkLen(len)) return; if (conn.getHeaderField("Content-Type").equals("text/html")) {
BufferedReader reader =
new BufferedReader(new InputStreamReader(ConnectionHelp.convertInputStream(conn)));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
reader.close();
handleUrlReTurn(conn, CommonUtil.getWindowReplaceUrl(sb.toString()));
return;
} else if (!checkLen(len) && !isChunked) {
return;
}
mEntity.setFileSize(len); mEntity.setFileSize(len);
mTaskEntity.isSupportBP = false; mTaskEntity.setSupportBP(false);
isComplete = true; end = true;
} else if (code == HttpURLConnection.HTTP_NOT_FOUND) { } else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:404", true); failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:404", true);
} else if (code == HttpURLConnection.HTTP_MOVED_TEMP } else if (code == HttpURLConnection.HTTP_MOVED_TEMP
|| code == HttpURLConnection.HTTP_MOVED_PERM || code == HttpURLConnection.HTTP_MOVED_PERM
|| code == HttpURLConnection.HTTP_SEE_OTHER) { || code == HttpURLConnection.HTTP_SEE_OTHER) {
mTaskEntity.redirectUrl = conn.getHeaderField(mTaskEntity.redirectUrlKey); handleUrlReTurn(conn, conn.getHeaderField("Location"));
mEntity.setRedirect(true);
mEntity.setRedirectUrl(mTaskEntity.redirectUrl);
handle302Turn(conn);
} else { } else {
failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:" + code, true); failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:" + code, true);
} }
if (isComplete) { if (end) {
mTaskEntity.setChunked(isChunked);
mTaskEntity.update();
if (onFileInfoListener != null) { if (onFileInfoListener != null) {
onFileInfoListener.onComplete(mEntity.getUrl(), code); CompleteInfo info = new CompleteInfo(code);
onFileInfoListener.onComplete(mEntity.getUrl(), info);
} }
mTaskEntity.update();
} }
} }
/**
* 重命名文件
*/
private void fileRename(String newName) {
if (TextUtils.isEmpty(newName)) {
ALog.w(TAG, "重命名失败【服务器返回的文件名为空】");
return;
}
File oldFile = new File(mEntity.getDownloadPath());
String oldName = oldFile.getName();
String newPath = oldFile.getParent() + "/" + newName;
if (oldFile.exists()){
oldFile.renameTo(new File(newPath));
}
mEntity.setFileName(newName);
mEntity.setDownloadPath(newPath);
mTaskEntity.setKey(newPath);
CommonUtil.renameDownloadConfig(oldName, newName);
}
/** /**
* 处理30x跳转 * 处理30x跳转
*/ */
private void handle302Turn(HttpURLConnection conn) throws IOException { private void handleUrlReTurn(HttpURLConnection conn, String newUrl) throws IOException {
String newUrl = conn.getHeaderField(mTaskEntity.redirectUrlKey); ALog.d(TAG, "30x跳转,新url为【" + newUrl + "】");
ALog.d(TAG, "30x跳转,location【 " + mTaskEntity.redirectUrlKey + "】" + "新url为【" + newUrl + "】");
if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null") || !newUrl.startsWith( if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null") || !newUrl.startsWith(
"http")) { "http")) {
if (onFileInfoListener != null) { if (onFileInfoListener != null) {
@ -137,7 +201,13 @@ class HttpFileInfoThread implements Runnable {
} }
return; return;
} }
newUrl = CheckUtil.checkUrl(newUrl); if (!CheckUtil.checkUrl(newUrl)) {
failDownload("下载失败,重定向url错误", false);
return;
}
mTaskEntity.setRedirectUrl(newUrl);
mEntity.setRedirect(true);
mEntity.setRedirectUrl(newUrl);
String cookies = conn.getHeaderField("Set-Cookie"); String cookies = conn.getHeaderField("Set-Cookie");
conn = (HttpURLConnection) new URL(newUrl).openConnection(); conn = (HttpURLConnection) new URL(newUrl).openConnection();
conn = ConnectionHelp.setConnectParam(mTaskEntity, conn); conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
@ -157,7 +227,7 @@ class HttpFileInfoThread implements Runnable {
*/ */
private boolean checkLen(long len) { private boolean checkLen(long len) {
if (len != mEntity.getFileSize()) { if (len != mEntity.getFileSize()) {
mTaskEntity.isNewTask = true; mTaskEntity.setNewTask(true);
} }
if (len < 0) { if (len < 0) {
failDownload("任务【" + mEntity.getUrl() + "】下载失败,文件长度小于0", true); failDownload("任务【" + mEntity.getUrl() + "】下载失败,文件长度小于0", true);

@ -27,6 +27,8 @@ import com.arialyy.aria.util.CommonUtil;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
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;
@ -71,49 +73,23 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
conn = ConnectionHelp.setConnectParam(mConfig.TASK_ENTITY, conn); conn = ConnectionHelp.setConnectParam(mConfig.TASK_ENTITY, conn);
conn.setConnectTimeout(STATE.CONNECT_TIME_OUT); conn.setConnectTimeout(STATE.CONNECT_TIME_OUT);
conn.setReadTimeout(STATE.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数 conn.setReadTimeout(STATE.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数
//is = conn.getInputStream();
is = new BufferedInputStream(conn.getInputStream()); is = new BufferedInputStream(ConnectionHelp.convertInputStream(conn));
//创建可设置位置的文件 //创建可设置位置的文件
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize); file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize);
//设置每条线程写入文件的位置 //设置每条线程写入文件的位置
file.seek(mConfig.START_LOCATION); file.seek(mConfig.START_LOCATION);
byte[] buffer = new byte[mBufSize];
int len; if (mTaskEntity.isChunked()) {
while ((len = is.read(buffer)) != -1) { readChunk(is, file);
if (STATE.isCancel || STATE.isStop){ } else {
break; readNormal(is, file);
}
if (mSleepTime > 0) {
Thread.sleep(mSleepTime);
}
file.write(buffer, 0, len);
progress(len);
} }
if (STATE.isCancel || STATE.isStop){
if (STATE.isCancel || STATE.isStop) {
return; return;
} }
//支持断点的处理 handleComplete();
if (mConfig.SUPPORT_BP) {
ALog.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕");
writeConfig(true, 1);
STATE.COMPLETE_THREAD_NUM++;
if (STATE.isComplete()) {
File configFile = new File(mConfigFPath);
if (configFile.exists()) {
configFile.delete();
}
STATE.isRunning = false;
mListener.onComplete();
}
if (STATE.isFail()){
STATE.isRunning = false;
mListener.onFail(false);
}
} else {
ALog.i(TAG, "任务下载完成");
STATE.isRunning = false;
mListener.onComplete();
}
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
fail(mChildCurrentLocation, "下载链接异常", e); fail(mChildCurrentLocation, "下载链接异常", e);
} catch (IOException e) { } catch (IOException e) {
@ -137,6 +113,69 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
} }
} }
/**
* 读取chunk模式的文件流
*
* @deprecated 暂时先这样处理无chun
*/
private void readChunk(InputStream is, RandomAccessFile file)
throws IOException, InterruptedException {
readNormal(is, file);
}
/**
* 读取普通的文件流
*/
private void readNormal(InputStream is, RandomAccessFile file)
throws IOException, InterruptedException {
byte[] buffer = new byte[mBufSize];
int len;
while ((len = is.read(buffer)) != -1) {
if (STATE.isCancel || STATE.isStop) {
break;
}
if (mSleepTime > 0) {
Thread.sleep(mSleepTime);
}
file.write(buffer, 0, len);
progress(len);
}
}
/**
* 处理完成配置文件的更新或事件回调
*
* @throws IOException
*/
private void handleComplete() throws IOException {
//支持断点的处理
if (mConfig.SUPPORT_BP) {
if (mChildCurrentLocation == mConfig.END_LOCATION) {
ALog.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕");
writeConfig(true, 1);
STATE.COMPLETE_THREAD_NUM++;
if (STATE.isComplete()) {
File configFile = new File(mConfigFPath);
if (configFile.exists()) {
configFile.delete();
}
STATE.isRunning = false;
mListener.onComplete();
}
} else {
STATE.FAIL_NUM++;
}
if (STATE.isFail()) {
STATE.isRunning = false;
mListener.onFail(false);
}
} else {
ALog.i(TAG, "任务下载完成");
STATE.isRunning = false;
mListener.onComplete();
}
}
@Override protected String getTaskType() { @Override protected String getTaskType() {
return "HTTP_DOWNLOAD"; return "HTTP_DOWNLOAD";
} }

@ -16,6 +16,7 @@
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback; import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
@ -28,7 +29,7 @@ import com.arialyy.aria.util.ErrorHelp;
* D_HTTP\FTP单任务下载工具 * D_HTTP\FTP单任务下载工具
*/ */
public class SimpleDownloadUtil implements IUtil, Runnable { public class SimpleDownloadUtil implements IUtil, Runnable {
private static final String TAG = "SimpleDownloadUtil"; private String TAG = "SimpleDownloadUtil";
private IDownloadListener mListener; private IDownloadListener mListener;
private Downloader mDownloader; private Downloader mDownloader;
private DownloadTaskEntity mTaskEntity; private DownloadTaskEntity mTaskEntity;
@ -85,14 +86,14 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
private void failDownload(String msg, boolean needRetry) { private void failDownload(String msg, boolean needRetry) {
mListener.onFail(needRetry); mListener.onFail(needRetry);
ErrorHelp.saveError("HTTP_DOWNLOAD", mTaskEntity.getEntity(), msg, ""); ErrorHelp.saveError(TAG, msg, "");
} }
@Override public void run() { @Override public void run() {
mListener.onPre(); mListener.onPre();
if (mTaskEntity.getEntity().getFileSize() <= 1 if (mTaskEntity.getEntity().getFileSize() <= 1
|| mTaskEntity.refreshInfo || mTaskEntity.isRefreshInfo()
|| mTaskEntity.requestType == AbsTaskEntity.D_FTP) { || mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP) {
new Thread(createInfoThread()).start(); new Thread(createInfoThread()).start();
} else { } else {
mDownloader.start(); mDownloader.start();
@ -103,10 +104,10 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
* 通过链接类型创建不同的获取文件信息的线程 * 通过链接类型创建不同的获取文件信息的线程
*/ */
private Runnable createInfoThread() { private Runnable createInfoThread() {
switch (mTaskEntity.requestType) { switch (mTaskEntity.getRequestType()) {
case AbsTaskEntity.D_FTP: case AbsTaskEntity.D_FTP:
return new FtpFileInfoThread(mTaskEntity, new OnFileInfoCallback() { return new FtpFileInfoThread(mTaskEntity, new OnFileInfoCallback() {
@Override public void onComplete(String url, int code) { @Override public void onComplete(String url, CompleteInfo info) {
mDownloader.start(); mDownloader.start();
} }
@ -116,7 +117,7 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
}); });
case AbsTaskEntity.D_HTTP: case AbsTaskEntity.D_HTTP:
return new HttpFileInfoThread(mTaskEntity, new OnFileInfoCallback() { return new HttpFileInfoThread(mTaskEntity, new OnFileInfoCallback() {
@Override public void onComplete(String url, int code) { @Override public void onComplete(String url, CompleteInfo info) {
mDownloader.start(); mDownloader.start();
} }

@ -0,0 +1,44 @@
/*
* 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.download.wrapper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
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.List;
/**
* Created by laoyuyu on 2018/3/30.
* 任务组实体和子任务实体的关系
*/
@Wrapper
public class DGEWrapper extends AbsWrapper {
@One
public DownloadGroupEntity groupEntity;
@Many(parentColumn = "groupName", entityColumn = "groupName")
public List<DownloadEntity> subEntity;
@Override protected void handleConvert() {
if (subEntity != null && !subEntity.isEmpty()) {
groupEntity.setSubEntities(subEntity);
}
}
}

@ -0,0 +1,44 @@
/*
* 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.download.wrapper;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
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.List;
/**
* Created by laoyuyu on 2018/4/11.
* 任务组任务实体和任务组任务实体的子任务实体对应关系
*/
@Wrapper
public class DGSTEWrapper extends AbsWrapper {
@One
public DownloadGroupTaskEntity dgTaskEntity;
@Many(parentColumn = "key", entityColumn = "groupName")
public List<DownloadTaskEntity> subTaskEntity;
@Override protected void handleConvert() {
if (subTaskEntity != null && !subTaskEntity.isEmpty()) {
dgTaskEntity.setSubTaskEntities(subTaskEntity);
}
}
}

@ -0,0 +1,65 @@
/*
* 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.download.wrapper;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.orm.AbsWrapper;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.annotation.Many;
import com.arialyy.aria.orm.annotation.One;
import com.arialyy.aria.orm.annotation.Wrapper;
import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList;
import java.util.List;
/**
* Created by laoyuyu on 2018/3/30.
* 任务组实体和任务组任务实体的关系
*/
@Wrapper
public class DGTEWrapper extends AbsWrapper {
@One
public DownloadGroupEntity entity;
@Many(parentColumn = "groupName", entityColumn = "key")
private List<DownloadGroupTaskEntity> taskEntitys;
public DownloadGroupTaskEntity taskEntity;
@Override protected void handleConvert() {
taskEntity = (taskEntitys == null || taskEntitys.isEmpty()) ? null : taskEntitys.get(0);
if (taskEntity != null) {
taskEntity.setEntity(entity);
List<DTEWrapper> subWrappers =
DbEntity.findRelationData(DTEWrapper.class, "DownloadTaskEntity.groupName=?",
taskEntity.getKey());
if (subWrappers != null && !subWrappers.isEmpty()) {
List<DownloadTaskEntity> temp = new ArrayList<>();
for (DTEWrapper dw : subWrappers) {
if (dw.taskEntity.getRequestType() == AbsTaskEntity.D_FTP) {
dw.taskEntity.setUrlEntity(CommonUtil.getFtpUrlInfo(dw.taskEntity.getUrl()));
}
temp.add(dw.taskEntity);
}
taskEntity.setSubTaskEntities(temp);
}
}
}
}

@ -0,0 +1,46 @@
/*
* 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.download.wrapper;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
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.List;
/**
* Created by laoyuyu on 2018/3/30.
*/
@Wrapper
public class DTEWrapper extends AbsWrapper {
@One
public DownloadEntity entity;
@Many(parentColumn = "downloadPath", entityColumn = "key")
private List<DownloadTaskEntity> taskEntitys = null;
public DownloadTaskEntity taskEntity;
@Override public void handleConvert() {
taskEntity = (taskEntitys == null || taskEntitys.isEmpty()) ? null : taskEntitys.get(0);
if (taskEntity != null) {
taskEntity.setEntity(entity);
}
}
}

@ -1,151 +0,0 @@
/*
* 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.inf;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
/**
* Created by lyy on 2017/2/28.
*/
public abstract class AbsDownloadTarget<TARGET extends AbsTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
extends AbsTarget<TARGET, ENTITY, TASK_ENTITY> {
/**
* 如果你的下载链接的header中含有md5码信息那么你可以通过设置key来获取从header获取该md5码信息
* key默认值为Content-MD5
* 获取md5信息{@link DownloadEntity#getMd5Code()}
*/
public TARGET setHeaderMd5Key(String md5Key) {
if (TextUtils.isEmpty(md5Key)) return (TARGET) this;
mTaskEntity.md5Key = md5Key;
if (TextUtils.isEmpty(mTaskEntity.md5Key) || !mTaskEntity.md5Key.equals(md5Key)) {
mTaskEntity.update();
}
return (TARGET) this;
}
/**
* 如果你的文件长度是放在header中那么你需要配置key来让Aria知道正确的文件长度
* key默认值为Content-Length
*/
public TARGET setHeaderContentLengthKey(String contentLength) {
if (TextUtils.isEmpty(contentLength)) return (TARGET) this;
mTaskEntity.contentLength = contentLength;
if (TextUtils.isEmpty(mTaskEntity.contentLength) || !mTaskEntity.contentLength.equals(
contentLength)) {
mTaskEntity.update();
}
return (TARGET) this;
}
/**
* 如果你的下载链接的header中含有文件描述信息那么你可以通过设置key来获取从header获取该文件描述信息
* key默认值为Content-Disposition
* 获取文件描述信息{@link DownloadEntity#getDisposition()}
*/
public TARGET setHeaderDispositionKey(String dispositionKey) {
if (TextUtils.isEmpty(dispositionKey)) return (TARGET) this;
mTaskEntity.dispositionKey = dispositionKey;
if (TextUtils.isEmpty(mTaskEntity.dispositionKey) || !mTaskEntity.dispositionKey.equals(
dispositionKey)) {
mTaskEntity.save();
}
return (TARGET) this;
}
/**
* 从文件描述信息{@link #setHeaderDispositionKey(String)}中含有文件名信息你可以通过设置key来获取header中的文件名
* key默认值为attachment;filename
* 获取文件名信息{@link DownloadEntity#getServerFileName()}
*/
public TARGET setHeaderDispositionFileKey(String dispositionFileKey) {
if (TextUtils.isEmpty(dispositionFileKey)) return (TARGET) this;
mTaskEntity.dispositionFileKey = dispositionFileKey;
if (TextUtils.isEmpty(mTaskEntity.dispositionFileKey) || !mTaskEntity.dispositionFileKey.equals(
dispositionFileKey)) {
mTaskEntity.save();
}
return (TARGET) this;
}
/**
* 将任务设置为最高优先级任务最高优先级任务有以下特点
* 1在下载队列中有且只有一个最高优先级任务
* 2最高优先级任务会一直存在直到用户手动暂停或任务完成
* 3任务调度器不会暂停最高优先级任务
* 4用户手动暂停或任务完成后第二次重新执行该任务该命令将失效
* 5如果下载队列中已经满了则会停止队尾的任务当高优先级任务完成后该队尾任务将自动执行
* 6把任务设置为最高优先级任务后将自动执行任务不需要重新调用start()启动任务
*/
protected void setHighestPriority() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity,
NormalCmdFactory.TASK_HIGHEST_PRIORITY, checkTaskType()))
.exe();
}
/**
* 重定向后新url的key默认为location
*/
public void setRedirectUrlKey(String redirectUrlKey) {
if (TextUtils.isEmpty(redirectUrlKey)) {
ALog.e("AbsDownloadTarget", "重定向后,新url的key不能为null");
return;
}
mTaskEntity.redirectUrlKey = redirectUrlKey;
}
/**
* 获取任务文件大小
*
* @return 文件大小
*/
public long getFileSize() {
return getSize();
}
/**
* 获取单位转换后的文件大小
*
* @return 文件大小{@code xxx mb}
*/
public String getConvertFileSize() {
return getConvertSize();
}
/**
* 添加任务
*/
public void add() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE,
checkTaskType()))
.exe();
}
/**
* 重新下载
*/
public void reStart() {
cancel();
start();
}
}

@ -18,7 +18,7 @@ package com.arialyy.aria.core.inf;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.Ignore; import com.arialyy.aria.orm.annotation.Ignore;
/** /**
* Created by AriaL on 2017/6/29. * Created by AriaL on 2017/6/29.
@ -31,7 +31,7 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
/** /**
* 单位转换后的速度 * 单位转换后的速度
*/ */
@Ignore private String convertSpeed = ""; @Ignore private String convertSpeed;
/** /**
* 下载失败计数每次开始都重置为0 * 下载失败计数每次开始都重置为0
*/ */
@ -40,7 +40,7 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
/** /**
* 扩展字段 * 扩展字段
*/ */
private String str = ""; private String str;
/** /**
* 文件大小 * 文件大小
*/ */
@ -48,7 +48,7 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
/** /**
* 转换后的文件大小 * 转换后的文件大小
*/ */
private String convertFileSize = ""; private String convertFileSize;
private int state = STATE_WAIT; private int state = STATE_WAIT;
/** /**

@ -17,10 +17,7 @@ package com.arialyy.aria.core.inf;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.orm.annotation.Primary;
import com.arialyy.aria.orm.Foreign;
import com.arialyy.aria.orm.NormalList;
import com.arialyy.aria.orm.Primary;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -29,20 +26,16 @@ import java.util.List;
*/ */
public abstract class AbsGroupEntity extends AbsEntity implements Parcelable { public abstract class AbsGroupEntity extends AbsEntity implements Parcelable {
/** /**
* 组名组名为任务地址相加的urlMd5 * 组名组名为任务地址相加的urlMd5
*/ */
@Primary @Foreign(table = DownloadGroupTaskEntity.class, column = "key") protected String @Primary protected String groupName;
groupName = "";
/** /**
* 任务组别名 * 任务组别名
*/ */
private String alias = ""; private String alias;
/** private List<String> urls = new ArrayList<>();
* 子任务链接组
*/
@NormalList(clazz = String.class) private List<String> urls = new ArrayList<>();
public List<String> getUrls() { public List<String> getUrls() {
return urls; return urls;

@ -17,8 +17,6 @@ package com.arialyy.aria.core.inf;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.Ignore;
/** /**
* Created by AriaL on 2017/6/3. * Created by AriaL on 2017/6/3.
@ -28,12 +26,12 @@ public abstract class AbsNormalEntity extends AbsEntity implements Parcelable {
/** /**
* 服务器地址 * 服务器地址
*/ */
private String url = ""; private String url;
/** /**
* 文件名 * 文件名
*/ */
private String fileName = ""; private String fileName;
/** /**
* 是否是任务组里面的下载实体 * 是否是任务组里面的下载实体
@ -41,7 +39,7 @@ public abstract class AbsNormalEntity extends AbsEntity implements Parcelable {
private boolean isGroupChild = false; private boolean isGroupChild = false;
private boolean isRedirect = false; //是否重定向 private boolean isRedirect = false; //是否重定向
private String redirectUrl = ""; //重定向链接 private String redirectUrl; //重定向链接
public String getUrl() { public String getUrl() {
return url; return url;

@ -15,13 +15,11 @@
*/ */
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.inf;
import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.ICmd; import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.command.normal.CancelCmd; import com.arialyy.aria.core.command.normal.CancelCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory; import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.manager.TEManager; import com.arialyy.aria.core.manager.TEManager;
@ -30,25 +28,29 @@ import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set;
/** /**
* Created by AriaL on 2017/7/3. * Created by AriaL on 2017/7/3.
*/ */
public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity> public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
implements ITarget<TARGET> { implements ITarget<TARGET> {
protected String TAG = "";
protected ENTITY mEntity; protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity; protected TASK_ENTITY mTaskEntity;
protected String mTargetName; protected String mTargetName;
protected AbsTarget() {
TAG = CommonUtil.getClassName(this);
}
/** /**
* 重置下载状态将任务状态设置为未开始状态 * 重置状态将任务状态设置为未开始状态
* 注意如果在后续方法调用链中没有调用 {@link #start()}{@link #stop()}{@link #cancel()}{@link #resume()}
* 等操作任务的方法那么你需要调用{@link #save()}才能将修改保存到数据库
*/ */
public TARGET resetState() { public TARGET resetState() {
mTaskEntity.getEntity().setState(IEntity.STATE_WAIT); mTaskEntity.getEntity().setState(IEntity.STATE_WAIT);
mTaskEntity.refreshInfo = true; mTaskEntity.setRefreshInfo(true);
mTaskEntity.update();
return (TARGET) this; return (TARGET) this;
} }
@ -60,32 +62,17 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
ALog.d("AbsTarget", "任务正在下载,即将删除任务"); ALog.d("AbsTarget", "任务正在下载,即将删除任务");
cancel(); cancel();
} else { } else {
mTaskEntity.deleteData(); mEntity.deleteData();
TEManager.getInstance().removeTEntity(mEntity.getKey()); TEManager.getInstance().removeTEntity(mEntity.getKey());
} }
} }
/**
* 任务是否在执行
*
* @return {@code true} 任务正在执行
*/
public boolean isRunning() {
return false;
}
/**
* 任务是否存在
*/
public boolean taskExists() {
return false;
}
/** /**
* 获取任务进度如果任务存在则返回当前进度 * 获取任务进度如果任务存在则返回当前进度
* *
* @return 该任务进度 * @return 该任务进度
*/ */
@Override
public long getCurrentProgress() { public long getCurrentProgress() {
return mEntity == null ? -1 : mEntity.getCurrentProgress(); return mEntity == null ? -1 : mEntity.getCurrentProgress();
} }
@ -110,6 +97,8 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
/** /**
* 设置扩展字段用来保存你的其它数据如果你的数据比较多你可以把你的数据转换为JSON字符串然后再存到Aria中 * 设置扩展字段用来保存你的其它数据如果你的数据比较多你可以把你的数据转换为JSON字符串然后再存到Aria中
* 注意如果在后续方法调用链中没有调用 {@link #start()}{@link #stop()}{@link #cancel()}{@link #resume()}
* 等操作任务的方法那么你需要调用{@link #save()}才能将修改保存到数据库
* *
* @param str 扩展数据 * @param str 扩展数据
*/ */
@ -117,8 +106,10 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
if (TextUtils.isEmpty(str)) return (TARGET) this; if (TextUtils.isEmpty(str)) return (TARGET) this;
if (TextUtils.isEmpty(mEntity.getStr()) || !mEntity.getStr().equals(str)) { if (TextUtils.isEmpty(mEntity.getStr()) || !mEntity.getStr().equals(str)) {
mEntity.setStr(str); mEntity.setStr(str);
mEntity.save(); } else {
ALog.e(TAG, "设置扩展字段失败,扩展字段为null");
} }
return (TARGET) this; return (TARGET) this;
} }
@ -135,6 +126,7 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
* *
* @return {@link IEntity} * @return {@link IEntity}
*/ */
@Override
public int getTaskState() { public int getTaskState() {
return mEntity.getState(); return mEntity.getState();
} }
@ -156,86 +148,43 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
} }
/** /**
* 给url请求添加头部 * 检查实体是否合法如果实体合法将保存实体到数据库或更新数据库中的实体对象
* *
* @param key 头部key * @return {@code true} 合法
* @param header 头部value
*/ */
public TARGET addHeader(@NonNull String key, @NonNull String header) { protected abstract boolean checkEntity();
return addHeader(key, header, false);
}
/** protected int checkTaskType() {
* 给url请求添加头部 int taskType = 0;
* if (mTaskEntity instanceof DownloadTaskEntity) {
* @param key 头部key taskType = ICmd.TASK_TYPE_DOWNLOAD;
* @param header 头部value } else if (mTaskEntity instanceof DownloadGroupTaskEntity) {
* @param refreshHeader 更新数据库中保存的头部信息 taskType = ICmd.TASK_TYPE_DOWNLOAD_GROUP;
*/ } else if (mTaskEntity instanceof UploadTaskEntity) {
public TARGET addHeader(@NonNull String key, @NonNull String header, boolean refreshHeader) { taskType = ICmd.TASK_TYPE_UPLOAD;
mTaskEntity.headers.put(key, header);
if (refreshHeader) {
mTaskEntity.update();
} }
return (TARGET) this; return taskType;
} }
/** /**
* 给url请求添加头部 * 保存修改
*/ */
public TARGET addHeaders(Map<String, String> headers) { public void save() {
return addHeaders(headers, false); if (!checkEntity()) {
} ALog.e(TAG, "保存修改失败");
/**
* 给url请求添加头部
*
* @param refreshHeader 更新数据库中保存的头部信息
*/
public TARGET addHeaders(Map<String, String> headers, boolean refreshHeader) {
if (headers != null && headers.size() > 0) {
Set<String> keys = headers.keySet();
for (String key : keys) {
mTaskEntity.headers.put(key, headers.get(key));
}
}
if (refreshHeader) {
mTaskEntity.update();
} }
return (TARGET) this;
}
/**
* 设置请求类型POST或GET默认为在GET
* 只试用于HTTP请求
*
* @param requestEnum {@link RequestEnum}
*/
public TARGET setRequestMode(RequestEnum requestEnum) {
mTaskEntity.requestEnum = requestEnum;
return (TARGET) this;
} }
/** /**
* 开始任务 * 开始任务
*/ */
@Override public void start() { @Override public void start() {
AriaManager.getInstance(AriaManager.APP) if (checkEntity()) {
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START, AriaManager.getInstance(AriaManager.APP)
checkTaskType())) .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START,
.exe(); checkTaskType()))
} .exe();
protected int checkTaskType() {
int taskType = 0;
if (mTaskEntity instanceof DownloadTaskEntity) {
taskType = ICmd.TASK_TYPE_DOWNLOAD;
} else if (mTaskEntity instanceof DownloadGroupTaskEntity) {
taskType = ICmd.TASK_TYPE_DOWNLOAD_GROUP;
} else if (mTaskEntity instanceof UploadTaskEntity) {
taskType = ICmd.TASK_TYPE_UPLOAD;
} }
return taskType;
} }
/** /**
@ -244,47 +193,58 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
* @see #stop() * @see #stop()
*/ */
@Deprecated public void pause() { @Deprecated public void pause() {
stop(); if (checkEntity()) {
stop();
}
} }
@Override public void stop() { @Override public void stop() {
AriaManager.getInstance(AriaManager.APP) if (checkEntity()) {
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP, AriaManager.getInstance(AriaManager.APP)
checkTaskType())) .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP,
.exe(); checkTaskType()))
.exe();
}
} }
/** /**
* 恢复任务 * 恢复任务
*/ */
@Override public void resume() { @Override public void resume() {
AriaManager.getInstance(AriaManager.APP) if (checkEntity()) {
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START, AriaManager.getInstance(AriaManager.APP)
checkTaskType())) .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START,
.exe(); checkTaskType()))
.exe();
}
} }
/** /**
* 删除任务 * 删除任务
*/ */
@Override public void cancel() { @Override public void cancel() {
AriaManager.getInstance(AriaManager.APP) if (checkEntity()) {
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL, AriaManager.getInstance(AriaManager.APP)
checkTaskType())) .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL,
.exe(); checkTaskType()))
.exe();
}
} }
/** /**
* 重试下载 * 任务重试
*/ */
public void reTry() { public void reTry() {
List<ICmd> cmds = new ArrayList<>(); if (checkEntity()) {
int taskType = checkTaskType(); List<ICmd> cmds = new ArrayList<>();
cmds.add( int taskType = checkTaskType();
CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP, taskType)); cmds.add(
cmds.add(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START, CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP,
taskType)); taskType));
AriaManager.getInstance(AriaManager.APP).setCmds(cmds).exe(); cmds.add(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START,
taskType));
AriaManager.getInstance(AriaManager.APP).setCmds(cmds).exe();
}
} }
/** /**
@ -294,35 +254,21 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
* {@code false}如果任务已经完成只删除任务数据库记录 * {@code false}如果任务已经完成只删除任务数据库记录
*/ */
public void cancel(boolean removeFile) { public void cancel(boolean removeFile) {
CancelCmd cancelCmd = (CancelCmd) CommonUtil.createNormalCmd(mTargetName, mTaskEntity, if (checkEntity()) {
NormalCmdFactory.TASK_CANCEL, checkTaskType()); CancelCmd cancelCmd = (CancelCmd) CommonUtil.createNormalCmd(mTargetName, mTaskEntity,
cancelCmd.removeFile = removeFile; NormalCmdFactory.TASK_CANCEL, checkTaskType());
AriaManager.getInstance(AriaManager.APP).setCmd(cancelCmd).exe(); cancelCmd.removeFile = removeFile;
AriaManager.getInstance(AriaManager.APP).setCmd(cancelCmd).exe();
}
} }
/** /**
* 创建文件名如果url链接有后缀名则使用url中的后缀名 * 重新下载
*
* @return url hashKey
*/ */
protected String createFileName(String url) { public void reStart() {
int end = url.indexOf("?"); if (checkEntity()) {
String tempUrl, fileName = ""; cancel();
if (end > 0) { start();
tempUrl = url.substring(0, end);
int tempEnd = tempUrl.lastIndexOf("/");
if (tempEnd > 0) {
fileName = tempUrl.substring(tempEnd + 1, tempUrl.length());
}
} else {
int tempEnd = url.lastIndexOf("/");
if (tempEnd > 0) {
fileName = url.substring(tempEnd + 1, url.length());
}
}
if (TextUtils.isEmpty(fileName)) {
fileName = CommonUtil.keyToHashKey(url);
} }
return fileName;
} }
} }

@ -18,8 +18,7 @@ package com.arialyy.aria.core.inf;
import com.arialyy.aria.core.FtpUrlEntity; import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.Ignore; import com.arialyy.aria.orm.annotation.Ignore;
import com.arialyy.aria.orm.Primary;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -55,103 +54,75 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
*/ */
public static final int U_FTP = 0xA2; public static final int U_FTP = 0xA2;
/**
* Task实体对应的key
*/
@Primary public String key = "";
/** /**
* 账号和密码 * 账号和密码
*/ */
@Ignore public FtpUrlEntity urlEntity; @Ignore private FtpUrlEntity urlEntity;
/** /**
* 刷新信息 {@code true} 重新刷新下载信息 * 刷新信息 {@code true} 重新刷新下载信息
*/ */
@Ignore public boolean refreshInfo = false; @Ignore private boolean refreshInfo = false;
/** /**
* 是否是新任务{@code true} 新任务 * 是否是新任务{@code true} 新任务
*/ */
@Ignore public boolean isNewTask = false; @Ignore private boolean isNewTask = false;
/** /**
* 任务状态和Entity的state同步 * 任务状态和Entity的state同步
*/ */
public int state = IEntity.STATE_WAIT; private int state = IEntity.STATE_WAIT;
/** /**
* 请求类型 * 请求类型
* {@link AbsTaskEntity#D_HTTP}{@link AbsTaskEntity#D_FTP}{@link AbsTaskEntity#D_FTP_DIR} * {@link AbsTaskEntity#D_HTTP}{@link AbsTaskEntity#D_FTP}{@link AbsTaskEntity#D_FTP_DIR}
*/ */
public int requestType = D_HTTP; private int requestType = D_HTTP;
/** /**
* http 请求头 * http 请求头
*/ */
public Map<String, String> headers = new HashMap<>(); private Map<String, String> headers = new HashMap<>();
/** /**
* 字符编码默认为"utf-8" * 字符编码默认为"utf-8"
*/ */
public String charSet = "utf-8"; private String charSet = "utf-8";
/** /**
* 网络请求类型 * 网络请求类型
*/ */
public RequestEnum requestEnum = RequestEnum.GET; private RequestEnum requestEnum = RequestEnum.GET;
/** /**
* 从header中含有的文件md5码信息所需要的key * 是否使用服务器通过content-disposition传递的文件名内容格式{@code attachment; filename="filename.jpg"}
*/
public String md5Key = "Content-MD5";
/**
* 是否使用服务器通过content-disposition传递的文件名内容格式{@code attachment;filename=***}
* {@code true} 使用 * {@code true} 使用
*/ */
public boolean useServerFileName = false; private boolean useServerFileName = false;
/**
* 从header中获取文件描述信息所需要的key
*/
public String dispositionKey = "Content-Disposition";
/**
* 重定向后从header中获取新url所需要的key
*/
public String redirectUrlKey = "location";
/**
* 从Disposition获取的文件名说需要的key
*/
public String dispositionFileKey = "attachment;filename";
/**
* 从header中含有的文件长度信息所需要的key
*/
public String contentLength = "Content-Length";
/** /**
* 重定向链接 * 重定向链接
*/ */
public String redirectUrl = ""; private String redirectUrl = "";
/** /**
* 删除任务时是否删除已下载完成的文件
* 未完成的任务不管true还是false都会删除文件
* {@code true} 删除任务数据库记录并且删除已经下载完成的文件 * {@code true} 删除任务数据库记录并且删除已经下载完成的文件
* {@code false} 如果任务已经完成只删除任务数据库记录 * {@code false} 如果任务已经完成只删除任务数据库记录
*/ */
@Ignore public boolean removeFile = false; @Ignore private boolean removeFile = false;
/** /**
* 是否支持断点, {@code true} 为支持断点 * 是否支持断点, {@code true} 为支持断点
*/ */
public boolean isSupportBP = true; private boolean isSupportBP = true;
/** /**
* 状态码 * 状态码
*/ */
public int code; private int code;
public abstract ENTITY getEntity(); public abstract ENTITY getEntity();
@ -164,12 +135,7 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
return getEntity().getState(); return getEntity().getState();
} }
@Override public void deleteData() { public abstract String getKey();
if (getEntity() != null) {
getEntity().deleteData();
}
super.deleteData();
}
@Override public void update() { @Override public void update() {
if (getEntity() != null) { if (getEntity() != null) {
@ -177,4 +143,104 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
} }
super.update(); super.update();
} }
public FtpUrlEntity getUrlEntity() {
return urlEntity;
}
public void setUrlEntity(FtpUrlEntity urlEntity) {
this.urlEntity = urlEntity;
}
public boolean isRefreshInfo() {
return refreshInfo;
}
public void setRefreshInfo(boolean refreshInfo) {
this.refreshInfo = refreshInfo;
}
public boolean isNewTask() {
return isNewTask;
}
public void setNewTask(boolean newTask) {
isNewTask = newTask;
}
public void setState(int state) {
this.state = state;
}
public int getRequestType() {
return requestType;
}
public void setRequestType(int requestType) {
this.requestType = requestType;
}
public Map<String, String> getHeaders() {
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
public String getCharSet() {
return charSet;
}
public void setCharSet(String charSet) {
this.charSet = charSet;
}
public RequestEnum getRequestEnum() {
return requestEnum;
}
public void setRequestEnum(RequestEnum requestEnum) {
this.requestEnum = requestEnum;
}
public boolean isUseServerFileName() {
return useServerFileName;
}
public void setUseServerFileName(boolean useServerFileName) {
this.useServerFileName = useServerFileName;
}
public String getRedirectUrl() {
return redirectUrl;
}
public void setRedirectUrl(String redirectUrl) {
this.redirectUrl = redirectUrl;
}
public boolean isRemoveFile() {
return removeFile;
}
public void setRemoveFile(boolean removeFile) {
this.removeFile = removeFile;
}
public boolean isSupportBP() {
return isSupportBP;
}
public void setSupportBP(boolean supportBP) {
isSupportBP = supportBP;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
} }

@ -1,65 +0,0 @@
/*
* 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.inf;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTask;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.CheckUtil;
/**
* Created by AriaL on 2017/6/29.
* 任务组超类
*/
public abstract class AbsUploadTarget<TARGET extends AbsUploadTarget, ENTITY extends UploadEntity, TASK_ENTITY extends UploadTaskEntity>
extends AbsTarget<TARGET, ENTITY, TASK_ENTITY> {
/**
* 设置上传路径
*
* @param uploadUrl 上传路径
*/
public TARGET setUploadUrl(@NonNull String uploadUrl) {
uploadUrl = CheckUtil.checkUrl(uploadUrl);
if (mEntity.getUrl().equals(uploadUrl)) return (TARGET) this;
mEntity.setUrl(uploadUrl);
mEntity.update();
return (TARGET) this;
}
/**
* 下载任务是否存在
*/
@Override public boolean taskExists() {
return UploadTaskQueue.getInstance().getTask(mEntity.getFilePath()) != null;
}
/**
* 是否在下载
*
* @deprecated {@link #isRunning()}
*/
public boolean isUploading() {
return isRunning();
}
@Override public boolean isRunning() {
UploadTask task = UploadTaskQueue.getInstance().getTask(mEntity.getKey());
return task != null && task.isRunning();
}
}

@ -15,7 +15,7 @@
*/ */
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.inf;
import com.arialyy.aria.orm.Ignore; import com.arialyy.aria.orm.annotation.Ignore;
/** /**
* Created by lyy on 2017/2/23. * Created by lyy on 2017/2/23.
@ -42,7 +42,7 @@ public interface IEntity {
*/ */
@Ignore int STATE_WAIT = 3; @Ignore int STATE_WAIT = 3;
/** /**
* 下载中 * 正在执行
*/ */
@Ignore int STATE_RUNNING = 4; @Ignore int STATE_RUNNING = 4;
/** /**
@ -54,7 +54,7 @@ public interface IEntity {
*/ */
@Ignore int STATE_POST_PRE = 6; @Ignore int STATE_POST_PRE = 6;
/** /**
* 取消下载 * 删除任务
*/ */
@Ignore int STATE_CANCEL = 7; @Ignore int STATE_CANCEL = 7;
} }

@ -0,0 +1,43 @@
/*
* 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.inf;
/**
* Created by laoyuyu on 2018/3/9.
*/
public interface IFtpTarget<TARGET extends ITarget> {
/**
* 设置字符编码
*/
TARGET charSet(String charSet);
/**
* ftp 用户登录信
*
* @param userName ftp用户名
* @param password ftp用户密码
*/
TARGET login(String userName, String password);
/**
* ftp 用户登录信息
*
* @param userName ftp用户名
* @param password ftp用户密码
* @param account ftp账号
*/
TARGET login(String userName, String password, String account);
}

@ -0,0 +1,52 @@
/*
* 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.inf;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.download.DownloadEntity;
import java.util.Map;
/**
* Created by laoyuyu on 2018/3/9.
* HTTP Header功能接口
*/
public interface IHttpHeaderTarget<TARGET extends ITarget> {
/**
* 给url请求添加Header数据
* 如果新的header数据和数据保存的不一致则更新数据库中对应的header数据
*
* @param key header对应的key
* @param value header对应的value
*/
TARGET addHeader(@NonNull String key, @NonNull String value);
/**
* 给url请求添加一组header数据
* 如果新的header数据和数据保存的不一致则更新数据库中对应的header数据
*
* @param headers 一组http header数据
*/
TARGET addHeaders(Map<String, String> headers);
/**
* 设置HTTP请求类型
*
* @param requestEnum {@link RequestEnum}
*/
TARGET setRequestMode(RequestEnum requestEnum);
}

@ -15,53 +15,50 @@
*/ */
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.inf;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.common.RequestEnum;
import java.util.Map;
/** /**
* Created by AriaL on 2017/6/29. * Created by AriaL on 2017/6/29.
*/ */
public interface ITarget<TARGET extends ITarget> { public interface ITarget<TARGET extends ITarget> {
/** /**
* 任务文件大小 * 获取任务状态
*
* @return {@link IEntity}
*/ */
long getSize(); int getTaskState();
/** /**
* 转换后的大小 * 任务是否在执行
*
* @return {@code true} 任务正在执行
*/ */
String getConvertSize(); boolean isRunning();
/** /**
* 获取任务进度百分比 * 任务是否存在
*
* @return {@code true} 任务存在
*/ */
int getPercent(); boolean taskExists();
/** /**
* 获取任务进度如果任务存在则返回当前进度 * 任务文件大小
*/ */
long getCurrentProgress(); long getSize();
/** /**
* 给url请求添加头部 * 转换后的大小
*
* @param key 头部key
* @param header 头部value
*/ */
TARGET addHeader(@NonNull String key, @NonNull String header) ; String getConvertSize();
/** /**
* 给url请求添加头部 * 获取任务进度百分比
*/ */
TARGET addHeaders(Map<String, String> headers); int getPercent();
/** /**
* 设置请求类型 * 获取任务进度如果任务存在则返回当前进度
*
* @param requestEnum {@link RequestEnum}
*/ */
TARGET setRequestMode(RequestEnum requestEnum); long getCurrentProgress();
/** /**
* 开始下载 * 开始下载
@ -82,5 +79,4 @@ public interface ITarget<TARGET extends ITarget> {
* 取消下载 * 取消下载
*/ */
void cancel(); void cancel();
} }

@ -15,8 +15,6 @@
*/ */
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.inf;
import com.arialyy.aria.core.inf.IEventListener;
/** /**
* Created by lyy on 2017/2/9. * Created by lyy on 2017/2/9.
* 上传监听 * 上传监听

@ -0,0 +1,169 @@
/*
* 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.manager;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.download.wrapper.DGEWrapper;
import com.arialyy.aria.core.download.wrapper.DGTEWrapper;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Aria.Lao on 2017/11/1.
* 任务实体工厂
*/
class DGTEFactory implements IGTEFactory<DownloadGroupEntity, DownloadGroupTaskEntity> {
private static final String TAG = "DTEFactory";
private static volatile DGTEFactory INSTANCE = null;
private DGTEFactory() {
}
public static DGTEFactory getInstance() {
if (INSTANCE == null) {
synchronized (DGTEFactory.class) {
INSTANCE = new DGTEFactory();
}
}
return INSTANCE;
}
@Override public DownloadGroupTaskEntity getGTE(String groupName, List<String> urls) {
DownloadGroupEntity entity = createDGroupEntity(groupName, urls);
List<DGTEWrapper> wrapper =
DbEntity.findRelationData(DGTEWrapper.class, "DownloadGroupTaskEntity.key=?",
entity.getGroupName());
DownloadGroupTaskEntity gte;
if (wrapper != null && !wrapper.isEmpty()) {
gte = wrapper.get(0).taskEntity;
if (gte == null) {
// 创建新的任务组任务实体
gte = new DownloadGroupTaskEntity();
//创建子任务的任务实体
gte.setSubTaskEntities(createDGSubTaskEntity(entity));
} else if (gte.getSubTaskEntities() == null || gte.getSubTaskEntities().isEmpty()) {
gte.setSubTaskEntities(createDGSubTaskEntity(entity));
}
} else {
gte = new DownloadGroupTaskEntity();
gte.setSubTaskEntities(createDGSubTaskEntity(entity));
}
gte.setKey(entity.getGroupName());
gte.setEntity(entity);
return gte;
}
@Override public DownloadGroupTaskEntity getFTE(String ftpUrl) {
List<DGTEWrapper> wrapper =
DbEntity.findRelationData(DGTEWrapper.class, "DownloadGroupTaskEntity.key=?",
ftpUrl);
DownloadGroupTaskEntity fte;
if (wrapper != null && !wrapper.isEmpty()) {
fte = wrapper.get(0).taskEntity;
if (fte == null) {
fte = new DownloadGroupTaskEntity();
DownloadGroupEntity dge = new DownloadGroupEntity();
dge.setGroupName(ftpUrl);
fte.setEntity(dge);
} else if (fte.getEntity() == null) {
DownloadGroupEntity dge = new DownloadGroupEntity();
dge.setGroupName(ftpUrl);
fte.setEntity(dge);
}
} else {
fte = new DownloadGroupTaskEntity();
DownloadGroupEntity dge = new DownloadGroupEntity();
dge.setGroupName(ftpUrl);
fte.setEntity(dge);
}
fte.setKey(ftpUrl);
fte.setUrlEntity(CommonUtil.getFtpUrlInfo(ftpUrl));
if (fte.getEntity().getSubEntities() == null) {
fte.getEntity().setSubEntities(new ArrayList<DownloadEntity>());
}
if (fte.getSubTaskEntities() == null) {
fte.setSubTaskEntities(new ArrayList<DownloadTaskEntity>());
}
return fte;
}
/**
* 创建任务组子任务的任务实体
*/
private List<DownloadTaskEntity> createDGSubTaskEntity(DownloadGroupEntity dge) {
List<DownloadTaskEntity> list = new ArrayList<>();
for (DownloadEntity entity : dge.getSubEntities()) {
DownloadTaskEntity taskEntity = new DownloadTaskEntity();
taskEntity.setEntity(entity);
taskEntity.setKey(entity.getDownloadPath());
taskEntity.setGroupName(dge.getKey());
taskEntity.setGroupTask(true);
taskEntity.setUrl(entity.getUrl());
list.add(taskEntity);
}
return list;
}
/**
* 查询任务组实体如果数据库不存在该实体则新创建一个新的任务组实体
*/
private DownloadGroupEntity createDGroupEntity(String groupName, List<String> urls) {
List<DGEWrapper> wrapper =
DbEntity.findRelationData(DGEWrapper.class, "DownloadGroupEntity.groupName=?",
groupName);
DownloadGroupEntity groupEntity;
if (wrapper != null && !wrapper.isEmpty()) {
groupEntity = wrapper.get(0).groupEntity;
if (groupEntity == null) {
groupEntity = new DownloadGroupEntity();
groupEntity.setSubEntities(createSubTask(groupName, urls));
}
} else {
groupEntity = new DownloadGroupEntity();
groupEntity.setSubEntities(createSubTask(groupName, urls));
}
groupEntity.setGroupName(groupName);
groupEntity.setUrls(urls);
return groupEntity;
}
/**
* 创建子任务
*/
private List<DownloadEntity> createSubTask(String groupName, List<String> urls) {
List<DownloadEntity> list = new ArrayList<>();
for (int i = 0, len = urls.size(); i < len; i++) {
DownloadEntity entity = new DownloadEntity();
entity.setUrl(urls.get(i));
entity.setDownloadPath(groupName + "_" + i);
entity.setFileName(groupName + "_" + i);
entity.setGroupName(groupName);
entity.setGroupChild(true);
list.add(entity);
}
return list;
}
}

@ -1,98 +0,0 @@
/*
* 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.manager;
import android.text.TextUtils;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil;
import java.util.List;
/**
* Created by Aria.Lao on 2017/11/1.
* 任务实体工厂
*/
class DGTEntityFactory implements ITEntityFactory<DownloadGroupEntity, DownloadGroupTaskEntity>,
IGTEntityFactory<DownloadGroupEntity, DownloadGroupTaskEntity> {
private static final String TAG = "DTEntityFactory";
private static volatile DGTEntityFactory INSTANCE = null;
private DGTEntityFactory() {
}
public static DGTEntityFactory getInstance() {
if (INSTANCE == null) {
synchronized (DGTEntityFactory.class) {
INSTANCE = new DGTEntityFactory();
}
}
return INSTANCE;
}
/**
* 通过下载实体创建任务实体
*/
@Override public DownloadGroupTaskEntity create(DownloadGroupEntity entity) {
DownloadGroupTaskEntity dgTaskEntity =
DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", entity.getGroupName());
if (dgTaskEntity == null) {
dgTaskEntity = new DownloadGroupTaskEntity();
dgTaskEntity.save(entity);
}
if (dgTaskEntity.entity == null || TextUtils.isEmpty(dgTaskEntity.entity.getKey())) {
dgTaskEntity.save(entity);
}
return dgTaskEntity;
}
/**
* 对于任务组不能使用这个可用于FTP文件夹下载
*
* @deprecated {@link #create(String, List)}
*/
@Override @Deprecated public DownloadGroupTaskEntity create(String key) {
DownloadGroupTaskEntity dgTaskEntity =
DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", key);
if (dgTaskEntity == null) {
dgTaskEntity = new DownloadGroupTaskEntity();
dgTaskEntity.save(getDownloadGroupEntity(key, null));
}
if (dgTaskEntity.entity == null || TextUtils.isEmpty(dgTaskEntity.entity.getKey())) {
dgTaskEntity.save(getDownloadGroupEntity(key, null));
}
dgTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(key);
return dgTaskEntity;
}
@Override public DownloadGroupTaskEntity create(String groupName, List<String> urls) {
return create(getDownloadGroupEntity(groupName, urls));
}
/**
* 查询任务组实体如果数据库不存在该实体则新创建一个新的任务组实体
*/
private DownloadGroupEntity getDownloadGroupEntity(String groupName, List<String> urls) {
DownloadGroupEntity entity =
DbEntity.findFirst(DownloadGroupEntity.class, "groupName=?", groupName);
if (entity == null) {
entity = new DownloadGroupEntity();
entity.setGroupName(groupName);
entity.setUrls(urls);
}
return entity;
}
}

@ -18,25 +18,28 @@ package com.arialyy.aria.core.manager;
import android.text.TextUtils; import android.text.TextUtils;
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.download.DownloadTaskEntity;
import com.arialyy.aria.core.download.wrapper.DTEWrapper;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import java.io.File; import java.io.File;
import java.util.List;
import java.util.UUID;
/** /**
* Created by Aria.Lao on 2017/11/1. * Created by Aria.Lao on 2017/11/1.
* 任务实体工厂 * 任务实体工厂
*/ */
class DTEntityFactory implements ITEntityFactory<DownloadEntity, DownloadTaskEntity> { class DTEFactory implements INormalTEFactory<DownloadEntity, DownloadTaskEntity> {
private static final String TAG = "DTEntityFactory"; private static final String TAG = "DTEFactory";
private static volatile DTEntityFactory INSTANCE = null; private static volatile DTEFactory INSTANCE = null;
private DTEntityFactory() { private DTEFactory() {
} }
public static DTEntityFactory getInstance() { public static DTEFactory getInstance() {
if (INSTANCE == null) { if (INSTANCE == null) {
synchronized (DTEntityFactory.class) { synchronized (DTEFactory.class) {
INSTANCE = new DTEntityFactory(); INSTANCE = new DTEFactory();
} }
} }
return INSTANCE; return INSTANCE;
@ -45,18 +48,24 @@ class DTEntityFactory implements ITEntityFactory<DownloadEntity, DownloadTaskEnt
/** /**
* 通过下载实体创建任务实体 * 通过下载实体创建任务实体
*/ */
@Override public DownloadTaskEntity create(DownloadEntity entity) { private DownloadTaskEntity create(DownloadEntity entity) {
DownloadTaskEntity taskEntity = List<DTEWrapper> wrapper = DbEntity.findRelationData(DTEWrapper.class,
DbEntity.findFirst(DownloadTaskEntity.class, "key=? and isGroupTask='false' and url=?", "DownloadTaskEntity.key=? and DownloadTaskEntity.isGroupTask='false' and DownloadTaskEntity.url=?",
entity.getDownloadPath(), entity.getUrl()); entity.getDownloadPath(), entity.getUrl());
if (taskEntity == null) { DownloadTaskEntity taskEntity;
if (wrapper != null && !wrapper.isEmpty()) {
taskEntity = wrapper.get(0).taskEntity;
if (taskEntity == null) {
taskEntity = new DownloadTaskEntity();
} else if (taskEntity.getEntity() == null || TextUtils.isEmpty(taskEntity.getEntity().getUrl())) {
taskEntity.setEntity(entity);
}
} else {
taskEntity = new DownloadTaskEntity(); taskEntity = new DownloadTaskEntity();
taskEntity.save(entity);
} else if (taskEntity.entity == null || TextUtils.isEmpty(taskEntity.entity.getUrl())) {
taskEntity.save(entity);
} else if (!taskEntity.entity.getUrl().equals(entity.getUrl())) { //处理地址切换而保存路径不变
taskEntity.save(entity);
} }
taskEntity.setKey(entity.getDownloadPath());
taskEntity.setUrl(entity.getUrl());
taskEntity.setEntity(entity);
return taskEntity; return taskEntity;
} }
@ -80,6 +89,8 @@ class DTEntityFactory implements ITEntityFactory<DownloadEntity, DownloadTaskEnt
entity = new DownloadEntity(); entity = new DownloadEntity();
entity.setUrl(downloadUrl); entity.setUrl(downloadUrl);
entity.setGroupChild(false); entity.setGroupChild(false);
entity.setGroupName(null);
entity.setDownloadPath(UUID.randomUUID().toString().replace("-", "")); //设置临时路径
} }
File file = new File(entity.getDownloadPath()); File file = new File(entity.getDownloadPath());
if (!file.exists()) { if (!file.exists()) {

@ -0,0 +1,46 @@
/*
* 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.manager;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import java.util.List;
/**
* 任务组通过组创建任务
* Created by Aria.Lao on 2017/11/1.
*/
interface IGTEFactory<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>> {
/**
* 获取任务组的任务实体
* 1创建实体和任务实体之间的关联
* 2如果在数据库中查找不到对应的数据则新创建任务实体
*
* @param groupName 任务组名
* @param urls 子任务的下载地址
*/
TASK_ENTITY getGTE(String groupName, List<String> urls);
/**
* 获取FTP文件夹的任务实体该方法需要以下操作
* 1创建实体和任务实体之间的关联
* 2如果在数据库中查找不到对应的数据则新创建任务实体
*
* @param ftpUrl ftp文件夹下载路径
*/
TASK_ENTITY getFTE(String ftpUrl);
}

@ -21,11 +21,7 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
/** /**
* Created by Aria.Lao on 2017/11/1. * Created by Aria.Lao on 2017/11/1.
*/ */
interface ITEntityFactory<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>> { interface INormalTEFactory<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>> {
/**
* 通过信息实体创建任务实体
*/
TASK_ENTITY create(ENTITY entity);
/** /**
* 通过key创建任务只适应于单任务 * 通过key创建任务只适应于单任务

@ -18,7 +18,6 @@ package com.arialyy.aria.core.manager;
import android.support.v4.util.LruCache; import android.support.v4.util.LruCache;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
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;
@ -29,7 +28,7 @@ import java.util.concurrent.locks.ReentrantLock;
/** /**
* Created by Aria.Lao on 2017/11/1. * Created by Aria.Lao on 2017/11/1.
* 任务实体管理器负责 * 任务实体管理器
*/ */
public class TEManager { public class TEManager {
private static final String TAG = "TaskManager"; private static final String TAG = "TaskManager";
@ -51,18 +50,17 @@ public class TEManager {
} }
/** /**
* 通过key创建任务只适应于单任务不能用于HTTP任务组可用于Ftp文件夹 * 通过key创建任务只适应于单任务
* 如果是任务组请使用{@link #createGTEntity(Class, List)}
* *
* @return 如果任务实体创建失败返回null * @return 如果任务实体创建失败返回null
*/ */
public <TE extends AbsTaskEntity> TE createTEntity(Class<TE> clazz, String key) { private <TE extends AbsTaskEntity> TE createNormalTE(Class<TE> clazz, String key) {
final Lock lock = this.lock; final Lock lock = this.lock;
lock.lock(); lock.lock();
try { try {
AbsTaskEntity tEntity = cache.get(convertKey(key)); AbsTaskEntity tEntity = cache.get(convertKey(key));
if (tEntity == null || tEntity.getClass() != clazz) { if (tEntity == null || tEntity.getClass() != clazz) {
ITEntityFactory factory = chooseFactory(clazz); INormalTEFactory factory = chooseNormalFactory(clazz);
if (factory == null) { if (factory == null) {
ALog.e(TAG, "任务实体创建失败"); ALog.e(TAG, "任务实体创建失败");
return null; return null;
@ -77,23 +75,44 @@ public class TEManager {
} }
/** /**
* 创建任务实体 * 通过key创建不需要缓存的任务实体只适应于单任务
* *
* @return 如果任务实体创建失败返回null * @return 如果任务实体创建失败返回null
*/ */
public <TE extends AbsTaskEntity> TE createGTEntity(Class<TE> clazz, List<String> urls) { public <TE extends AbsTaskEntity> TE createNormalNoCacheTE(Class<TE> clazz, String key) {
final Lock lock = this.lock;
lock.lock();
try {
INormalTEFactory factory = chooseNormalFactory(clazz);
if (factory == null) {
ALog.e(TAG, "任务实体创建失败");
return null;
}
AbsTaskEntity tEntity = factory.create(key);
return (TE) tEntity;
} finally {
lock.unlock();
}
}
/**
* 创建任务组
*
* @return 如果任务实体创建失败返回null
*/
private <TE extends AbsTaskEntity> TE createGTEntity(Class<TE> clazz, List<String> urls) {
final Lock lock = this.lock; final Lock lock = this.lock;
lock.lock(); lock.lock();
try { try {
String groupName = CommonUtil.getMd5Code(urls); String groupName = CommonUtil.getMd5Code(urls);
AbsTaskEntity tEntity = cache.get(convertKey(groupName)); AbsTaskEntity tEntity = cache.get(convertKey(groupName));
if (tEntity == null || tEntity.getClass() != clazz) { if (tEntity == null || tEntity.getClass() != clazz) {
IGTEntityFactory factory = chooseGroupFactory(clazz); IGTEFactory factory = chooseGroupFactory(clazz);
if (factory == null) { if (factory == null) {
ALog.e(TAG, "任务实体创建失败"); ALog.e(TAG, "任务实体创建失败");
return null; return null;
} }
tEntity = factory.create(groupName, urls); tEntity = factory.getGTE(groupName, urls);
cache.put(convertKey(groupName), tEntity); cache.put(convertKey(groupName), tEntity);
} }
return (TE) tEntity; return (TE) tEntity;
@ -103,23 +122,23 @@ public class TEManager {
} }
/** /**
* 通过实体创建任务 * 通过ftp文件夹路径创建FTP文件夹实体
* *
* @return 如果任务实体创建失败返回null * @return 如果任务实体创建失败返回null
*/ */
public <TE extends AbsTaskEntity> TE createTEntity(Class<TE> clazz, AbsEntity absEntity) { private <TE extends AbsTaskEntity> TE createFDTE(Class<TE> clazz, String key) {
final Lock lock = this.lock; final Lock lock = this.lock;
lock.lock(); lock.lock();
try { try {
AbsTaskEntity tEntity = cache.get(convertKey(absEntity.getKey())); AbsTaskEntity tEntity = cache.get(convertKey(key));
if (tEntity == null || tEntity.getClass() != clazz) { if (tEntity == null || tEntity.getClass() != clazz) {
ITEntityFactory factory = chooseFactory(clazz); IGTEFactory factory = chooseGroupFactory(clazz);
if (factory == null) { if (factory == null) {
ALog.e(TAG, "任务实体创建失败"); ALog.e(TAG, "任务实体创建失败");
return null; return null;
} }
tEntity = factory.create(absEntity); tEntity = factory.getFTE(key);
cache.put(convertKey(absEntity.getKey()), tEntity); cache.put(convertKey(key), tEntity);
} }
return (TE) tEntity; return (TE) tEntity;
} finally { } finally {
@ -127,26 +146,26 @@ public class TEManager {
} }
} }
private IGTEntityFactory chooseGroupFactory(Class clazz) { private IGTEFactory chooseGroupFactory(Class clazz) {
if (clazz == DownloadGroupTaskEntity.class) { if (clazz == DownloadGroupTaskEntity.class) {
return DGTEntityFactory.getInstance(); return DGTEFactory.getInstance();
} }
return null; return null;
} }
private ITEntityFactory chooseFactory(Class clazz) { private INormalTEFactory chooseNormalFactory(Class clazz) {
if (clazz == DownloadTaskEntity.class) { if (clazz == DownloadTaskEntity.class) {
return DTEntityFactory.getInstance(); return DTEFactory.getInstance();
} else if (clazz == UploadTaskEntity.class) { } else if (clazz == UploadTaskEntity.class) {
return UTEntityFactory.getInstance(); return UTEFactory.getInstance();
} else if (clazz == DownloadGroupTaskEntity.class) {
return DGTEntityFactory.getInstance();
} }
return null; return null;
} }
/** /**
* 从任务实体管理器中获取任务实体 * 从缓存中获取单任务实体如果任务实体不存在则创建任务实体
*
* @return 创建失败返回null
*/ */
public <TE extends AbsTaskEntity> TE getTEntity(Class<TE> clazz, String key) { public <TE extends AbsTaskEntity> TE getTEntity(Class<TE> clazz, String key) {
final Lock lock = this.lock; final Lock lock = this.lock;
@ -154,7 +173,53 @@ public class TEManager {
try { try {
AbsTaskEntity tEntity = cache.get(convertKey(key)); AbsTaskEntity tEntity = cache.get(convertKey(key));
if (tEntity == null) { if (tEntity == null) {
return null; return createNormalTE(clazz, key);
} else {
return (TE) tEntity;
}
} finally {
lock.unlock();
}
}
/**
* 从缓存中获取FTP文件夹任务实体如果任务实体不存在则创建任务实体
*
* @return 创建失败返回null
*/
public <TE extends AbsTaskEntity> TE getFDTEntity(Class<TE> clazz, String key) {
final Lock lock = this.lock;
lock.lock();
try {
AbsTaskEntity tEntity = cache.get(convertKey(key));
if (tEntity == null) {
return createFDTE(clazz, key);
} else {
return (TE) tEntity;
}
} finally {
lock.unlock();
}
}
/**
* 从缓存中获取HTTP任务组的任务实体如果任务实体不存在则创建任务实体
*
* @param urls HTTP任务组的子任务下载地址列表
* @return 地址列表为null或创建实体失败返回null
*/
public <TE extends AbsTaskEntity> TE getGTEntity(Class<TE> clazz, List<String> urls) {
if (urls == null || urls.isEmpty()) {
ALog.e(TAG, "获取HTTP任务组实体失败:任务组的子任务下载地址列表为null");
return null;
}
final Lock lock = this.lock;
lock.lock();
try {
String groupName = CommonUtil.getMd5Code(urls);
AbsTaskEntity tEntity = cache.get(convertKey(groupName));
if (tEntity == null) {
return createGTEntity(clazz, urls);
} else { } else {
return (TE) tEntity; return (TE) tEntity;
} }
@ -189,7 +254,7 @@ public class TEManager {
final Lock lock = this.lock; final Lock lock = this.lock;
lock.lock(); lock.lock();
try { try {
return cache.put(convertKey(te.key), te) != null; return cache.put(convertKey(te.getKey()), te) != null;
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@ -210,6 +275,7 @@ public class TEManager {
} }
private String convertKey(String key) { private String convertKey(String key) {
key = key.trim();
final Lock lock = this.lock; final Lock lock = this.lock;
lock.lock(); lock.lock();
try { try {

@ -1,86 +0,0 @@
/*
* 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.manager;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by Aria.Lao on 2017/9/1.
* 任务管理器
*/
class TaskManager {
private static final String TAG = "TaskManager";
private static volatile TaskManager INSTANCE = null;
private Map<String, AbsTask> map = new ConcurrentHashMap<>();
public static TaskManager getInstance() {
if (INSTANCE == null) {
synchronized (TaskManager.class) {
INSTANCE = new TaskManager();
}
}
return INSTANCE;
}
private TaskManager() {
}
/**
* 管理器添加任务
*
* @param key 任务的key下载为保存路径任务组为任务组名上传为文件上传路径
* @param task 任务
* @return {@code true}添加成功
*/
public <T extends AbsTask> boolean addTask(String key, Class<T> clazz, T task) {
String hash = CommonUtil.keyToHashKey(key);
if (map.keySet().contains(hash)) {
ALog.e(TAG, "任务【" + key + "】已存在");
return false;
}
map.put(CommonUtil.keyToHashKey(key), task);
return true;
}
/**
* 移除任务
*
* @param key 任务的key下载为保存路径任务组为任务组名上传为文件上传路径
*/
public void removeTask(String key) {
String hash = CommonUtil.keyToHashKey(key);
for (Iterator<Map.Entry<String, AbsTask>> iter = map.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry<String, AbsTask> entry = iter.next();
if (entry.getKey().equals(hash)) iter.remove();
}
}
/**
* 通过key获取任务
*
* @return 如果找不到任务返回null否则返回key对应的任务
*/
public AbsTask getTask(String key) {
return map.get(CommonUtil.keyToHashKey(key));
}
}

@ -15,43 +15,55 @@
*/ */
package com.arialyy.aria.core.manager; package com.arialyy.aria.core.manager;
import android.text.TextUtils;
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.core.upload.wrapper.UTEWrapper;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.Regular; import com.arialyy.aria.util.Regular;
import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
* Created by Aria.Lao on 2017/11/1. * Created by Aria.Lao on 2017/11/1.
* 任务实体工厂 * 任务实体工厂
*/ */
class UTEntityFactory implements ITEntityFactory<UploadEntity, UploadTaskEntity> { class UTEFactory implements INormalTEFactory<UploadEntity, UploadTaskEntity> {
private static final String TAG = "DTEntityFactory"; private static final String TAG = "DTEFactory";
private static volatile UTEntityFactory INSTANCE = null; private static volatile UTEFactory INSTANCE = null;
private UTEntityFactory() { private UTEFactory() {
} }
public static UTEntityFactory getInstance() { public static UTEFactory getInstance() {
if (INSTANCE == null) { if (INSTANCE == null) {
synchronized (UTEntityFactory.class) { synchronized (UTEFactory.class) {
INSTANCE = new UTEntityFactory(); INSTANCE = new UTEFactory();
} }
} }
return INSTANCE; return INSTANCE;
} }
@Override public UploadTaskEntity create(UploadEntity entity) { private UploadTaskEntity create(UploadEntity entity) {
UploadTaskEntity uTaskEntity = List<UTEWrapper> wrapper =
DbEntity.findFirst(UploadTaskEntity.class, "key=?", entity.getFilePath()); DbEntity.findRelationData(UTEWrapper.class, "UploadTaskEntity.key=?",
if (uTaskEntity == null) { entity.getFilePath());
uTaskEntity = new UploadTaskEntity();
uTaskEntity.entity = entity; if (wrapper != null && !wrapper.isEmpty()) {
} UploadTaskEntity uTaskEntity = wrapper.get(0).taskEntity;
if (uTaskEntity.entity == null) { if (uTaskEntity == null) {
uTaskEntity.entity = entity; uTaskEntity = new UploadTaskEntity();
uTaskEntity.setEntity(entity);
} else if (uTaskEntity.getEntity() == null || TextUtils.isEmpty(
uTaskEntity.getEntity().getFilePath())) {
uTaskEntity.setEntity(entity);
}
return uTaskEntity;
} else {
UploadTaskEntity uTaskEntity = new UploadTaskEntity();
uTaskEntity.setEntity(entity);
return uTaskEntity;
} }
return uTaskEntity;
} }
@Override public UploadTaskEntity create(String key) { @Override public UploadTaskEntity create(String key) {
@ -67,14 +79,12 @@ class UTEntityFactory implements ITEntityFactory<UploadEntity, UploadTaskEntity>
UploadEntity entity = UploadEntity.findFirst(UploadEntity.class, "filePath=?", filePath); UploadEntity entity = UploadEntity.findFirst(UploadEntity.class, "filePath=?", filePath);
if (entity == null) { if (entity == null) {
entity = new UploadEntity(); entity = new UploadEntity();
//String regex = "[/|\\\\|//]";
String regex = Regular.REG_FILE_NAME; String regex = Regular.REG_FILE_NAME;
Pattern p = Pattern.compile(regex); Pattern p = Pattern.compile(regex);
String[] strs = p.split(filePath); String[] strs = p.split(filePath);
String fileName = strs[strs.length - 1]; String fileName = strs[strs.length - 1];
entity.setFileName(fileName); entity.setFileName(fileName);
entity.setFilePath(filePath); entity.setFilePath(filePath);
entity.insert();
} }
return entity; return entity;
} }

@ -150,10 +150,10 @@ abstract class AbsTaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
} }
} }
@Override public TASK getTask(String url) { @Override public TASK getTask(String key) {
TASK task = mExecutePool.getTask(url); TASK task = mExecutePool.getTask(key);
if (task == null) { if (task == null) {
task = mCachePool.getTask(url); task = mCachePool.getTask(key);
} }
return task; return task;
} }
@ -202,6 +202,7 @@ abstract class AbsTaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
if (!task.isRunning()) { if (!task.isRunning()) {
task.start(); task.start();
} else { } else {
task.stop();
ALog.e(TAG, "任务【" + task.getTaskName() + "】重试失败,原因:任务没有完全停止,"); ALog.e(TAG, "任务【" + task.getTaskName() + "】重试失败,原因:任务没有完全停止,");
} }
} }

@ -67,7 +67,7 @@ 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.key = entity.getEntity().getGroupName(); entity.setKey(entity.getEntity().getGroupName());
mCachePool.putTask(task); mCachePool.putTask(task);
} else { } else {
ALog.w(TAG, "任务已存在"); ALog.w(TAG, "任务已存在");

@ -123,7 +123,7 @@ 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.key = entity.getEntity().getDownloadPath(); entity.setKey(entity.getEntity().getDownloadPath());
mCachePool.putTask(task); mCachePool.putTask(task);
} else { } else {
ALog.w(TAG, "任务已存在"); ALog.w(TAG, "任务已存在");

@ -69,7 +69,7 @@ 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.key = entity.getEntity().getFilePath(); entity.setKey(entity.getEntity().getFilePath());
mCachePool.putTask(task); mCachePool.putTask(task);
} else { } else {
ALog.w(TAG, "任务已存在"); ALog.w(TAG, "任务已存在");

@ -18,6 +18,7 @@ package com.arialyy.aria.core.scheduler;
import android.os.CountDownTimer; import android.os.CountDownTimer;
import android.os.Message; import android.os.Message;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadGroupTask;
import com.arialyy.aria.core.download.DownloadTask; import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsNormalEntity; import com.arialyy.aria.core.inf.AbsNormalEntity;
@ -38,8 +39,8 @@ import java.util.concurrent.ConcurrentHashMap;
* Created by lyy on 2017/6/4. * Created by lyy on 2017/6/4.
* 事件调度器用于处理任务状态的调度 * 事件调度器用于处理任务状态的调度
*/ */
abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends AbsTask<TASK_ENTITY>, QUEUE extends ITaskQueue<TASK, TASK_ENTITY>> abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends AbsTask<TASK_ENTITY>,
implements ISchedulers<TASK> { QUEUE extends ITaskQueue<TASK, TASK_ENTITY>> implements ISchedulers<TASK> {
private final String TAG = "AbsSchedulers"; private final String TAG = "AbsSchedulers";
protected QUEUE mQueue; protected QUEUE mQueue;
@ -54,12 +55,12 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
@Override public void register(Object obj) { @Override public void register(Object obj) {
String targetName = obj.getClass().getName(); String targetName = obj.getClass().getName();
AbsSchedulerListener<TASK, AbsNormalEntity> listener = mObservers.get(targetName); AbsSchedulerListener<TASK, AbsNormalEntity> listener = mObservers.get(getKey(obj));
if (listener == null) { if (listener == null) {
listener = createListener(targetName); listener = createListener(targetName);
if (listener != null) { if (listener != null) {
listener.setListener(obj); listener.setListener(obj);
mObservers.put(targetName, listener); mObservers.put(getKey(obj), listener);
} else { } else {
ALog.e(TAG, "注册错误,没有【" + targetName + "】观察者"); ALog.e(TAG, "注册错误,没有【" + targetName + "】观察者");
} }
@ -67,18 +68,22 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
} }
@Override public void unRegister(Object obj) { @Override public void unRegister(Object obj) {
if (!mObservers.containsKey(obj.getClass().getName())) { if (!mObservers.containsKey(getKey(obj))) {
return; return;
} }
for (Iterator<Map.Entry<String, AbsSchedulerListener<TASK, AbsNormalEntity>>> iter = for (Iterator<Map.Entry<String, AbsSchedulerListener<TASK, AbsNormalEntity>>> iter =
mObservers.entrySet().iterator(); iter.hasNext(); ) { mObservers.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry<String, AbsSchedulerListener<TASK, AbsNormalEntity>> entry = iter.next(); Map.Entry<String, AbsSchedulerListener<TASK, AbsNormalEntity>> entry = iter.next();
if (entry.getKey().equals(obj.getClass().getName())) { if (entry.getKey().equals(getKey(obj))) {
iter.remove(); iter.remove();
} }
} }
} }
private String getKey(Object obj) {
return obj.getClass().getName() + obj.hashCode();
}
/** /**
* 创建代理类 * 创建代理类
* *
@ -178,7 +183,9 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
} else { } else {
TEManager.getInstance().putTEntity(task.getKey(), task.getTaskEntity()); TEManager.getInstance().putTEntity(task.getKey(), task.getTaskEntity());
} }
callback(what, task); if (what != FAIL) {
callback(what, task);
}
} }
/** /**
@ -253,7 +260,7 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
} }
long interval = 2000; long interval = 2000;
int num = 10; int num = 10;
if (task instanceof DownloadTask) { if (task instanceof DownloadTask || task instanceof DownloadGroupTask) {
interval = AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getReTryInterval(); interval = AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getReTryInterval();
num = AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getReTryNum(); num = AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getReTryNum();
} else if (task instanceof UploadTask) { } else if (task instanceof UploadTask) {
@ -262,6 +269,13 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, TASK extends Abs
} }
final int reTryNum = num; final int reTryNum = num;
if (task.getTaskEntity().getEntity().getFailNum() > reTryNum) {
callback(FAIL, task);
mQueue.removeTaskFormQueue(task.getKey());
startNextTask();
TEManager.getInstance().removeTEntity(task.getKey());
return;
}
CountDownTimer timer = new CountDownTimer(interval, 1000) { CountDownTimer timer = new CountDownTimer(interval, 1000) {
@Override public void onTick(long millisUntilFinished) { @Override public void onTick(long millisUntilFinished) {
@ -269,7 +283,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) {
TASK task = mQueue.getTask(entity.getKey()); TASK task = mQueue.getTask(entity.getKey());
mQueue.reTryStart(task); mQueue.reTryStart(task);
} else { } else {

@ -13,20 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.manager; package com.arialyy.aria.core.upload;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import java.util.List;
/** /**
* 任务组通过组创建任务 * Created by AriaL on 2017/6/29.
* Created by Aria.Lao on 2017/11/1.
*/ */
interface IGTEntityFactory<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>> { abstract class AbsUploadTarget<TARGET extends AbsUploadTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
extends AbsTarget<TARGET, ENTITY, TASK_ENTITY> {
/**
* 通过key创建任务
*/
TASK_ENTITY create(String groupName, List<String> urls);
} }

@ -0,0 +1,133 @@
/*
* 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.upload;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.util.ALog;
import java.io.File;
/**
* Created by AriaL on 2018/3/9.
*/
abstract class BaseNormalTarget<TARGET extends AbsUploadTarget>
extends AbsUploadTarget<TARGET, UploadEntity, UploadTaskEntity> {
protected String mTempUrl;
void initTarget(String filePath) {
mTaskEntity = TEManager.getInstance().getTEntity(UploadTaskEntity.class, filePath);
mEntity = mTaskEntity.getEntity();
File file = new File(filePath);
mEntity.setFileName(file.getName());
mEntity.setFileSize(file.length());
mTempUrl = mEntity.getUrl();
}
/**
* 设置上传路径
*
* @param uploadUrl 上传路径
*/
public TARGET setUploadUrl(@NonNull String uploadUrl) {
mTempUrl = uploadUrl;
return (TARGET) this;
}
/**
* 上传任务是否存在
*
* @return {@code true}存在
*/
@Override public boolean taskExists() {
return UploadTaskQueue.getInstance().getTask(mEntity.getFilePath()) != null;
}
/**
* 是否在上传
*
* @deprecated {@link #isRunning()}
*/
public boolean isUploading() {
return isRunning();
}
@Override public boolean isRunning() {
UploadTask task = UploadTaskQueue.getInstance().getTask(mEntity.getKey());
return task != null && task.isRunning();
}
@Override protected boolean checkEntity() {
boolean b = checkUrl() && checkFilePath();
if (b) {
mEntity.save();
mTaskEntity.save();
}
return b;
}
/**
* 检查上传文件路径是否合法
*
* @return {@code true} 合法
*/
private boolean checkFilePath() {
String filePath = mEntity.getFilePath();
if (TextUtils.isEmpty(filePath)) {
ALog.e(TAG, "上传失败,文件路径为null");
return false;
} else if (!filePath.startsWith("/")) {
ALog.e(TAG, "上传失败,文件路径【" + filePath + "】不合法");
return false;
}
File file = new File(mEntity.getFilePath());
if (!file.exists()) {
ALog.e(TAG, "上传失败,文件【" + filePath + "】不存在");
return false;
}
if (file.isDirectory()) {
ALog.e(TAG, "上传失败,文件【" + filePath + "】不能是文件夹");
return false;
}
return true;
}
/**
* 检查普通任务的下载地址
*
* @return {@code true}地址合法
*/
protected boolean checkUrl() {
final String url = mTempUrl;
if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "上传失败,url为null");
return false;
} else if (!url.startsWith("http") && !url.startsWith("ftp")) {
ALog.e(TAG, "上传失败,url【" + url + "】错误");
return false;
}
int index = url.indexOf("://");
if (index == -1) {
ALog.e(TAG, "上传失败,url【" + url + "】不合法");
return false;
}
mEntity.setUrl(url);
return true;
}
}

@ -136,11 +136,11 @@ class BaseUListener<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<
} }
private void saveData(int state, long location) { private void saveData(int state, long location) {
mTaskEntity.state = state; mTaskEntity.setState(state);
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) {
mTaskEntity.deleteData(); mEntity.deleteData();
return; return;
} else if (mEntity.isComplete()) { } else if (mEntity.isComplete()) {
mEntity.setCompleteTime(System.currentTimeMillis()); mEntity.setCompleteTime(System.currentTimeMillis());

@ -15,25 +15,23 @@
*/ */
package com.arialyy.aria.core.upload; package com.arialyy.aria.core.upload;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.normal.NormalCmdFactory; import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.delegate.FtpDelegate;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.AbsUploadTarget; import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.io.File;
/** /**
* Created by Aria.Lao on 2017/7/27. * Created by Aria.Lao on 2017/7/27.
* ftp单任务上传 * ftp单任务上传
*/ */
public class FtpUploadTarget public class FtpUploadTarget extends BaseNormalTarget<FtpUploadTarget>
extends AbsUploadTarget<FtpUploadTarget, UploadEntity, UploadTaskEntity> { implements IFtpTarget<FtpUploadTarget> {
private final String TAG = "FtpUploadTarget"; private FtpDelegate<FtpUploadTarget, UploadEntity, UploadTaskEntity> mDelegate;
private String mAccount, mUser, mPw;
private boolean needLogin = false;
FtpUploadTarget(String filePath, String targetName) { FtpUploadTarget(String filePath, String targetName) {
this.mTargetName = targetName; this.mTargetName = targetName;
@ -41,84 +39,52 @@ public class FtpUploadTarget
} }
private void initTask(String filePath) { private void initTask(String filePath) {
mTaskEntity = TEManager.getInstance().getTEntity(UploadTaskEntity.class, filePath); initTarget(filePath);
if (mTaskEntity == null) { mTaskEntity.setRequestType(AbsTaskEntity.U_FTP);
mTaskEntity = TEManager.getInstance().createTEntity(UploadTaskEntity.class, filePath); mDelegate = new FtpDelegate<>(this, mTaskEntity);
}
mEntity = mTaskEntity.entity;
File file = new File(filePath);
mEntity.setFileName(file.getName());
mEntity.setFileSize(file.length());
mTaskEntity.requestType = AbsTaskEntity.U_FTP;
} }
/** /**
* 设置上传路径FTP上传路径必须是从"/"开始的完整路径 * 添加任务
*
* @param uploadUrl 上传路径
*/ */
public FtpUploadTarget setUploadUrl(@NonNull String uploadUrl) { public void add() {
uploadUrl = CheckUtil.checkUrl(uploadUrl); if (checkEntity()) {
if (!uploadUrl.endsWith("/")) { AriaManager.getInstance(AriaManager.APP)
uploadUrl += "/"; .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE,
checkTaskType()))
.exe();
} }
mTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(uploadUrl);
if (mEntity.getUrl().equals(uploadUrl)) return this;
mEntity.setUrl(uploadUrl);
mEntity.update();
return this;
} }
/** @Override protected boolean checkUrl() {
* 设置字符编码 boolean b = super.checkUrl();
*/ if (!b) {
public FtpUploadTarget charSet(String charSet) { return false;
if (TextUtils.isEmpty(charSet)) return this; }
mTaskEntity.charSet = charSet; mTaskEntity.setUrlEntity(CommonUtil.getFtpUrlInfo(mTempUrl));
return this; mTaskEntity.getUrlEntity().account = mAccount;
mTaskEntity.getUrlEntity().user = mUser;
mTaskEntity.getUrlEntity().password = mPw;
mTaskEntity.getUrlEntity().needLogin = needLogin;
return true;
} }
/** @Override public FtpUploadTarget charSet(String charSet) {
* ftp 用户登录信 return mDelegate.charSet(charSet);
* 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)}
*
* @param userName ftp用户名
* @param password ftp用户密码
*/
public FtpUploadTarget login(String userName, String password) {
return login(userName, password, null);
} }
/** @Override public FtpUploadTarget login(String userName, String password) {
* ftp 用户登录信息 needLogin = true;
* 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)} mUser = userName;
* mPw = password;
* @param userName ftp用户名
* @param password ftp用户密码
* @param account ftp账号
*/
public FtpUploadTarget login(String userName, String password, String account) {
if (TextUtils.isEmpty(userName)) {
ALog.e(TAG, "用户名不能为null");
return this;
} else if (TextUtils.isEmpty(password)) {
ALog.e(TAG, "密码不能为null");
return this;
}
mTaskEntity.urlEntity.needLogin = true;
mTaskEntity.urlEntity.user = userName;
mTaskEntity.urlEntity.password = password;
mTaskEntity.urlEntity.account = account;
return this; return this;
} }
/** @Override public FtpUploadTarget login(String userName, String password, String account) {
* 添加任务 needLogin = true;
*/ mUser = userName;
public void add() { mPw = password;
AriaManager.getInstance(AriaManager.APP) mAccount = account;
.setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE, return this;
checkTaskType()))
.exe();
} }
} }

@ -19,15 +19,17 @@ import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
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.orm.Foreign; import com.arialyy.aria.orm.annotation.Primary;
import com.arialyy.aria.orm.Primary;
/** /**
* Created by lyy on 2017/2/9. * Created by lyy on 2017/2/9.
* 上传文件实体 * 上传文件实体
*/ */
public class UploadEntity extends AbsNormalEntity implements Parcelable { public class UploadEntity extends AbsNormalEntity implements Parcelable {
@Primary @Foreign(table = UploadTaskEntity.class, column = "key") private String filePath; //文件路径 /**
* 文件上传路径
*/
@Primary private String filePath;
/** /**
* 上传完成后服务器返回的数据 * 上传完成后服务器返回的数据

@ -20,9 +20,8 @@ import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.ICmd; import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory; import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.ProxyHelper; import com.arialyy.aria.core.common.ProxyHelper;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.AbsReceiver; import com.arialyy.aria.core.inf.AbsReceiver;
import com.arialyy.aria.core.scheduler.ISchedulerListener;
import com.arialyy.aria.core.scheduler.UploadSchedulers; import com.arialyy.aria.core.scheduler.UploadSchedulers;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CheckUtil;
@ -36,7 +35,6 @@ import java.util.Set;
*/ */
public class UploadReceiver extends AbsReceiver<UploadEntity> { public class UploadReceiver extends AbsReceiver<UploadEntity> {
private static final String TAG = "UploadReceiver"; private static final String TAG = "UploadReceiver";
public ISchedulerListener<UploadTask> listener;
/** /**
* 加载HTTP单文件上传任务 * 加载HTTP单文件上传任务
@ -72,10 +70,32 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
return DbEntity.findFirst(UploadEntity.class, "filePath=?", filePath) != null; return DbEntity.findFirst(UploadEntity.class, "filePath=?", filePath) != null;
} }
/**
* 获取所有普通上传任务
* 获取未完成的普通任务列表{@link #getAllNotCompletTask()}
* 获取已经完成的普通任务列表{@link #getAllCompleteTask()}
*/
@Override public List<UploadEntity> getTaskList() { @Override public List<UploadEntity> getTaskList() {
return DbEntity.findAllData(UploadEntity.class); return DbEntity.findAllData(UploadEntity.class);
} }
/**
* 获取所有未完成的普通上传任务
*/
public List<UploadEntity> getAllNotCompletTask() {
return UploadEntity.findDatas(UploadEntity.class,
"isGroupChild=? and isComplete=?", "false", "false");
}
/**
* 获取所有已经完成的普通任务
*/
public List<UploadEntity> getAllCompleteTask() {
return UploadEntity.findDatas(UploadEntity.class,
"isGroupChild=? and isComplete=?", "false", "true");
}
@Override public void stopAllTask() { @Override public void stopAllTask() {
AriaManager.getInstance(AriaManager.APP) AriaManager.getInstance(AriaManager.APP)
.setCmd(NormalCmdFactory.getInstance() .setCmd(NormalCmdFactory.getInstance()
@ -93,7 +113,7 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
@Override public void removeAllTask(boolean removeFile) { @Override public void removeAllTask(boolean removeFile) {
final AriaManager am = AriaManager.getInstance(AriaManager.APP); final AriaManager am = AriaManager.getInstance(AriaManager.APP);
am.setCmd(CommonUtil.createNormalCmd(targetName, new DownloadTaskEntity(), am.setCmd(CommonUtil.createNormalCmd(targetName, new UploadTaskEntity(),
NormalCmdFactory.TASK_CANCEL_ALL, ICmd.TASK_TYPE_UPLOAD)).exe(); NormalCmdFactory.TASK_CANCEL_ALL, ICmd.TASK_TYPE_UPLOAD)).exe();
Set<String> keys = am.getReceiver().keySet(); Set<String> keys = am.getReceiver().keySet();
@ -104,7 +124,6 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
@Override public void destroy() { @Override public void destroy() {
targetName = null; targetName = null;
listener = null;
} }
/** /**

@ -16,16 +16,19 @@
package com.arialyy.aria.core.upload; package com.arialyy.aria.core.upload;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.arialyy.aria.core.inf.AbsUploadTarget; import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.manager.TEManager; import com.arialyy.aria.core.delegate.HttpHeaderDelegate;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import java.io.File; import com.arialyy.aria.core.inf.IHttpHeaderTarget;
import java.util.Map;
/** /**
* Created by lyy on 2017/2/28. * Created by lyy on 2017/2/28.
* http 文件上传 * http 文件上传
*/ */
public class UploadTarget extends AbsUploadTarget<UploadTarget, UploadEntity, UploadTaskEntity> { public class UploadTarget extends BaseNormalTarget<UploadTarget>
implements IHttpHeaderTarget<UploadTarget> {
private HttpHeaderDelegate<UploadTarget, UploadEntity, UploadTaskEntity> mDelegate;
UploadTarget(String filePath, String targetName) { UploadTarget(String filePath, String targetName) {
this.mTargetName = targetName; this.mTargetName = targetName;
@ -33,24 +36,19 @@ public class UploadTarget extends AbsUploadTarget<UploadTarget, UploadEntity, Up
} }
private void initTask(String filePath) { private void initTask(String filePath) {
mTaskEntity = TEManager.getInstance().getTEntity(UploadTaskEntity.class, filePath); initTarget(filePath);
if (mTaskEntity == null) {
mTaskEntity = TEManager.getInstance().createTEntity(UploadTaskEntity.class, filePath);
}
mEntity = mTaskEntity.entity;
File file = new File(filePath);
mEntity.setFileName(file.getName());
mEntity.setFileSize(file.length());
//http暂时不支持断点上传 //http暂时不支持断点上传
mTaskEntity.isSupportBP = false; mTaskEntity.setSupportBP(false);
mTaskEntity.requestType = AbsTaskEntity.U_HTTP; mTaskEntity.setRequestType(AbsTaskEntity.U_HTTP);
mDelegate = new HttpHeaderDelegate<>(this, mTaskEntity);
} }
/** /**
* 设置userAgent * 设置userAgent
*/ */
public UploadTarget setUserAngent(@NonNull String userAgent) { public UploadTarget setUserAngent(@NonNull String userAgent) {
mTaskEntity.userAgent = userAgent; mTaskEntity.setUserAgent(userAgent);
return this; return this;
} }
@ -60,7 +58,7 @@ public class UploadTarget extends AbsUploadTarget<UploadTarget, UploadEntity, Up
* @param attachment 附件key * @param attachment 附件key
*/ */
public UploadTarget setAttachment(@NonNull String attachment) { public UploadTarget setAttachment(@NonNull String attachment) {
mTaskEntity.attachment = attachment; mTaskEntity.setAttachment(attachment);
return this; return this;
} }
@ -70,7 +68,19 @@ public class UploadTarget extends AbsUploadTarget<UploadTarget, UploadEntity, Up
* @param contentType tipmultipart/form-data * @param contentType tipmultipart/form-data
*/ */
public UploadTarget setContentType(String contentType) { public UploadTarget setContentType(String contentType) {
mTaskEntity.contentType = contentType; mTaskEntity.setContentType(contentType);
return this; return this;
} }
@Override public UploadTarget addHeader(@NonNull String key, @NonNull String value) {
return mDelegate.addHeader(key, value);
}
@Override public UploadTarget addHeaders(Map<String, String> headers) {
return mDelegate.addHeaders(headers);
}
@Override public UploadTarget setRequestMode(RequestEnum requestEnum) {
return mDelegate.setRequestMode(requestEnum);
}
} }

@ -16,6 +16,7 @@
package com.arialyy.aria.core.upload.uploader; 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.OnFileInfoCallback; import com.arialyy.aria.core.common.OnFileInfoCallback;
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;
@ -39,8 +40,7 @@ class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity>
} }
@Override protected String setRemotePath() { @Override protected String setRemotePath() {
String url = mEntity.getUrl(); return mTaskEntity.getUrlEntity().remotePath + "/" + mEntity.getFileName();
return mTaskEntity.urlEntity.remotePath + "/" + mEntity.getFileName();
} }
/** /**
@ -57,6 +57,7 @@ class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity>
//远程文件已完成 //远程文件已完成
if (ftpFile.getSize() == mEntity.getFileSize()) { if (ftpFile.getSize() == mEntity.getFileSize()) {
isComplete = true; isComplete = true;
ALog.d(TAG, "FTP服务器上已存在该文件【" + ftpFile.getName() + "】");
} else { } else {
ALog.w(TAG, "FTP服务器已存在未完成的文件【" ALog.w(TAG, "FTP服务器已存在未完成的文件【"
+ ftpFile.getName() + ftpFile.getName()
@ -64,16 +65,16 @@ class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity>
+ ftpFile.getSize() + ftpFile.getSize()
+ "】" + "】"
+ "尝试从位置:" + "尝试从位置:"
+ ftpFile.getSize() + (ftpFile.getSize() - 1)
+ "开始上传"); + "开始上传");
File configFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName())); File configFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
Properties pro = CommonUtil.loadConfig(configFile); Properties pro = CommonUtil.loadConfig(configFile);
String key = mEntity.getFileName() + "_record_" + 0; String key = mEntity.getFileName() + "_record_" + 0;
mTaskEntity.isNewTask = false; mTaskEntity.setNewTask(false);
long oldRecord = Long.parseLong(pro.getProperty(key, "0")); long oldRecord = Long.parseLong(pro.getProperty(key, "0"));
if (oldRecord == 0) { if (oldRecord == 0 || oldRecord != ftpFile.getSize()) {
//修改本地保存的停止地址为服务器上对应文件的大小 //修改本地保存的停止地址为服务器上对应文件的大小
pro.setProperty(key, ftpFile.getSize() + ""); pro.setProperty(key, (ftpFile.getSize() - 1) + "");
CommonUtil.saveConfig(configFile, pro); CommonUtil.saveConfig(configFile, pro);
} }
} }
@ -82,6 +83,6 @@ class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity>
@Override protected void onPreComplete(int code) { @Override protected void onPreComplete(int code) {
super.onPreComplete(code); super.onPreComplete(code);
mCallback.onComplete(mEntity.getKey(), isComplete ? CODE_COMPLETE : code); mCallback.onComplete(mEntity.getKey(), new CompleteInfo(isComplete ? CODE_COMPLETE : code));
} }
} }

@ -32,7 +32,7 @@ import org.apache.commons.net.ftp.OnFtpInputStreamListener;
/** /**
* Created by Aria.Lao on 2017/7/28. * Created by Aria.Lao on 2017/7/28.
* FTP 单线程上传任务需要FTP 服务器给用户打开删除和读入IO的权限 * FTP 单线程上传任务需要FTP 服务器给用户打开append和write的权限
*/ */
class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> { class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
private final String TAG = "FtpUploadThreadTask"; private final String TAG = "FtpUploadThreadTask";
@ -112,9 +112,9 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
} }
private void initPath() throws UnsupportedEncodingException { private void initPath() throws UnsupportedEncodingException {
dir = new String(mTaskEntity.urlEntity.remotePath.getBytes(charSet), SERVER_CHARSET); dir = new String(mTaskEntity.getUrlEntity().remotePath.getBytes(charSet), SERVER_CHARSET);
remotePath = new String( remotePath = new String(
("/" + mTaskEntity.urlEntity.remotePath + mEntity.getFileName()).getBytes(charSet), ("/" + mTaskEntity.getUrlEntity().remotePath + "/" + mEntity.getFileName()).getBytes(charSet),
SERVER_CHARSET); SERVER_CHARSET);
} }

@ -15,6 +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.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;
@ -65,30 +66,33 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
try { try {
url = new URL(mEntity.getUrl()); url = new URL(mEntity.getUrl());
mHttpConn = (HttpURLConnection) url.openConnection(); mHttpConn = (HttpURLConnection) url.openConnection();
mHttpConn.setRequestMethod(mTaskEntity.getRequestEnum().name);
mHttpConn.setUseCaches(false); mHttpConn.setUseCaches(false);
mHttpConn.setDoOutput(true); mHttpConn.setDoOutput(true);
mHttpConn.setDoInput(true); mHttpConn.setDoInput(true);
mHttpConn.setRequestProperty("Connection", "Keep-Alive");
mHttpConn.setRequestProperty("Content-Type", mHttpConn.setRequestProperty("Content-Type",
mTaskEntity.contentType + "; boundary=" + BOUNDARY); mTaskEntity.getContentType() + "; boundary=" + BOUNDARY);
mHttpConn.setRequestProperty("User-Agent", mTaskEntity.userAgent); mHttpConn.setRequestProperty("User-Agent", mTaskEntity.getUserAgent());
mHttpConn.setConnectTimeout(5000);
//mHttpConn.setRequestProperty("Range", "bytes=" + 0 + "-" + "100"); //mHttpConn.setRequestProperty("Range", "bytes=" + 0 + "-" + "100");
//内部缓冲区---分段上传防止oom //内部缓冲区---分段上传防止oom
mHttpConn.setChunkedStreamingMode(1024); mHttpConn.setChunkedStreamingMode(1024);
//添加Http请求头部 //添加Http请求头部
Set<String> keys = mTaskEntity.headers.keySet(); Set<String> keys = mTaskEntity.getHeaders().keySet();
for (String key : keys) { for (String key : keys) {
mHttpConn.setRequestProperty(key, mTaskEntity.headers.get(key)); mHttpConn.setRequestProperty(key, mTaskEntity.getHeaders().get(key));
} }
mOutputStream = mHttpConn.getOutputStream(); mOutputStream = mHttpConn.getOutputStream();
PrintWriter writer = PrintWriter writer =
new PrintWriter(new OutputStreamWriter(mOutputStream, mTaskEntity.charSet), true); new PrintWriter(new OutputStreamWriter(mOutputStream, mTaskEntity.getCharSet()), true);
//添加文件上传表单字段 //添加文件上传表单字段
keys = mTaskEntity.formFields.keySet(); keys = mTaskEntity.getFormFields().keySet();
for (String key : keys) { for (String key : keys) {
addFormField(writer, key, mTaskEntity.formFields.get(key)); addFormField(writer, key, mTaskEntity.getFormFields().get(key));
} }
uploadFile(writer, mTaskEntity.attachment, uploadFile); uploadFile(writer, mTaskEntity.getAttachment(), uploadFile);
mTaskEntity.getEntity().setResponseStr(finish(writer)); mTaskEntity.getEntity().setResponseStr(finish(writer));
mListener.onComplete(); mListener.onComplete();
} catch (Exception e) { } catch (Exception e) {
@ -119,7 +123,7 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
.append("\"") .append("\"")
.append(LINE_END); .append(LINE_END);
writer.append("Content-Type: text/plain; charset=") writer.append("Content-Type: text/plain; charset=")
.append(mTaskEntity.charSet) .append(mTaskEntity.getCharSet())
.append(LINE_END); .append(LINE_END);
writer.append(LINE_END); writer.append(LINE_END);
writer.append(value).append(LINE_END); writer.append(value).append(LINE_END);

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.upload.uploader; package com.arialyy.aria.core.upload.uploader;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback; import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
@ -48,11 +49,11 @@ public class SimpleUploadUtil implements IUtil, Runnable {
@Override public void run() { @Override public void run() {
mListener.onPre(); mListener.onPre();
switch (mTaskEntity.requestType) { switch (mTaskEntity.getRequestType()) {
case AbsTaskEntity.U_FTP: case AbsTaskEntity.U_FTP:
new FtpFileInfoThread(mTaskEntity, new OnFileInfoCallback() { new FtpFileInfoThread(mTaskEntity, new OnFileInfoCallback() {
@Override public void onComplete(String url, int code) { @Override public void onComplete(String url, CompleteInfo info) {
if (code == FtpFileInfoThread.CODE_COMPLETE) { if (info.code == FtpFileInfoThread.CODE_COMPLETE) {
mListener.onComplete(); mListener.onComplete();
} else { } else {
mUploader.start(); mUploader.start();

@ -50,7 +50,7 @@ class Uploader extends AbsFileer<UploadEntity, UploadTaskEntity> {
*/ */
protected void checkTask() { protected void checkTask() {
mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName())); mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
if (!mTaskEntity.isSupportBP) { if (!mTaskEntity.isSupportBP()) {
isNewTask = true; isNewTask = true;
return; return;
} }
@ -65,16 +65,16 @@ class Uploader extends AbsFileer<UploadEntity, UploadTaskEntity> {
} }
} }
@Override protected void handleNewTask() { @Override protected boolean handleNewTask() {
return true;
} }
@Override protected int getNewTaskThreadNum() { @Override protected int setNewTaskThreadNum() {
return 1; return 1;
} }
@Override protected AbsThreadTask selectThreadTask(SubThreadConfig<UploadTaskEntity> config) { @Override protected AbsThreadTask selectThreadTask(SubThreadConfig<UploadTaskEntity> config) {
switch (mTaskEntity.requestType) { switch (mTaskEntity.getRequestType()) {
case AbsTaskEntity.U_FTP: case AbsTaskEntity.U_FTP:
return new FtpThreadTask(mConstance, mListener, config); return new FtpThreadTask(mConstance, mListener, config);
case AbsTaskEntity.U_HTTP: case AbsTaskEntity.U_HTTP:

@ -0,0 +1,47 @@
/*
* 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.upload.wrapper;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
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.List;
/**
* Created by laoyuyu on 2018/3/30.
*/
@Wrapper
public class UTEWrapper extends AbsWrapper {
@One
public UploadEntity entity;
@Many(parentColumn = "filePath", entityColumn = "key")
private List<UploadTaskEntity> taskEntitys = null;
public UploadTaskEntity taskEntity;
@Override public void handleConvert() {
//taskEntity.entity = (tEntity == null || tEntity.isEmpty()) ? null : tEntity.get(0);
taskEntity = (taskEntitys == null || taskEntitys.isEmpty()) ? null : taskEntitys.get(0);
if (taskEntity != null) {
taskEntity.setEntity(entity);
}
}
}

@ -0,0 +1,163 @@
/*
* 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;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.v4.util.LruCache;
import android.text.TextUtils;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field;
import java.net.URLEncoder;
/**
* Created by laoyuyu on 2018/3/22.
*/
abstract class AbsDelegate {
static final String TAG = "AbsDelegate";
static final int CREATE_TABLE = 0;
static final int TABLE_EXISTS = 1;
static final int INSERT_DATA = 2;
static final int MODIFY_DATA = 3;
static final int FIND_DATA = 4;
static final int FIND_ALL_DATA = 5;
static final int DEL_DATA = 6;
static final int ROW_ID = 7;
static final int RELATION = 8;
static final int DROP_TABLE = 9;
static LruCache<String, DbEntity> mDataCache = new LruCache<>(1024);
/**
* 打印数据库日志
*
* @param type {@link DelegateWrapper}
*/
static void print(int type, String sql) {
if (!ALog.DEBUG) {
return;
}
String str = "";
switch (type) {
case CREATE_TABLE:
str = "创建表 >>>> ";
break;
case TABLE_EXISTS:
str = "表是否存在 >>>> ";
break;
case INSERT_DATA:
str = "插入数据 >>>> ";
break;
case MODIFY_DATA:
str = "修改数据 >>>> ";
break;
case FIND_DATA:
str = "查询一行数据 >>>> ";
break;
case FIND_ALL_DATA:
str = "遍历整个数据库 >>>> ";
break;
case ROW_ID:
str = "查询RowId >>> ";
break;
case RELATION:
str = "查询关联表 >>> ";
break;
case DROP_TABLE:
str = "删除表 >>> ";
break;
}
ALog.d(TAG, str.concat(sql));
}
String getCacheKey(DbEntity dbEntity) {
return dbEntity.getClass().getName() + "_" + dbEntity.rowID;
}
/**
* 检查list参数是否合法list只能是{@code List<String>}
*
* @return {@code true} 合法
*/
boolean checkList(Field list) {
Class t = CommonUtil.getListParamType(list);
if (t != null && t == String.class) {
return true;
} else {
ALog.d(TAG, "map参数错误,支持List<String>的参数字段");
return false;
}
}
/**
* 检查map参数是否合法map只能是{@code Map<String, String>}
*
* @return {@code true} 合法
*/
boolean checkMap(Field map) {
Class[] ts = CommonUtil.getMapParamType(map);
if (ts != null
&& ts[0] != null
&& ts[1] != null
&& ts[0] == String.class
&& ts[1] == String.class) {
return true;
} else {
ALog.d(TAG, "map参数错误,支持Map<String,String>的参数字段");
return false;
}
}
/**
* 为了防止特殊字符串导致存储失败需要使用URL编码保存的字符串
*
* @param value 需要保存的内容
* @return 转换后的内容
*/
String convertValue(String value) {
if (!TextUtils.isEmpty(value) && value.contains("'")) {
return URLEncoder.encode(value);
}
return value;
}
void closeCursor(Cursor cursor) {
if (cursor != null && !cursor.isClosed()) {
try {
cursor.close();
} catch (android.database.SQLException e) {
e.printStackTrace();
}
}
}
void close(SQLiteDatabase db) {
//if (db != null && db.isOpen()) db.close();
}
/**
* 检查数据库是否关闭已经关闭的话打开数据库
*
* @return 返回数据库
*/
SQLiteDatabase checkDb(SQLiteDatabase db) {
if (db == null || !db.isOpen()) {
db = SqlHelper.INSTANCE.getWritableDatabase();
}
return db;
}
}

@ -0,0 +1,27 @@
/*
* 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;
/**
* Created by laoyuyu on 2018/3/30.
*/
public abstract class AbsWrapper {
/**
* 处理转换
*/
protected abstract void handleConvert();
}

@ -0,0 +1,62 @@
/*
* 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;
import com.arialyy.aria.orm.annotation.Foreign;
/**
* Created by laoyuyu on 2018/3/22.
* on update on delete 都可跟不同action功能
*
* @see <a href="https://sqlite.org/foreignkeys.html"></a>
* {@link Foreign#onDelete()}{@link Foreign#onUpdate()}
*/
public enum ActionPolicy {
/**
* 如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作
*/
NO_ACTION("NO ACTION"),
/**
* 和NO ACTION 作用一致和NO ACTION的区别是
* 主表update/delete执行时马上就触发约束
* 而NO ACTION 是执行完成语句后才触发约束
*/
RESTRICT("RESTRICT"),
/**
* 在父表上update/delete记录时将子表上匹配记录的列设为null (要注意子表的外键列不能为not null)
*/
SET_NULL("SET NULL"),
/**
* 父表有变更时,子表将外键列设置成一个默认的值default配置的值
*/
SET_DEFAULT("SET DEFAULT"),
/**
* 在父表上update/delete记录时同步update/delete掉子表的匹配记录
*/
CASCADE("CASCADE");
String function;
ActionPolicy(String function) {
this.function = function;
}
}

@ -16,8 +16,6 @@
package com.arialyy.aria.orm; package com.arialyy.aria.orm;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.ErrorEntity;
import com.arialyy.aria.core.UrlMapping;
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;
@ -32,9 +30,15 @@ import java.util.Map;
* 数据库配置信息 * 数据库配置信息
*/ */
class DBConfig { class DBConfig {
/*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 = 23; static int VERSION = 31;
/**
* 是否将数据库保存在Sd卡{@code true}
*/
static final boolean SAVE_IN_SDCARD = false;
static { static {
if (TextUtils.isEmpty(DB_NAME)) { if (TextUtils.isEmpty(DB_NAME)) {
@ -46,13 +50,11 @@ class DBConfig {
} }
static { static {
mapping.put("DownloadEntity", DownloadEntity.class); mapping.put("DownloadGroupTaskEntity", DownloadGroupTaskEntity.class);
mapping.put("DownloadGroupEntity", DownloadGroupEntity.class); mapping.put("DownloadGroupEntity", DownloadGroupEntity.class);
mapping.put("DownloadTaskEntity", DownloadTaskEntity.class); mapping.put("DownloadTaskEntity", DownloadTaskEntity.class);
mapping.put("DownloadGroupTaskEntity", DownloadGroupTaskEntity.class);
mapping.put("UploadEntity", UploadEntity.class);
mapping.put("UploadTaskEntity", UploadTaskEntity.class); mapping.put("UploadTaskEntity", UploadTaskEntity.class);
mapping.put("ErrorEntity", ErrorEntity.class); mapping.put("DownloadEntity", DownloadEntity.class);
//mapping.put("UrlMapping", UrlMapping.class); mapping.put("UploadEntity", UploadEntity.class);
} }
} }

@ -0,0 +1,93 @@
/*
* 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;
import android.content.Context;
import android.content.ContextWrapper;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.io.IOException;
/**
* 保存在sd卡的数据库使用的Context
*/
class DatabaseContext extends ContextWrapper {
public DatabaseContext(Context context) {
super(context);
}
/**
* 获得数据库路径如果不存在则创建对象对象
*/
@Override
public File getDatabasePath(String name) {
String dbDir = CommonUtil.getAppPath(getBaseContext());
dbDir += "DB";//数据库所在目录
String dbPath = dbDir + "/" + name;//数据库路径
//判断目录是否存在,不存在则创建该目录
File dirFile = new File(dbDir);
if (!dirFile.exists()) {
dirFile.mkdirs();
}
//数据库文件是否创建成功
boolean isFileCreateSuccess = false;
//判断文件是否存在,不存在则创建该文件
File dbFile = new File(dbPath);
if (!dbFile.exists()) {
try {
isFileCreateSuccess = dbFile.createNewFile();//创建文件
} catch (IOException e) {
e.printStackTrace();
}
} else {
isFileCreateSuccess = true;
}
//返回数据库文件对象
if (isFileCreateSuccess) {
return dbFile;
} else {
return null;
}
}
/**
* 重载这个方法是用来打开SD卡上的数据库的android 2.3及以下会调用这个方法
*/
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode,
SQLiteDatabase.CursorFactory factory) {
return SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
}
/**
* Android 4.0会调用此方法获取数据库
*
* @see android.content.ContextWrapper#openOrCreateDatabase(java.lang.String, int,
* android.database.sqlite.SQLiteDatabase.CursorFactory,
* android.database.DatabaseErrorHandler)
*/
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode,
SQLiteDatabase.CursorFactory factory,
DatabaseErrorHandler errorHandler) {
return SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
}
}

@ -16,35 +16,29 @@
package com.arialyy.aria.orm; package com.arialyy.aria.orm;
import android.support.annotation.NonNull;
import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Created by lyy on 2015/11/2. * Created by lyy on 2015/11/2.
* 所有数据库实体父类 * 所有数据库实体父类
*/ */
public class DbEntity { public abstract class DbEntity {
private static final Object LOCK = new Object(); private static final Object LOCK = new Object();
protected int rowID = -1; protected long rowID = -1;
protected DbEntity() { protected DbEntity() {
} }
///** /**
// * 关键字模糊检索全文 * 查询关联数据
// * *
// * @param column 需要查找的列 * @param expression 查询条件
// * @param mathSql 关键字语法,exsimple “white OR green”、“blue AND red”、“white NOT green” */
// */ public static <T extends AbsWrapper> List<T> findRelationData(Class<T> clazz,
//public static <T extends DbEntity> List<T> searchData(Class<T> clazz, String column, String mathSql) { String... expression) {
// return DbUtil.getInstance().searchData(clazz, column, mathSql); return DelegateWrapper.getInstance().findRelationData(clazz, expression);
//} }
/** /**
* 检查某个字段的值是否存在 * 检查某个字段的值是否存在
@ -53,21 +47,21 @@ public class DbEntity {
* @return {@code true}该字段的对应的value已存在 * @return {@code true}该字段的对应的value已存在
*/ */
public static boolean checkDataExist(Class clazz, String... expression) { public static boolean checkDataExist(Class clazz, String... expression) {
return DbUtil.getInstance().checkDataExist(clazz, expression); return DelegateWrapper.getInstance().checkDataExist(clazz, expression);
} }
/** /**
* 清空表数据 * 清空表数据
*/ */
public static <T extends DbEntity> void clean(Class<T> clazz) { public static <T extends DbEntity> void clean(Class<T> clazz) {
DbUtil.getInstance().clean(clazz); DelegateWrapper.getInstance().clean(clazz);
} }
/** /**
* 直接执行sql语句 * 直接执行sql语句
*/ */
public static void exeSql(String sql) { public static void exeSql(String sql) {
DbUtil.getInstance().exeSql(sql); DelegateWrapper.getInstance().exeSql(sql);
} }
/** /**
@ -76,7 +70,7 @@ public class DbEntity {
* @return 没有数据返回null * @return 没有数据返回null
*/ */
public static <T extends DbEntity> List<T> findAllData(Class<T> clazz) { public static <T extends DbEntity> List<T> findAllData(Class<T> clazz) {
DbUtil util = DbUtil.getInstance(); DelegateWrapper util = DelegateWrapper.getInstance();
return util.findAllData(clazz); return util.findAllData(clazz);
} }
@ -97,7 +91,7 @@ public class DbEntity {
* @return 没有数据返回null * @return 没有数据返回null
*/ */
public static <T extends DbEntity> List<T> findDatas(Class<T> clazz, String... expression) { public static <T extends DbEntity> List<T> findDatas(Class<T> clazz, String... expression) {
DbUtil util = DbUtil.getInstance(); DelegateWrapper util = DelegateWrapper.getInstance();
return util.findData(clazz, expression); return util.findData(clazz, expression);
} }
@ -110,25 +104,11 @@ public class DbEntity {
* @return 没有数据返回null * @return 没有数据返回null
*/ */
public static <T extends DbEntity> T findFirst(Class<T> clazz, String... expression) { public static <T extends DbEntity> T findFirst(Class<T> clazz, String... expression) {
DbUtil util = DbUtil.getInstance(); DelegateWrapper util = DelegateWrapper.getInstance();
List<T> datas = util.findData(clazz, expression); List<T> datas = util.findData(clazz, expression);
return datas == null ? null : datas.size() > 0 ? datas.get(0) : null; return datas == null ? null : datas.size() > 0 ? datas.get(0) : null;
} }
/**
* 获取所有行的rowid
*/
public int[] getRowIds() {
return DbUtil.getInstance().getRowId(getClass());
}
/**
* 获取rowid
*/
public int getRowId(@NonNull Object[] wheres, @NonNull Object[] values) {
return DbUtil.getInstance().getRowId(getClass(), wheres, values);
}
/** /**
* 删除当前数据 * 删除当前数据
*/ */
@ -143,7 +123,7 @@ public class DbEntity {
* </code> * </code>
*/ */
public static <T extends DbEntity> void deleteData(Class<T> clazz, String... expression) { public static <T extends DbEntity> void deleteData(Class<T> clazz, String... expression) {
DbUtil util = DbUtil.getInstance(); DelegateWrapper util = DelegateWrapper.getInstance();
util.delData(clazz, expression); util.delData(clazz, expression);
} }
@ -151,11 +131,12 @@ public class DbEntity {
* 修改数据 * 修改数据
*/ */
public void update() { public void update() {
DbUtil.getInstance().modifyData(this); DelegateWrapper.getInstance().modifyData(this);
} }
/** /**
* 保存自身如果表中已经有数据则更新数据否则插入数据 * 保存自身如果表中已经有数据则更新数据否则插入数据
* 只有 target中checkEntity成功后才能保存创建实体部分也不允许保存
*/ */
public void save() { public void save() {
synchronized (LOCK) { synchronized (LOCK) {
@ -171,58 +152,14 @@ public class DbEntity {
* 查找数据在表中是否存在 * 查找数据在表中是否存在
*/ */
private boolean thisIsExist() { private boolean thisIsExist() {
DbUtil util = DbUtil.getInstance(); DelegateWrapper util = DelegateWrapper.getInstance();
return util.isExist(getClass(), rowID); return rowID != -1 && util.isExist(getClass(), rowID);
} }
/** /**
* 插入数据 * 插入数据只有 target中checkEntity成功后才能插入创建实体部分也不允许操作
*/ */
public void insert() { public void insert() {
DbUtil.getInstance().insertData(this); DelegateWrapper.getInstance().insertData(this);
updateRowID();
}
private <T extends DbEntity> T findFirst(Class<T> clazz, @NonNull String[] wheres,
@NonNull String[] values) {
DbUtil util = DbUtil.getInstance();
List<T> list = util.findData(clazz, wheres, values);
return list == null ? null : list.get(0);
}
private void updateRowID() {
try {
List<Field> fields = CommonUtil.getAllFields(getClass());
List<String> where = new ArrayList<>();
List<String> values = new ArrayList<>();
for (Field field : fields) {
field.setAccessible(true);
if (SqlUtil.ignoreField(field)) {
continue;
}
where.add(field.getName());
Type type = field.getType();
if (SqlUtil.isOneToOne(field)) {
values.add(SqlUtil.getOneToOneParams(field));
} else if (type == List.class) {
if (SqlUtil.isOneToMany(field)) {
values.add(SqlUtil.getOneToManyElementParams(field));
} else {
values.add(SqlUtil.list2Str(this, field));
}
} else if (type == Map.class) {
values.add(SqlUtil.map2Str((Map<String, String>) field.get(this)));
} else {
values.add(field.get(this) + "");
}
}
DbEntity entity = findFirst(getClass(), where.toArray(new String[where.size()]),
values.toArray(new String[values.size()]));
if (entity != null) {
rowID = entity.rowID;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} }
} }

@ -1,249 +0,0 @@
/*
* 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;
import android.app.Application;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.util.List;
/**
* Created by lyy on 2015/2/11.
* 数据库操作工具
*/
public class DbUtil {
private static final String TAG = "DbUtil";
private volatile static DbUtil INSTANCE = null;
private int ROW_ID = 7;
private SQLiteDatabase mDb;
private SqlHelper mHelper;
private DbUtil() {
}
private DbUtil(Context context) {
mHelper = SqlHelper.init(context.getApplicationContext());
}
public static DbUtil init(Context context) {
if (context instanceof Application) {
synchronized (AriaManager.LOCK) {
if (INSTANCE == null) {
INSTANCE = new DbUtil(context);
}
}
}
return INSTANCE;
}
protected static DbUtil getInstance() {
if (INSTANCE == null) {
throw new NullPointerException("请在Application中调用init进行数据库工具注册注册");
}
return INSTANCE;
}
///**
// * 关键字模糊检索全文
// *
// * @param column 需要查找的列
// * @param mathSql 关键字语法,exsimple “white OR green”、“blue AND red”、“white NOT green”
// */
//public <T extends DbEntity> List<T> searchData(Class<T> clazz, String column, String mathSql) {
// checkDb();
// return SqlHelper.searchData(mDb, clazz, column, mathSql);
//}
/**
* 检查某个字段的值是否存在
*
* @param expression 字段和值"url=xxx"
* @return {@code true}该字段的对应的value已存在
*/
synchronized boolean checkDataExist(Class clazz, String... expression) {
checkDb();
return SqlHelper.checkDataExist(mDb, clazz, expression);
}
/**
* 清空表数据
*/
synchronized <T extends DbEntity> void clean(Class<T> clazz) {
checkDb();
String tableName = CommonUtil.getClassName(clazz);
if (tableExists(clazz)) {
String sql = "DELETE FROM " + tableName;
exeSql(sql);
}
}
/**
* 执行sql语句
*/
void exeSql(String sql) {
mDb.execSQL(sql);
}
/**
* 删除某条数据
*/
synchronized <T extends DbEntity> void delData(Class<T> clazz, String... expression) {
CheckUtil.checkSqlExpression(expression);
checkDb();
SqlHelper.delData(mDb, clazz, expression);
}
/**
* 修改某行数据
*/
synchronized void modifyData(DbEntity dbEntity) {
checkDb();
SqlHelper.modifyData(mDb, dbEntity);
}
/**
* 遍历所有数据
*/
synchronized <T extends DbEntity> List<T> findAllData(Class<T> clazz) {
checkDb();
return SqlHelper.findAllData(mDb, clazz);
}
/**
* 条件查寻数据
*/
synchronized <T extends DbEntity> List<T> findData(Class<T> clazz, String... expression) {
checkDb();
return SqlHelper.findData(mDb, clazz, expression);
}
/**
* 通过rowId判断数据是否存在
*/
synchronized <T extends DbEntity> boolean isExist(Class<T> clazz, int rowId) {
checkDb();
String sql = "SELECT rowid FROM " + CommonUtil.getClassName(clazz) + " WHERE rowid=" + rowId;
Cursor cursor = mDb.rawQuery(sql, null);
boolean isExist = cursor.getCount() > 0;
cursor.close();
return isExist;
}
/**
* 条件查寻数据
*/
@Deprecated synchronized <T extends DbEntity> List<T> findData(Class<T> clazz,
@NonNull String[] wheres, @NonNull String[] values) {
checkDb();
return SqlHelper.findData(mDb, clazz, wheres, values);
}
/**
* 插入数据
*/
synchronized void insertData(DbEntity dbEntity) {
checkDb();
SqlHelper.insertData(mDb, dbEntity);
}
/**
* 查找某张表是否存在
*/
synchronized boolean tableExists(Class clazz) {
checkDb();
return SqlHelper.tableExists(mDb, clazz);
}
synchronized void createTable(Class clazz, String tableName) {
checkDb();
SqlHelper.createTable(mDb, clazz, tableName);
}
private void checkDb() {
if (mDb == null || !mDb.isOpen()) {
mDb = mHelper.getReadableDatabase();
}
}
/**
* 创建表
*/
private synchronized void createTable(Class clazz) {
createTable(clazz, null);
}
/**
* 关闭数据库
*/
private synchronized void close() {
if (mDb != null) {
mDb.close();
}
}
/**
* 获取所在行Id
*/
synchronized int[] getRowId(Class clazz) {
checkDb();
Cursor cursor = mDb.rawQuery("SELECT rowid, * FROM " + CommonUtil.getClassName(clazz), null);
int[] ids = new int[cursor.getCount()];
int i = 0;
while (cursor.moveToNext()) {
ids[i] = cursor.getInt(cursor.getColumnIndex("rowid"));
i++;
}
cursor.close();
close();
return ids;
}
/**
* 获取行Id
*/
synchronized int getRowId(Class clazz, Object[] wheres, Object[] values) {
checkDb();
if (wheres.length <= 0 || values.length <= 0) {
ALog.e(TAG, "请输入删除条件");
return -1;
} else if (wheres.length != values.length) {
ALog.e(TAG, "groupName 和 vaule 长度不相等");
return -1;
}
StringBuilder sb = new StringBuilder();
sb.append("SELECT rowid FROM ").append(CommonUtil.getClassName(clazz)).append(" WHERE ");
int i = 0;
for (Object where : wheres) {
sb.append(where).append("=").append("'").append(values[i]).append("'");
sb.append(i >= wheres.length - 1 ? "" : ",");
i++;
}
SqlHelper.print(ROW_ID, sb.toString());
Cursor c = mDb.rawQuery(sb.toString(), null);
int id = c.getColumnIndex("rowid");
c.close();
close();
return id;
}
}

@ -0,0 +1,221 @@
/*
* 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;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;
import com.arialyy.aria.orm.annotation.Default;
import com.arialyy.aria.orm.annotation.Foreign;
import com.arialyy.aria.orm.annotation.Primary;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Created by laoyuyu on 2018/3/22.
* 通用委托创建表检查字段
*/
class DelegateCommon extends AbsDelegate {
private DelegateCommon() {
}
/**
* 删除指定的表
*/
void dropTable(SQLiteDatabase db, String tableName) {
db = checkDb(db);
String deleteSQL = "DROP TABLE IF EXISTS ".concat(tableName);
print(DROP_TABLE, deleteSQL);
//db.beginTransaction();
db.execSQL(deleteSQL);
//db.setTransactionSuccessful();
//db.endTransaction();
}
/**
* 清空表数据
*/
<T extends DbEntity> void clean(SQLiteDatabase db, Class<T> clazz) {
db = checkDb(db);
String tableName = CommonUtil.getClassName(clazz);
if (tableExists(db, clazz)) {
String sql = "DELETE FROM " + tableName;
db.execSQL(sql);
}
}
/**
* 查找表是否存在
*
* @param clazz 数据库实体
* @return true该数据库实体对应的表存在false不存在
*/
boolean tableExists(SQLiteDatabase db, Class clazz) {
return tableExists(db, CommonUtil.getClassName(clazz));
}
private boolean tableExists(SQLiteDatabase db, String tableName) {
db = checkDb(db);
Cursor cursor = null;
try {
StringBuilder sb = new StringBuilder();
sb.append("SELECT COUNT(*) AS c FROM sqlite_master WHERE type='table' AND name='");
sb.append(tableName);
sb.append("'");
print(TABLE_EXISTS, sb.toString());
cursor = db.rawQuery(sb.toString(), null);
if (cursor != null && cursor.moveToNext()) {
int count = cursor.getInt(0);
if (count > 0) {
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeCursor(cursor);
close(db);
}
return false;
}
/**
* 检查某个字段的值是否存在
*
* @param expression 字段和值"url=xxx"
* @return {@code true}该字段的对应的value已存在
*/
boolean checkDataExist(SQLiteDatabase db, Class clazz, String... expression) {
db = checkDb(db);
CheckUtil.checkSqlExpression(expression);
String sql =
"SELECT rowid, * FROM " + CommonUtil.getClassName(clazz) + " WHERE " + expression[0] + " ";
sql = sql.replace("?", "%s");
Object[] params = new String[expression.length - 1];
for (int i = 0, len = params.length; i < len; i++) {
params[i] = "'" + expression[i + 1] + "'";
}
sql = String.format(sql, params);
print(FIND_DATA, sql);
Cursor cursor = db.rawQuery(sql, null);
final boolean isExist = cursor.getCount() > 0;
closeCursor(cursor);
close(db);
return isExist;
}
/**
* 创建表
*
* @param clazz 数据库实体
*/
void createTable(SQLiteDatabase db, Class clazz) {
db = checkDb(db);
List<Field> fields = CommonUtil.getAllFields(clazz);
if (fields != null && fields.size() > 0) {
//外键Map,在Sqlite3中foreign修饰的字段必须放在最后
final List<Field> foreignArray = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb.append("CREATE TABLE ")
.append(CommonUtil.getClassName(clazz))
.append(" (");
for (Field field : fields) {
field.setAccessible(true);
if (SqlUtil.isIgnore(field)) {
continue;
}
Class<?> type = field.getType();
sb.append(field.getName());
if (type == String.class || type.isEnum()) {
sb.append(" VARCHAR");
} else if (type == int.class || type == Integer.class) {
sb.append(" INTEGER");
} else if (type == float.class || type == Float.class) {
sb.append(" FLOAT");
} else if (type == double.class || type == Double.class) {
sb.append(" DOUBLE");
} else if (type == long.class || type == Long.class) {
sb.append(" BIGINT");
} else if (type == boolean.class || type == Boolean.class) {
sb.append(" BOOLEAN");
} else if (type == java.util.Date.class || type == java.sql.Date.class) {
sb.append(" DATA");
} else if (type == byte.class || type == Byte.class) {
sb.append(" BLOB");
} else if (type == Map.class || type == List.class) {
sb.append(" TEXT");
} else {
continue;
}
if (SqlUtil.isPrimary(field)) {
Primary pk = field.getAnnotation(Primary.class);
sb.append(" PRIMARY KEY");
if (pk.autoincrement() && (type == int.class || type == Integer.class)) {
sb.append(" AUTOINCREMENT");
}
}
if (SqlUtil.isForeign(field)) {
foreignArray.add(field);
}
if (SqlUtil.isNoNull(field)) {
sb.append(" NOT NULL");
}
if (SqlUtil.isDefault(field)) {
Default d = field.getAnnotation(Default.class);
if (!TextUtils.isEmpty(d.value())) {
sb.append(" DEFAULT ").append("'").append(d.value()).append("'");
}
}
sb.append(",");
}
for (Field field : foreignArray) {
Foreign foreign = field.getAnnotation(Foreign.class);
sb.append("FOREIGN KEY (")
.append(field.getName())
.append(") REFERENCES ")
.append(CommonUtil.getClassName(foreign.parent()))
.append("(")
.append(foreign.column())
.append(")");
ActionPolicy update = foreign.onUpdate();
ActionPolicy delete = foreign.onDelete();
if (update != ActionPolicy.NO_ACTION) {
sb.append(" ON UPDATE ").append(update.function);
}
if (delete != ActionPolicy.NO_ACTION) {
sb.append(" ON DELETE ").append(update.function);
}
sb.append(",");
}
String str = sb.toString();
str = str.substring(0, str.length() - 1) + ");";
print(CREATE_TABLE, str);
db.execSQL(str);
}
close(db);
}
}

@ -0,0 +1,512 @@
/*
* 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;
import android.annotation.TargetApi;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import android.text.TextUtils;
import com.arialyy.aria.orm.annotation.Many;
import com.arialyy.aria.orm.annotation.One;
import com.arialyy.aria.orm.annotation.Wrapper;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
/**
* Created by laoyuyu on 2018/3/22.
* 查询数据
*/
class DelegateFind extends AbsDelegate {
private final String PARENT_COLUMN_ALIAS = "p";
private final String CHILD_COLUMN_ALIAS = "c";
private DelegateFind() {
}
/**
* 查找一对多的关联数据
* 如果查找不到数据或实体没有被{@link Wrapper}注解将返回null
* 如果实体中没有{@link One}{@link Many}注解将返回null
* 如果实体中有多个{@link One}{@link Many}注解将返回nul
*/
<T extends AbsWrapper> List<T> findRelationData(SQLiteDatabase db, Class<T> clazz,
String... expression) {
db = checkDb(db);
if (SqlUtil.isWrapper(clazz)) {
StringBuilder sb = new StringBuilder();
Field[] fields = clazz.getDeclaredFields();
Field one = null, many = null;
boolean hasOne = false, hasMany = false;
for (Field field : fields) {
if (SqlUtil.isOne(field)) {
if (hasOne) {
ALog.w(TAG, "查询数据失败,实体中有多个@One 注解");
return null;
}
hasOne = true;
one = field;
}
if (SqlUtil.isMany(field)) {
if (hasMany) {
ALog.w(TAG, "查询数据失败,实体中有多个@Many 注解");
return null;
}
hasMany = true;
many = field;
}
}
if (one == null || many == null) {
ALog.w(TAG, "查询数据失败,实体中没有@One或@Many注解");
return null;
}
if (many.getType() != List.class) {
ALog.w(TAG, "查询数据失败,@Many注解的字段必须是List");
return null;
}
try {
Many m = many.getAnnotation(Many.class);
Class parentClazz = Class.forName(one.getType().getName());
Class childClazz = Class.forName(CommonUtil.getListParamType(many).getName());
final String pTableName = parentClazz.getSimpleName();
final String cTableName = childClazz.getSimpleName();
List<Field> pColumn = SqlUtil.getAllNotIgnoreField(parentClazz);
List<Field> cColumn = SqlUtil.getAllNotIgnoreField(childClazz);
List<String> pColumnAlias = new ArrayList<>();
List<String> cColumnAlias = new ArrayList<>();
StringBuilder pSb = new StringBuilder();
StringBuilder cSb = new StringBuilder();
if (pColumn != null) {
pSb.append(pTableName.concat(".rowid AS ").concat(PARENT_COLUMN_ALIAS).concat("rowid,"));
for (Field f : pColumn) {
String temp = PARENT_COLUMN_ALIAS.concat(f.getName());
pColumnAlias.add(temp);
pSb.append(pTableName.concat(".").concat(f.getName()))
.append(" AS ")
.append(temp)
.append(",");
}
}
if (cColumn != null) {
pSb.append(cTableName.concat(".rowid AS ").concat(CHILD_COLUMN_ALIAS).concat("rowid,"));
for (Field f : cColumn) {
String temp = CHILD_COLUMN_ALIAS.concat(f.getName());
cColumnAlias.add(temp);
cSb.append(cTableName.concat(".").concat(f.getName()))
.append(" AS ")
.append(temp)
.append(",");
}
}
String pColumnAlia = pSb.toString();
String cColumnAlia = cSb.toString();
if (!TextUtils.isEmpty(pColumnAlia)) {
pColumnAlia = pColumnAlia.substring(0, pColumnAlia.length() - 1);
}
if (!TextUtils.isEmpty(cColumnAlia)) {
cColumnAlia = cColumnAlia.substring(0, cColumnAlia.length() - 1);
}
sb.append("SELECT ");
if (!TextUtils.isEmpty(pColumnAlia)) {
sb.append(pColumnAlia).append(",");
}
if (!TextUtils.isEmpty(cColumnAlia)) {
sb.append(cColumnAlia);
}
if (TextUtils.isEmpty(pColumnAlia) && TextUtils.isEmpty(cColumnAlia)) {
sb.append(" * ");
}
sb.append(" FROM ")
.append(pTableName)
.append(" INNER JOIN ")
.append(cTableName)
.append(" ON ")
.append(pTableName.concat(".").concat(m.parentColumn()))
.append(" = ")
.append(cTableName.concat(".").concat(m.entityColumn()));
String sql;
if (expression != null && expression.length > 0) {
CheckUtil.checkSqlExpression(expression);
sb.append(" WHERE ").append(expression[0]).append(" ");
sql = sb.toString();
sql = sql.replace("?", "%s");
Object[] params = new String[expression.length - 1];
for (int i = 0, len = params.length; i < len; i++) {
params[i] = "'" + convertValue(expression[i + 1]) + "'";
}
sql = String.format(sql, params);
} else {
sql = sb.toString();
}
print(RELATION, sql);
Cursor cursor = db.rawQuery(sql, null);
List<T> data =
(List<T>) newInstanceEntity(clazz, parentClazz, childClazz, cursor, pColumn, cColumn,
pColumnAlias, cColumnAlias);
closeCursor(cursor);
close(db);
return data;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} else {
ALog.w(TAG, "查询数据失败,实体类没有使用@Wrapper 注解");
return null;
}
return null;
}
/**
* 创建关联查询的数据
*
* @param pColumn 父表的所有字段
* @param cColumn 字表的所有字段
* @param pColumnAlias 关联查询父表别名
* @param cColumnAlias 关联查询子表别名
*/
private <T extends AbsWrapper, P extends DbEntity, C extends DbEntity> List<T> newInstanceEntity(
Class<T> clazz, Class<P> parent,
Class<C> child,
Cursor cursor,
List<Field> pColumn, List<Field> cColumn,
List<String> pColumnAlias, List<String> cColumnAlias) {
try {
String parentPrimary = ""; //父表主键别名
for (Field f : pColumn) {
if (SqlUtil.isPrimary(f)) {
parentPrimary = PARENT_COLUMN_ALIAS.concat(f.getName());
break;
}
}
List<T> wrappers = new ArrayList<>();
Map<Object, P> tempParent = new WeakHashMap<>(); // 所有父表元素,key为父表主键的值
Map<Object, List<C>> tempChild = new WeakHashMap<>(); // 所有的字表元素,key为父表主键的值
Object old = null;
while (cursor.moveToNext()) {
//创建父实体
Object ppValue = setPPValue(parentPrimary, cursor);
if (old == null || ppValue != old) { //当主键不同时,表示是不同的父表数据
old = ppValue;
if (tempParent.get(old) == null) {
P pEntity = parent.newInstance();
String pPrimaryName = "";
for (int i = 0, len = pColumnAlias.size(); i < len; i++) {
Field pField = pColumn.get(i);
pField.setAccessible(true);
Class<?> type = pField.getType();
int column = cursor.getColumnIndex(pColumnAlias.get(i));
if (column == -1) continue;
setFieldValue(type, pField, column, cursor, pEntity);
if (SqlUtil.isPrimary(pField) && (type == int.class || type == Integer.class)) {
pPrimaryName = pField.getName();
}
}
//当设置了主键,而且主键的类型为integer时,查询RowID等于主键
pEntity.rowID = cursor.getInt(
cursor.getColumnIndex(
TextUtils.isEmpty(pPrimaryName) ? PARENT_COLUMN_ALIAS.concat("rowid")
: pPrimaryName));
tempParent.put(ppValue, pEntity);
}
}
// 创建子实体
C cEntity = child.newInstance();
String cPrimaryName = "";
for (int i = 0, len = cColumnAlias.size(); i < len; i++) {
Field cField = cColumn.get(i);
cField.setAccessible(true);
Class<?> type = cField.getType();
int column = cursor.getColumnIndex(cColumnAlias.get(i));
if (column == -1) continue;
setFieldValue(type, cField, column, cursor, cEntity);
if (SqlUtil.isPrimary(cField) && (type == int.class || type == Integer.class)) {
cPrimaryName = cField.getName();
}
}
//当设置了主键,而且主键的类型为integer时,查询RowID等于主键
cEntity.rowID = cursor.getInt(
cursor.getColumnIndex(
TextUtils.isEmpty(cPrimaryName) ? CHILD_COLUMN_ALIAS.concat("rowid")
: cPrimaryName));
if (tempChild.get(old) == null) {
tempChild.put(old, new ArrayList<C>());
}
tempChild.get(old).add(cEntity);
}
List<Field> wFields = SqlUtil.getAllNotIgnoreField(clazz);
if (wFields != null && !wFields.isEmpty()) {
Set<Object> pKeys = tempParent.keySet();
for (Object pk : pKeys) {
T wrapper = clazz.newInstance();
P p = tempParent.get(pk);
boolean isPSet = false, isCSet = false;
for (Field f : wFields) {
if (!isPSet && f.getAnnotation(One.class) != null) {
f.set(wrapper, p);
isPSet = true;
}
if (!isCSet && f.getAnnotation(Many.class) != null) {
f.set(wrapper, tempChild.get(pk));
isCSet = true;
}
}
wrapper.handleConvert(); //处理下转换
wrappers.add(wrapper);
}
}
return wrappers;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
/**
* 获取父表主键数据
*
* @param parentPrimary 父表主键别名
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB) private Object setPPValue(String parentPrimary,
Cursor cursor) {
Object ppValue = null;
int ppColumn = cursor.getColumnIndex(parentPrimary); //父表主键所在的列
int type = cursor.getType(ppColumn);
switch (type) {
case Cursor.FIELD_TYPE_INTEGER:
ppValue = cursor.getLong(ppColumn);
break;
case Cursor.FIELD_TYPE_FLOAT:
ppValue = cursor.getFloat(ppColumn);
break;
case Cursor.FIELD_TYPE_STRING:
ppValue = cursor.getString(ppColumn);
break;
}
return ppValue;
}
/**
* 条件查寻数据
*/
<T extends DbEntity> List<T> findData(SQLiteDatabase db, Class<T> clazz, String... expression) {
db = checkDb(db);
CheckUtil.checkSqlExpression(expression);
String sql =
"SELECT rowid, * FROM " + CommonUtil.getClassName(clazz) + " WHERE " + expression[0] + " ";
sql = sql.replace("?", "%s");
Object[] params = new String[expression.length - 1];
for (int i = 0, len = params.length; i < len; i++) {
params[i] = "'" + convertValue(expression[i + 1]) + "'";
}
sql = String.format(sql, params);
print(FIND_DATA, sql);
Cursor cursor = db.rawQuery(sql, null);
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
closeCursor(cursor);
close(db);
return data;
}
/**
* 查找表的所有数据
*/
<T extends DbEntity> List<T> findAllData(SQLiteDatabase db, Class<T> clazz) {
db = checkDb(db);
StringBuilder sb = new StringBuilder();
sb.append("SELECT rowid, * FROM ").append(CommonUtil.getClassName(clazz));
print(FIND_ALL_DATA, sb.toString());
Cursor cursor = db.rawQuery(sb.toString(), null);
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
closeCursor(cursor);
close(db);
return data;
}
/**
* 根据数据游标创建一个具体的对象
*/
private <T extends DbEntity> List<T> newInstanceEntity(Class<T> clazz, Cursor cursor) {
List<Field> fields = CommonUtil.getAllFields(clazz);
List<T> entitys = new ArrayList<>();
if (fields != null && fields.size() > 0) {
try {
while (cursor.moveToNext()) {
T entity = clazz.newInstance();
String primaryName = "";
for (Field field : fields) {
field.setAccessible(true);
if (SqlUtil.isIgnore(field)) {
continue;
}
Class<?> type = field.getType();
if (SqlUtil.isPrimary(field) && (type == int.class || type == Integer.class)) {
primaryName = field.getName();
}
int column = cursor.getColumnIndex(field.getName());
if (column == -1) continue;
setFieldValue(type, field, column, cursor, entity);
}
//当设置了主键,而且主键的类型为integer时,查询RowID等于主键
entity.rowID = cursor.getInt(
cursor.getColumnIndex(TextUtils.isEmpty(primaryName) ? "rowid" : primaryName));
//mDataCache.put(getCacheKey(entity), entity);
entitys.add(entity);
}
closeCursor(cursor);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return entitys;
}
/**
* 设置字段的值
*
* @throws IllegalAccessException
*/
private void setFieldValue(Class type, Field field, int column, Cursor cursor, Object entity)
throws IllegalAccessException {
if (type == String.class) {
String temp = cursor.getString(column);
if (!TextUtils.isEmpty(temp)) {
field.set(entity, URLDecoder.decode(temp));
}
} else if (type == int.class || type == Integer.class) {
field.setInt(entity, cursor.getInt(column));
} else if (type == float.class || type == Float.class) {
field.setFloat(entity, cursor.getFloat(column));
} else if (type == double.class || type == Double.class) {
field.setDouble(entity, cursor.getDouble(column));
} else if (type == long.class || type == Long.class) {
field.setLong(entity, cursor.getLong(column));
} else if (type == boolean.class || type == Boolean.class) {
String temp = cursor.getString(column);
if (TextUtils.isEmpty(temp)) {
field.setBoolean(entity, false);
} else {
field.setBoolean(entity, !temp.equalsIgnoreCase("false"));
}
} else if (type == java.util.Date.class || type == java.sql.Date.class) {
field.set(entity, new Date(cursor.getString(column)));
} else if (type == byte[].class) {
field.set(entity, cursor.getBlob(column));
} else if (type == Map.class) {
String temp = cursor.getString(column);
if (!TextUtils.isEmpty(temp)) {
field.set(entity, SqlUtil.str2Map(temp));
}
} else if (type == List.class) {
String value = cursor.getString(column);
if (!TextUtils.isEmpty(value)) {
field.set(entity, SqlUtil.str2List(value, field));
}
}
}
/**
* 获取所在行Id
*/
int[] getRowId(SQLiteDatabase db, Class clazz) {
db = checkDb(db);
Cursor cursor = db.rawQuery("SELECT rowid, * FROM " + CommonUtil.getClassName(clazz), null);
int[] ids = new int[cursor.getCount()];
int i = 0;
while (cursor.moveToNext()) {
ids[i] = cursor.getInt(cursor.getColumnIndex("rowid"));
i++;
}
cursor.close();
close(db);
return ids;
}
/**
* 获取行Id
*/
int getRowId(SQLiteDatabase db, Class clazz, Object[] wheres, Object[] values) {
db = checkDb(db);
if (wheres.length <= 0 || values.length <= 0) {
ALog.e(TAG, "请输入删除条件");
return -1;
} else if (wheres.length != values.length) {
ALog.e(TAG, "groupName 和 vaule 长度不相等");
return -1;
}
StringBuilder sb = new StringBuilder();
sb.append("SELECT rowid FROM ").append(CommonUtil.getClassName(clazz)).append(" WHERE ");
int i = 0;
for (Object where : wheres) {
sb.append(where).append("=").append("'").append(values[i]).append("'");
sb.append(i >= wheres.length - 1 ? "" : ",");
i++;
}
print(ROW_ID, sb.toString());
Cursor c = db.rawQuery(sb.toString(), null);
int id = c.getColumnIndex("rowid");
c.close();
close(db);
return id;
}
/**
* 通过rowId判断数据是否存在
*/
<T extends DbEntity> boolean itemExist(SQLiteDatabase db, Class<T> clazz,
long rowId) {
db = checkDb(db);
String sql = "SELECT rowid FROM " + CommonUtil.getClassName(clazz) + " WHERE rowid=" + rowId;
print(ROW_ID, sql);
Cursor cursor = db.rawQuery(sql, null);
boolean isExist = cursor.getCount() > 0;
cursor.close();
return isExist;
}
}

@ -0,0 +1,69 @@
/*
* 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;
import android.util.SparseArray;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* Created by laoyuyu on 2018/3/22.
* Delegate管理器
*/
class DelegateManager {
private final String TAG = "ModuleFactory";
private SparseArray<AbsDelegate> mDelegates = new SparseArray<>();
private static volatile DelegateManager INSTANCE = null;
private DelegateManager() {
}
static DelegateManager getInstance() {
if (INSTANCE == null) {
synchronized (DelegateManager.class) {
INSTANCE = new DelegateManager();
}
}
return INSTANCE;
}
/**
* 获取Module
*/
<M extends AbsDelegate> M getDelegate(Class<M> clazz) {
M delegate = (M) mDelegates.get(clazz.hashCode());
try {
if (delegate == null) {
Constructor c = clazz.getDeclaredConstructor();
c.setAccessible(true);
delegate = (M) c.newInstance();
mDelegates.put(clazz.hashCode(), delegate);
return delegate;
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return delegate;
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save