pull/330/head
laoyuyu 7 years ago
commit 788c1398e0
  1. 1
      .gitignore
  2. 7
      Aria/build.gradle
  3. 92
      Aria/src/main/java/com/arialyy/aria/core/Aria.java
  4. 105
      Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
  5. 146
      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. 54
      Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
  11. 57
      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. 180
      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. 80
      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. 101
      Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
  38. 188
      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. 93
      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. 162
      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. 41
      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. 116
      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. 42
      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. 30
      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
/cache
*.log
uml

@ -16,6 +16,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
}
dependencies {
@ -23,8 +26,8 @@ dependencies {
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
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'

@ -17,15 +17,8 @@
package com.arialyy.aria.core;
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.os.Build;
import android.widget.PopupWindow;
import com.arialyy.aria.core.download.DownloadReceiver;
import com.arialyy.aria.core.upload.UploadReceiver;
@ -51,6 +44,24 @@ import com.arialyy.aria.core.upload.UploadReceiver;
* .start();
* </code>
* </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 {
@ -60,52 +71,53 @@ import com.arialyy.aria.core.upload.UploadReceiver;
/**
* 初始化下载
*
* @param obj 支持类型有ActivityServiceApplicationDialogFragmentFragmentPopupWindowDialog
* @param context 支持类型有ActivityServiceApplicationDialogFragmentFragmentPopupWindowDialog
*/
public static DownloadReceiver download(Object obj) {
return get(obj).download(obj);
public static DownloadReceiver download(Context context) {
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) {
return get(obj).upload(obj);
return AriaManager.getInstance().upload(obj);
}
/**
* 处理通用事件
*
* @param obj 支持类型有ActivityServiceApplicationDialogFragmentFragmentPopupWindowDialog
*/
public static AriaManager get(Object obj) {
if (obj instanceof Activity || obj instanceof Service || obj instanceof Application) {
return AriaManager.getInstance((Context) obj);
} else if (obj instanceof DialogFragment) {
DialogFragment dialog = (DialogFragment) obj;
return AriaManager.getInstance(
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? dialog.getContext()
: dialog.getActivity());
} else if (obj instanceof android.support.v4.app.Fragment) {
android.support.v4.app.Fragment fragment = (android.support.v4.app.Fragment) obj;
return AriaManager.getInstance(
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? fragment.getContext()
: 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("不支持的类型");
public static AriaManager get(Context context) {
return AriaManager.getInstance(context);
}
/**
* 初始化Aria如果你需要在ActivityServiceApplicationDialogFragmentFragmentPopupWindowDialog
* 之外的java中使用Aria那么你应该在Application或Activity初始化的时候调用本方法对Aria进行初始化
* 只需要初始化一次就可以
* {@link #download(Object)}{@link #upload(Object)}
*/
public static AriaManager init(Context context) {
return AriaManager.getInstance(context);
}
}

@ -20,13 +20,11 @@ import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Application;
import android.app.Dialog;
import android.app.Service;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.widget.PopupWindow;
import com.arialyy.aria.core.command.ICmd;
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.UploadTaskEntity;
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.AriaCrashHandler;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.io.IOException;
@ -75,12 +74,14 @@ import org.xml.sax.SAXException;
private List<ICmd> mCommands = new ArrayList<>();
private Configuration.DownloadConfig mDConfig;
private Configuration.UploadConfig mUConfig;
private Configuration.AppConfig mAConfig;
private AriaManager(Context context) {
DbUtil.init(context.getApplicationContext());
DelegateWrapper.init(context.getApplicationContext());
APP = context.getApplicationContext();
regAppLifeCallback(context);
initConfig();
initAria();
}
public static AriaManager getInstance(Context context) {
@ -92,34 +93,53 @@ import org.xml.sax.SAXException;
return INSTANCE;
}
public Map<String, AbsReceiver> getReceiver() {
return mReceivers;
static AriaManager getInstance() {
if (INSTANCE == null) {
throw new NullPointerException("请在Application或Activity初始化时调用一次Aria.init(context)方法进行初始化操作");
}
return INSTANCE;
}
/**
* 设置Aria 日志级别
*
* @param level {@link ALog#LOG_LEVEL_VERBOSE}
*/
public void setLogLevel(int level) {
ALog.LOG_LEVEL = level;
private void initAria() {
if (mAConfig.getUseAriaCrashHandler()) {
Thread.setDefaultUncaughtExceptionHandler(new AriaCrashHandler());
}
mAConfig.setLogLevel(mAConfig.getLogLevel());
}
public Map<String, AbsReceiver> getReceiver() {
return mReceivers;
}
/**
* 设置上传任务的执行队列类型
* 设置上传任务的执行队列类型后续版本会删除该api请使用
* <pre>
* <code>
* Aria.get(this).getUploadConfig().setQueueMod(mod.tag)
* </code>
* </pre>
*
* @param mod {@link QueueMod}
* @deprecated 后续版本会删除该api
*/
@Deprecated
public AriaManager setUploadQueueMod(QueueMod mod) {
mUConfig.setQueueMod(mod.tag);
return this;
}
/**
* 设置下载任务的执行队列类型
* 设置下载任务的执行队列类型后续版本会删除该api请使用
* <pre>
* <code>
* Aria.get(this).getDownloadConfig().setQueueMod(mod.tag)
* </code>
* </pre>
*
* @param mod {@link QueueMod}
* @deprecated 后续版本会删除该api
*/
@Deprecated
public AriaManager setDownloadQueueMod(QueueMod mod) {
mDConfig.setQueueMod(mod.tag);
return this;
@ -151,6 +171,13 @@ import org.xml.sax.SAXException;
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;
}
/**
* 获取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);
IReceiver receiver = mReceivers.get(key);
boolean needRmReceiver = false;
// 监控Dialog、fragment、popupWindow的生命周期
final WidgetLiftManager widgetLiftManager = new WidgetLiftManager();
if (obj instanceof Dialog) {
needRmReceiver = widgetLiftManager.handleDialogLift((Dialog) obj);
@ -270,7 +282,8 @@ import org.xml.sax.SAXException;
/**
* 不允许在"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();
int i = 0;
for (StackTraceElement e : stack) {
@ -288,8 +301,8 @@ import org.xml.sax.SAXException;
"onStop");
if (isDestroyed) {
ALog.w(TAG,
"请不要在Activity或Fragment的onDestroy、finish、onStop等方法中调用Aria,Aria的unRegister会在Activity页面销毁时自动执行");
ALog.e(TAG,
"请不要在Activity或Fragment的onDestroy、finish、onStop等方法中注册Aria,Aria的unRegister会在Activity页面销毁时自动执行");
}
if (obj instanceof Activity && isDestroyed) {
@ -309,8 +322,7 @@ import org.xml.sax.SAXException;
*/
private String getKey(boolean isDownload, Object obj) {
String clsName = obj.getClass().getName();
String key = "";
if (!(obj instanceof Activity)) {
String key;
if (obj instanceof DialogFragment) {
key = clsName + "_" + ((DialogFragment) obj).getActivity().getClass().getName();
} else if (obj instanceof android.app.DialogFragment) {
@ -333,21 +345,10 @@ import org.xml.sax.SAXException;
} else {
key = clsName;
}
} else if (obj instanceof Service) {
key = clsName;
} else if (obj instanceof Application) {
key = clsName;
}
}
if (obj instanceof Activity || obj instanceof Service) {
key = clsName;
} else if (obj instanceof Application) {
} else {
key = clsName;
}
if (TextUtils.isEmpty(key)) {
throw new IllegalArgumentException("未知类型");
}
key += isDownload ? DOWNLOAD : UPLOAD;
key += (isDownload ? DOWNLOAD : UPLOAD) + obj.hashCode();
return key;
}
@ -377,6 +378,7 @@ import org.xml.sax.SAXException;
}
mDConfig = Configuration.DownloadConfig.getInstance();
mUConfig = Configuration.UploadConfig.getInstance();
mAConfig = Configuration.AppConfig.getInstance();
if (tempDir.exists()) {
File newDir = new File(APP.getFilesDir().getPath() + DOWNLOAD_TEMP_DIR);
newDir.mkdirs();
@ -406,8 +408,8 @@ import org.xml.sax.SAXException;
private void regAppLifeCallback(Context context) {
Context app = context.getApplicationContext();
if (app instanceof Application) {
LifeCallback mLifeCallback = new LifeCallback();
((Application) app).registerActivityLifecycleCallbacks(mLifeCallback);
LifeCallback lifeCallback = new LifeCallback();
((Application) app).registerActivityLifecycleCallbacks(lifeCallback);
}
}
@ -478,6 +480,7 @@ import org.xml.sax.SAXException;
@Override public void onActivityDestroyed(Activity 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 {
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.UploadConfig mUploadConfig = Configuration.UploadConfig.getInstance();
private Configuration.AppConfig mAppConfig = Configuration.AppConfig.getInstance();
@Override public void startDocument() throws SAXException {
super.startDocument();
@ -43,10 +44,17 @@ class ConfigHelper extends DefaultHandler {
if (qName.equals("download")) {
isDownloadConfig = true;
isUploadConfig = false;
isAppConfig = false;
} else if (qName.equals("upload")) {
isUploadConfig = true;
isDownloadConfig = false;
isAppConfig = false;
} else if (qName.equals("app")) {
isUploadConfig = false;
isDownloadConfig = false;
isAppConfig = true;
}
if (isDownloadConfig || isUploadConfig) {
String value = attributes.getValue("value");
@ -90,17 +98,46 @@ class ConfigHelper extends DefaultHandler {
loadUpdateInterval(value);
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) {
long temp = 1000;
if (!TextUtils.isEmpty(value)) {
temp = Long.parseLong(value);
if (temp <= 0) {
temp = 1000;
private void loadLogLevel(String value) {
int level;
try {
level = Integer.parseInt(value);
} catch (NumberFormatException e) {
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) {
mDownloadConfig.updateInterval = temp;
}
@ -124,17 +161,18 @@ class ConfigHelper extends DefaultHandler {
}
private void loadMaxSpeed(String value) {
double maxSpeed = 0.0;
if (!TextUtils.isEmpty(value)) {
maxSpeed = Double.parseDouble(value);
}
int maxSpeed = checkInt(value) ? Integer.parseInt(value) : 0;
if (isDownloadConfig) {
mDownloadConfig.msxSpeed = maxSpeed;
mDownloadConfig.maxSpeed = maxSpeed;
}
}
private void loadConvertSpeed(String value) {
boolean open = Boolean.parseBoolean(value);
boolean open = true;
if (checkBoolean(value)) {
open = Boolean.parseBoolean(value);
}
if (isDownloadConfig) {
mDownloadConfig.isConvertSpeed = open;
}
@ -144,10 +182,7 @@ class ConfigHelper extends DefaultHandler {
}
private void loadReTryInterval(String value) {
int time = 2 * 1000;
if (!TextUtils.isEmpty(value)) {
time = Integer.parseInt(value);
}
int time = checkInt(value) ? Integer.parseInt(value) : 2 * 1000;
if (time < 2 * 1000) {
time = 2 * 1000;
@ -166,10 +201,7 @@ class ConfigHelper extends DefaultHandler {
}
private void loadBuffSize(String value) {
int buffSize = 8192;
if (!TextUtils.isEmpty(value)) {
buffSize = Integer.parseInt(value);
}
int buffSize = checkInt(value) ? Integer.parseInt(value) : 8192;
if (buffSize < 2048) {
buffSize = 2048;
@ -181,10 +213,7 @@ class ConfigHelper extends DefaultHandler {
}
private void loadIOTimeout(String value) {
int time = 10 * 1000;
if (!TextUtils.isEmpty(value)) {
time = Integer.parseInt(value);
}
int time = checkInt(value) ? Integer.parseInt(value) : 10 * 1000;
if (time < 10 * 1000) {
time = 10 * 1000;
@ -196,10 +225,7 @@ class ConfigHelper extends DefaultHandler {
}
private void loadConnectTime(String value) {
int time = 5 * 1000;
if (!TextUtils.isEmpty(value)) {
time = Integer.parseInt(value);
}
int time = checkInt(value) ? Integer.parseInt(value) : 5 * 1000;
if (isDownloadConfig) {
mDownloadConfig.connectTimeOut = time;
@ -210,10 +236,7 @@ class ConfigHelper extends DefaultHandler {
}
private void loadReTry(String value) {
int num = 0;
if (!TextUtils.isEmpty(value)) {
num = Integer.parseInt(value);
}
int num = checkInt(value) ? Integer.parseInt(value) : 0;
if (isDownloadConfig) {
mDownloadConfig.reTryNum = num;
@ -224,10 +247,7 @@ class ConfigHelper extends DefaultHandler {
}
private void loadMaxQueue(String value) {
int num = 2;
if (!TextUtils.isEmpty(value)) {
num = Integer.parseInt(value);
}
int num = checkInt(value) ? Integer.parseInt(value) : 2;
if (num < 1) {
ALog.w(TAG, "任务队列数不能小于 1");
num = 2;
@ -241,10 +261,7 @@ class ConfigHelper extends DefaultHandler {
}
private void loadThreadNum(String value) {
int num = 3;
if (!TextUtils.isEmpty(value)) {
num = Integer.parseInt(value);
}
int num = checkInt(value) ? Integer.parseInt(value) : 3;
if (num < 1) {
ALog.e(TAG, "下载线程数不能小于 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 {
super.characters(ch, start, length);
}
@ -266,5 +329,6 @@ class ConfigHelper extends DefaultHandler {
super.endDocument();
mDownloadConfig.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 信息链接实体
*/
public class FtpUrlEntity implements Cloneable {
/**
* ftp://127.0.0.1:21/download/AriaPrj.zip
* remotePath便是download/AriaPrj.zip
*/
public String remotePath;
public String account;
@ -35,12 +38,12 @@ public class FtpUrlEntity implements Cloneable {
public String url;
/**
* ftp协议
* ftp协议ftp
*/
public String protocol;
/**
* 用户
* 登录的用户
*/
public String user;
/**

@ -16,13 +16,7 @@
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.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.
@ -44,46 +38,5 @@ public class CancelAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
@Override public void executeCmd() {
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();
}
if (task != null) {
mTaskEntity.removeFile = removeFile;
mTaskEntity.setRemoveFile(removeFile);
if (!TextUtils.isEmpty(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.download.DownloadGroupTaskEntity;
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.IEntity;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.core.queue.UploadTaskQueue;
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.util.ALog;
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} 单任务上传任务
*/
private List<AbsTaskEntity> findTaskData(int type) {
// TODO: 2018/4/20 需要测试
List<AbsTaskEntity> tempList = new ArrayList<>();
switch (type) {
case 1:
List<DownloadTaskEntity> dTaskEntity =
DbEntity.findDatas(DownloadTaskEntity.class, "isGroupTask=?", "false");
if (dTaskEntity != null && !dTaskEntity.isEmpty()) {
tempList.addAll(dTaskEntity);
}
break;
case 2:
List<DownloadGroupTaskEntity> groupTask =
DbEntity.findAllData(DownloadGroupTaskEntity.class);
if (groupTask != null && !groupTask.isEmpty()) {
tempList.addAll(groupTask);
}
break;
case 3:
List<UploadTaskEntity> uTaskEntity =
DbEntity.findDatas(UploadTaskEntity.class, "isGroupTask=?", "false");
if (uTaskEntity != null && !uTaskEntity.isEmpty()) {
tempList.addAll(uTaskEntity);
}
break;
if (type == 1) {
List<DTEWrapper> wrappers = DbEntity.findRelationData(DTEWrapper.class,
"DownloadTaskEntity.isGroupTask=? and DownloadTaskEntity.state!=?", "false", "1");
if (wrappers != null && !wrappers.isEmpty()) {
for (DTEWrapper w : wrappers) {
tempList.add(w.taskEntity);
}
}
} else if (type == 2) {
List<DGTEWrapper> wrappers =
DbEntity.findRelationData(DGTEWrapper.class, "DownloadGroupTaskEntity.state!=?", "1");
if (wrappers != null && !wrappers.isEmpty()) {
for (DGTEWrapper w : wrappers) {
tempList.add(w.taskEntity);
}
}
} else if (type == 3) {
List<UTEWrapper> wrappers =
DbEntity.findRelationData(UTEWrapper.class, "UploadTaskEntity.state!=?", "1");
if (wrappers != null && !wrappers.isEmpty()) {
for (UTEWrapper w : wrappers) {
tempList.add(w.taskEntity);
}
}
}
return tempList;
}
@ -123,8 +129,8 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
*/
private void resumeEntity(AbsTaskEntity te) {
if (te instanceof DownloadTaskEntity) {
if (te.requestType == AbsTaskEntity.D_FTP || te.requestType == AbsTaskEntity.U_FTP) {
te.urlEntity = CommonUtil.getFtpUrlInfo(te.getEntity().getKey());
if (te.getRequestType() == AbsTaskEntity.D_FTP || te.getRequestType() == AbsTaskEntity.U_FTP) {
te.setUrlEntity(CommonUtil.getFtpUrlInfo(te.getEntity().getKey()));
}
mQueue = DownloadTaskQueue.getInstance();
} 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.download.DownloadGroupTaskEntity;
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.AbsTaskEntity;
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.UploadTaskQueue;
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.util.ALog;
import com.arialyy.aria.util.CommonUtil;
@ -53,6 +56,7 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
return;
}
String mod;
// TODO: 2018/4/12 配置文件不存在,是否会出现wait获取不到 ?
int maxTaskNum = mQueue.getMaxTaskNum();
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
if (isDownloadCmd) {
@ -77,7 +81,6 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
|| task.getState() == IEntity.STATE_OTHER
|| task.getState() == IEntity.STATE_POST_PRE
|| task.getState() == IEntity.STATE_COMPLETE) {
//startTask();
resumeTask();
} else {
sendWaitState();
@ -85,7 +88,6 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
}
} else {
if (!task.isRunning()) {
//startTask();
resumeTask();
}
}
@ -113,29 +115,32 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
}
private List<AbsTaskEntity> findWaitData(int type) {
// TODO: 2018/4/20 需要测试
List<AbsTaskEntity> waitList = new ArrayList<>();
switch (type) {
case 1:
List<DownloadTaskEntity> dEntity =
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=? and state=?", "", "3");
if (dEntity != null && !dEntity.isEmpty()) {
waitList.addAll(dEntity);
}
break;
case 2:
List<DownloadGroupTaskEntity> dgEntity =
DbEntity.findDatas(DownloadGroupTaskEntity.class, "state=?", "3");
if (dgEntity != null && !dgEntity.isEmpty()) {
waitList.addAll(dgEntity);
}
break;
case 3:
List<UploadTaskEntity> uEntity =
DbEntity.findDatas(UploadTaskEntity.class, "state=?", "3");
if (uEntity != null && !uEntity.isEmpty()) {
waitList.addAll(uEntity);
}
break;
if (type == 1) {
List<DTEWrapper> wrappers = DbEntity.findRelationData(DTEWrapper.class,
"DownloadTaskEntity.isGroupTask=? and DownloadTaskEntity.state=?", "false", "3");
if (wrappers != null && !wrappers.isEmpty()) {
for (DTEWrapper w : wrappers) {
waitList.add(w.taskEntity);
}
}
} else if (type == 2) {
List<DGTEWrapper> wrappers =
DbEntity.findRelationData(DGTEWrapper.class, "DownloadGroupTaskEntity.state=?", "3");
if (wrappers != null && !wrappers.isEmpty()) {
for (DGTEWrapper w : wrappers) {
waitList.add(w.taskEntity);
}
}
} else if (type == 3) {
List<UTEWrapper> wrappers = DbEntity.findRelationData(UTEWrapper.class,
"UploadTaskEntity.state=?", "3");
if (wrappers != null && !wrappers.isEmpty()) {
for (UTEWrapper w : wrappers) {
waitList.add(w.taskEntity);
}
}
}
return waitList;
}
@ -146,8 +151,8 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
AbsTask task = getTask(te.getEntity());
if (task != null) continue;
if (te instanceof DownloadTaskEntity) {
if (te.requestType == AbsTaskEntity.D_FTP || te.requestType == AbsTaskEntity.U_FTP) {
te.urlEntity = CommonUtil.getFtpUrlInfo(te.getEntity().getKey());
if (te.getRequestType() == AbsTaskEntity.D_FTP || te.getRequestType() == AbsTaskEntity.U_FTP) {
te.setUrlEntity(CommonUtil.getFtpUrlInfo(te.getEntity().getKey()));
}
mQueue = DownloadTaskQueue.getInstance();
} else if (te instanceof UploadTaskEntity) {

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

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

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

@ -86,7 +86,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
mEntity = mTaskEntity.getEntity();
mConfigFPath = info.CONFIG_FILE_PATH;
mBufSize = manager.getDownloadConfig().getBuffSize();
setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed());
setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxSpeed());
mTaskType = getTaskType();
mLastSaveTime = System.currentTimeMillis();
mConfigThreadPool = Executors.newCachedThreadPool();
@ -200,7 +200,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
synchronized (AriaManager.LOCK) {
try {
if (ex != null) {
ALog.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex));
ALog.e(TAG, msg + "\n" + ALog.getExceptionString(ex));
} else {
ALog.e(TAG, msg);
}
@ -210,7 +210,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY
} else {
ALog.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
mListener.onFail(true);
ErrorHelp.saveError(mTaskType, mEntity, "", CommonUtil.getPrintException(ex));
ErrorHelp.saveError(TAG, "", ALog.getExceptionString(ex));
}
} catch (IOException e) {
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.
* 抽象的下载接口
* 任务功能接口
*/
public interface IUtil {
@ -28,39 +28,39 @@ public interface IUtil {
long getFileSize();
/**
* 获取当前下载位置
* 获取当前位置
*/
long getCurrentLocation();
/**
* 是否正在下载
* 任务是否正在执行
*
* @return true, 正在下载
* @return {@code true} 任务正在执行
*/
boolean isRunning();
/**
* 取消下载
* 取消
*/
void cancel();
/**
* 停止下载
* 停止
*/
void stop();
/**
* 开始下载
* 开始
*/
void start();
/**
* 从上次断点恢复下载
* 从上次断点恢复
*/
void resume();
/**
* 设置最大下载速度
* 设置最大速度
*/
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;
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
* limitations under the License.
*/
package com.arialyy.aria.core;
package com.arialyy.aria.core.common;
import com.arialyy.aria.orm.DbEntity;
/**
* Created by lyy on 2017/10/17.
* Url 映射表
* Created by laoyuyu on 2018/3/21.
* 任务上传或下载的记录
*/
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) {
mTaskEntity.state = state;
mTaskEntity.setState(state);
mEntity.setState(state);
mEntity.setComplete(state == IEntity.STATE_COMPLETE);
if (state == IEntity.STATE_CANCEL) {
mTaskEntity.deleteData();
mEntity.deleteData();
return;
} else if (mEntity.isComplete()) {
mEntity.setCompleteTime(System.currentTimeMillis());

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

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

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

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

@ -15,45 +15,53 @@
*/
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.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
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.Set;
/**
* Created by AriaL on 2017/6/29.
* 下载任务组
*/
public class DownloadGroupTarget
extends BaseGroupTarget<DownloadGroupTarget, DownloadGroupTaskEntity> {
private final String TAG = "DownloadGroupTarget";
public class DownloadGroupTarget extends BaseGroupTarget<DownloadGroupTarget> {
/**
* 子任务下载地址
*/
private List<String> mUrls = new ArrayList<>();
/**
* 子任务文件名
*/
private List<String> mSubNameTemp = new ArrayList<>();
DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) {
this.mTargetName = targetName;
if (groupEntity.getUrls() != null && !groupEntity.getUrls().isEmpty()) {
this.mUrls.addAll(groupEntity.getUrls());
}
mGroupName = CommonUtil.getMd5Code(groupEntity.getUrls());
mTaskEntity = TEManager.getInstance().getTEntity(DownloadGroupTaskEntity.class, mGroupName);
if (mTaskEntity == null) {
mTaskEntity =
TEManager.getInstance().createTEntity(DownloadGroupTaskEntity.class, groupEntity);
}
mEntity = mTaskEntity.entity;
init();
}
DownloadGroupTarget(List<String> urls, String targetName) {
this.mTargetName = targetName;
this.mUrls = urls;
mGroupName = CommonUtil.getMd5Code(urls);
mTaskEntity = TEManager.getInstance().getTEntity(DownloadGroupTaskEntity.class, mGroupName);
if (mTaskEntity == null) {
mTaskEntity = TEManager.getInstance().createGTEntity(DownloadGroupTaskEntity.class, mUrls);
init();
}
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) {
mEntity.setFileSize(fileSize);
mEntity.update();
}
return this;
}
@ -80,16 +87,165 @@ public class DownloadGroupTarget
* 如果你是使用{@link DownloadReceiver#load(DownloadGroupEntity)}进行下载操作那么你需要设置任务组的下载地址
*/
public DownloadGroupTarget setGroupUrl(List<String> urls) {
CheckUtil.checkDownloadUrls(urls);
mUrls.clear();
mUrls.addAll(urls);
mEntity.setGroupName(CommonUtil.getMd5Code(urls));
mEntity.update();
return this;
}
@Override public boolean isRunning() {
DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(mEntity.getKey());
return task != null && task.isRunning();
/**
* 设置子任务文件名该方法必须在{@link #setDirPath(String)}之后调用否则不生效
*
* @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;
mContext = AriaManager.APP;
mListener = new DownloadGroupListener(this, mOutHandler);
switch (taskEntity.requestType) {
switch (taskEntity.getRequestType()) {
case AbsTaskEntity.D_HTTP:
mUtil = new DownloadGroupUtil(mListener, mTaskEntity);
break;
@ -71,16 +71,18 @@ public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity> {
@Override public void stop() {
if (!mUtil.isRunning()) {
mListener.onStop(getCurrentProgress());
}
} else {
mUtil.stop();
}
}
@Override public void cancel() {
if (!mUtil.isRunning()) {
mListener.onCancel();
}
} else {
mUtil.cancel();
}
}
@Override public String getTaskName() {
return "任务组->" + (TextUtils.isEmpty(mTaskEntity.getEntity().getAlias())
@ -116,7 +118,6 @@ public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity> {
public DownloadGroupTask build() {
DownloadGroupTask task = new DownloadGroupTask(taskEntity, outHandler);
task.setTargetName(targetName);
taskEntity.save();
return task;
}
}

@ -16,24 +16,48 @@
package com.arialyy.aria.core.download;
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.
* 任务组的任务实体
*/
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() {
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){
key = groupEntity.getKey();
entity = groupEntity;
groupEntity.save();
save();
public void setKey(String key) {
this.key = key;
}
}

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

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

@ -18,7 +18,6 @@ package com.arialyy.aria.core.download;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.IUtil;
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() {
return isDownloading();
return mUtil.isRunning();
}
public DownloadEntity getDownloadEntity() {

@ -16,31 +16,51 @@
package com.arialyy.aria.core.download;
import com.arialyy.aria.core.inf.AbsNormalTaskEntity;
import com.arialyy.aria.orm.NoNull;
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.NoNull;
import com.arialyy.aria.orm.annotation.Primary;
/**
* Created by lyy on 2017/1/23.
* 下载任务实体
* 下载任务实体和下载实体为一对一关系下载实体删除任务实体自动删除
*/
public class DownloadTaskEntity extends AbsNormalTaskEntity<DownloadEntity> {
@OneToOne(table = DownloadEntity.class, key = "downloadPath") public DownloadEntity entity;
@Ignore private DownloadEntity entity;
/**
* 任务的url
*/
@NoNull public String url = "";
@NoNull private String url;
/**
* 所属的任务组组名如果不属于任务组则为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() {
}
@ -49,13 +69,47 @@ public class DownloadTaskEntity extends AbsNormalTaskEntity<DownloadEntity> {
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;
if (entity != null) {
url = entity.getUrl();
key = entity.getDownloadPath();
entity.save();
}
save();
public void setUrl(String url) {
this.url = url;
}
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;
import android.text.TextUtils;
import com.arialyy.aria.core.delegate.FtpDelegate;
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.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.util.ALog;
/**
* Created by Aria.Lao on 2017/7/26.
* ftp文件夹下载
*/
public class FtpDirDownloadTarget
extends BaseGroupTarget<FtpDirDownloadTarget, DownloadGroupTaskEntity> {
private final String TAG = "FtpDirDownloadTarget";
public class FtpDirDownloadTarget extends BaseGroupTarget<FtpDirDownloadTarget>
implements IFtpTarget<FtpDirDownloadTarget> {
private FtpDelegate<FtpDirDownloadTarget, DownloadGroupEntity, DownloadGroupTaskEntity> mDelegate;
FtpDirDownloadTarget(String url, String targetName) {
mTargetName = targetName;
@ -36,57 +37,68 @@ public class FtpDirDownloadTarget
private void init(String key) {
mGroupName = key;
mTaskEntity = TEManager.getInstance().getTEntity(DownloadGroupTaskEntity.class, key);
if (mTaskEntity == null) {
mTaskEntity = TEManager.getInstance().createTEntity(DownloadGroupTaskEntity.class, key);
mTaskEntity = TEManager.getInstance().getFDTEntity(DownloadGroupTaskEntity.class, key);
mTaskEntity.setRequestType(AbsTaskEntity.D_FTP_DIR);
mEntity = mTaskEntity.getEntity();
if (mEntity != null) {
mDirPathTemp = mEntity.getDirPath();
}
mTaskEntity.requestType = AbsTaskEntity.D_FTP_DIR;
mEntity = mTaskEntity.entity;
mDelegate = new FtpDelegate<>(this, mTaskEntity);
}
/**
* 设置字符编码
*/
public FtpDirDownloadTarget charSet(String charSet) {
if (TextUtils.isEmpty(charSet)) return this;
mTaskEntity.charSet = charSet;
return this;
@Override protected int getTargetType() {
return GROUP_FTP_DIR;
}
/**
* ftp 用户登录信息
*
* @param userName ftp用户名
* @param password ftp用户密码
*/
public FtpDirDownloadTarget login(String userName, String password) {
return login(userName, password, null);
@Override protected boolean checkEntity() {
boolean b = getTargetType() == GROUP_FTP_DIR && checkDirPath() && checkUrl();
if (b) {
mEntity.save();
mTaskEntity.save();
if (mTaskEntity.getSubTaskEntities() != 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用户名
* @param password ftp用户密码
* @param account ftp账号
* @return {@code true}地址合法
*/
public FtpDirDownloadTarget 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;
private boolean checkUrl() {
final String url = mGroupName;
if (TextUtils.isEmpty(url)) {
ALog.e(TAG, "下载失败,url为null");
return false;
} else if (!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;
}
mTaskEntity.urlEntity.needLogin = true;
mTaskEntity.urlEntity.user = userName;
mTaskEntity.urlEntity.password = password;
mTaskEntity.urlEntity.account = account;
return this;
@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() {
DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(mEntity.getKey());
return task != null && task.isRunning();
@Override public FtpDirDownloadTarget login(String userName, String password, String account) {
return mDelegate.login(userName, password, account);
}
}

@ -16,22 +16,21 @@
package com.arialyy.aria.core.download;
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.util.ALog;
import com.arialyy.aria.core.inf.IFtpTarget;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
/**
* Created by lyy on 2016/12/5.
* https://github.com/AriaLyy/Aria
*/
public class FtpDownloadTarget extends DownloadTarget {
private final String TAG = "FtpDownloadTarget";
public class FtpDownloadTarget extends BaseNormalTarget<FtpDownloadTarget>
implements IFtpTarget<FtpDownloadTarget> {
private FtpDelegate<FtpDownloadTarget, DownloadEntity, DownloadTaskEntity> mDelegate;
FtpDownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) {
super(entity, targetName, refreshInfo);
init(refreshInfo);
this(entity.getUrl(), targetName, refreshInfo);
}
FtpDownloadTarget(String url, String targetName) {
@ -39,16 +38,29 @@ public class FtpDownloadTarget extends DownloadTarget {
}
FtpDownloadTarget(String url, String targetName, boolean refreshInfo) {
super(url, targetName);
initTarget(url, targetName, refreshInfo);
init(refreshInfo);
}
private void init(boolean refreshInfo) {
int lastIndex = url.lastIndexOf("/");
mEntity.setFileName(url.substring(lastIndex + 1, url.length()));
mTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(url);
mTaskEntity.refreshInfo = refreshInfo;
mTaskEntity.requestType = AbsTaskEntity.D_FTP;
mTaskEntity.setUrlEntity(CommonUtil.getFtpUrlInfo(url));
mTaskEntity.setRefreshInfo(refreshInfo);
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
* 2如果保存路径是文件夹路径/mnt/sdcard/则使用FTP服务器该文件的文件名
*
* @param downloadPath 路径必须为文件路径不能为文件夹路径
* @param filePath 路径必须为文件路径不能为文件夹路径
*/
@Override public FtpDownloadTarget setDownloadPath(@NonNull String downloadPath) {
if (TextUtils.isEmpty(downloadPath)) {
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());
}
}
public FtpDownloadTarget setFilePath(@NonNull String filePath) {
mTempFilePath = filePath;
return this;
}
/**
* 设置字符编码
*/
public FtpDownloadTarget charSet(String charSet) {
if (TextUtils.isEmpty(charSet)) return this;
mTaskEntity.charSet = charSet;
return this;
@Override protected int getTargetType() {
return FTP;
}
/**
* ftp 用户登录信息
*
* @param userName ftp用户名
* @param password ftp用户密码
*/
public FtpDownloadTarget login(String userName, String password) {
return login(userName, password, null);
@Override public FtpDownloadTarget charSet(String charSet) {
return mDelegate.charSet(charSet);
}
/**
* ftp 用户登录信息
*
* @param userName ftp用户名
* @param password ftp用户密码
* @param account ftp账号
*/
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;
@Override public FtpDownloadTarget login(String userName, String password) {
return mDelegate.login(userName, password);
}
mTaskEntity.urlEntity.needLogin = true;
mTaskEntity.urlEntity.user = userName;
mTaskEntity.urlEntity.password = password;
mTaskEntity.urlEntity.account = account;
return this;
@Override public FtpDownloadTarget login(String userName, String password, String account) {
return mDelegate.login(userName, password, account);
}
}

@ -16,20 +16,17 @@
package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.NetUtils;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
@ -73,65 +70,31 @@ public abstract class AbsGroupUtil implements IUtil {
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}需要
*/
boolean isNeedLoadFileSize = true;
//已经完成的任务数
private int mCompleteNum = 0;
//失败的任务数
private int mFailNum = 0;
int mCompleteNum = 0;
//停止的任务数
private int mStopNum = 0;
//实际的下载任务数
int mActualTaskNum = 0;
//初始化完成的任务数
int mInitNum = 0;
// 初始化失败的任务数
int mInitFailNum = 0;
//任务组大小
int mGroupSize = 0;
long mUpdateInterval = 1000;
private long mUpdateInterval = 1000;
AbsGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity groupEntity) {
mListener = listener;
mGTEntity = groupEntity;
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 =
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getUpdateInterval();
}
@ -190,11 +153,9 @@ public abstract class AbsGroupUtil implements IUtil {
* @param url 子任务下载地址
*/
public void cancelSubTask(String url) {
List<String> urls = mGTEntity.entity.getUrls();
if (urls != null && !urls.isEmpty() && urls.contains(url)) {
urls.remove(url);
DownloadTaskEntity det =
DbEntity.findFirst(DownloadTaskEntity.class, "url=? and isGroupTask='true'", url);
Set<String> urls = mTasksMap.keySet();
if (!urls.isEmpty() && urls.contains(url)) {
DownloadTaskEntity det = mTasksMap.get(url);
if (det != null) {
mTotalLen -= det.getEntity().getFileSize();
mGroupSize--;
@ -260,7 +221,6 @@ public abstract class AbsGroupUtil implements IUtil {
@Override public void cancel() {
closeTimer(false);
mListener.onCancel();
onCancel();
if (!mExePool.isShutdown()) {
mExePool.shutdown();
@ -273,38 +233,15 @@ public abstract class AbsGroupUtil implements IUtil {
dt.cancel();
}
}
delDownloadInfo();
mGTEntity.deleteData();
clearState();
CommonUtil.delDownloadGroupTaskConfig(mGTEntity.isRemoveFile(), mGTEntity.getEntity());
mListener.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() {
closeTimer(false);
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() {
isRunning = true;
mFailNum = 0;
mListener.onPre();
clearState();
onStart();
}
@ -345,6 +307,11 @@ public abstract class AbsGroupUtil implements IUtil {
}
private void clearState(){
mDownloaderMap.clear();
mFailMap.clear();
}
private void closeTimer(boolean isRunning) {
this.isRunning = isRunning;
if (mTimer != null) {
@ -389,7 +356,7 @@ public abstract class AbsGroupUtil implements IUtil {
*
* @param start 是否启动下载
*/
Downloader createChildDownload(DownloadTaskEntity taskEntity, boolean start) {
private Downloader createChildDownload(DownloadTaskEntity taskEntity, boolean start) {
ChildDownloadListener listener = new ChildDownloadListener(taskEntity);
Downloader dt = new Downloader(listener, taskEntity);
mDownloaderMap.put(taskEntity.getEntity().getUrl(), dt);
@ -400,44 +367,6 @@ public abstract class AbsGroupUtil implements IUtil {
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);
synchronized (AbsGroupUtil.class) {
mStopNum++;
if (mStopNum + mCompleteNum + mInitFailNum + mFailNum >= mGroupSize) {
if (mStopNum + mCompleteNum + mFailMap.size() == mGroupSize) {
closeTimer(false);
mListener.onStop(mCurrentLocation);
}
@ -515,13 +444,13 @@ public abstract class AbsGroupUtil implements IUtil {
saveData(IEntity.STATE_COMPLETE, subEntity.getFileSize());
handleSpeed(0);
mListener.onSubComplete(subEntity);
synchronized (AbsGroupUtil.class) {
synchronized (ChildDownloadListener.class) {
mCompleteNum++;
//如果子任务完成的数量和总任务数一致,表示任务组任务已经完成
if (mCompleteNum >= mGroupSize) {
closeTimer(false);
mListener.onComplete();
} else if (mStopNum + mCompleteNum + mInitFailNum + mFailNum >= mGroupSize) {
} else if (mFailMap.size() > 0 && mStopNum + mCompleteNum + mFailMap.size() >= mGroupSize) {
//如果子任务完成数量加上失败的数量和总任务数一致,则任务组停止下载
closeTimer(false);
mListener.onStop(mCurrentLocation);
@ -537,24 +466,27 @@ public abstract class AbsGroupUtil implements IUtil {
}
/**
* 失败后重试下载如果失败次数超过5次不再重试
* 重试下载
*/
private void reTry(boolean needRetry) {
synchronized (AriaManager.LOCK) {
if (subEntity.getFailNum() < 5 && isRunning && needRetry && NetUtils.isConnected(
AriaManager.APP)) {
synchronized (ChildDownloadListener.class) {
if (subEntity.getFailNum() < 5 && needRetry && NetUtils.isConnected(AriaManager.APP)) {
reStartTask();
} else {
mFailNum++;
mFailMap.put(subTaskEntity.getUrl(), subTaskEntity);
mListener.onSubFail(subEntity);
//如果失败的任务数大于实际的下载任务数,任务组停止下载
if (mFailNum >= mActualTaskNum) {
if (mFailMap.size() >= mExeMap.size()) {
closeTimer(false);
if (mFailMap.size() == mGroupSize) { //所有任务都失败了,则认为该任务组已经失败
mListener.onFail(true);
} else {
mListener.onStop(mCurrentLocation);
}
}
}
}
}
private void reStartTask() {
Timer timer = new Timer();
@ -574,11 +506,11 @@ public abstract class AbsGroupUtil implements IUtil {
}
private void saveData(int state, long location) {
subTaskEntity.state = state;
subTaskEntity.setState(state);
subEntity.setState(state);
subEntity.setComplete(state == IEntity.STATE_COMPLETE);
if (state == IEntity.STATE_CANCEL) {
subTaskEntity.deleteData();
subEntity.deleteData();
return;
} else if (subEntity.isComplete()) {
subEntity.setCompleteTime(System.currentTimeMillis());

@ -15,18 +15,21 @@
*/
package com.arialyy.aria.core.download.downloader;
import android.text.TextUtils;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.util.SSLContextUtil;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import java.util.zip.InflaterInputStream;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import org.apache.commons.net.ftp.FTPClient;
/**
* Created by lyy on 2017/1/18.
@ -34,6 +37,26 @@ import org.apache.commons.net.ftp.FTPClient;
*/
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)
throws ProtocolException {
conn.setRequestMethod(entity.requestEnum.name);
conn.setRequestMethod(entity.getRequestEnum().name);
Set<String> keys = null;
if (entity.headers != null && entity.headers.size() > 0) {
keys = entity.headers.keySet();
if (entity.getHeaders() != null && entity.getHeaders().size() > 0) {
keys = entity.getHeaders().keySet();
for (String key : keys) {
conn.setRequestProperty(key, entity.headers.get(key));
conn.setRequestProperty(key, entity.getHeaders().get(key));
}
}
if (keys == null || !keys.contains("Charset")) {
@ -86,6 +109,7 @@ class ConnectionHelp {
.append("image/jpeg, ")
.append("image/pjpeg, ")
.append("image/webp, ")
.append("image/apng, ")
.append("application/xml, ")
.append("application/xaml+xml, ")
.append("application/xhtml+xml, ")

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

@ -44,14 +44,20 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
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() {
mConfigFile = new File(CommonUtil.getFileConfigPath(true, mEntity.getFileName()));
mTempFile = new File(mEntity.getDownloadPath());
if (!mTaskEntity.isSupportBP) {
if (!mTaskEntity.isSupportBP()) {
isNewTask = true;
return;
}
if (mTaskEntity.isNewTask) {
if (mTaskEntity.isNewTask()) {
isNewTask = true;
return;
}
@ -67,20 +73,21 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
}
}
@Override protected void handleNewTask() {
@Override protected boolean handleNewTask() {
CommonUtil.createFile(mTempFile.getPath());
BufferedRandomAccessFile file = null;
try {
file = new BufferedRandomAccessFile(new File(mTempFile.getPath()), "rwd", 8192);
//设置文件长度
file.setLength(mEntity.getFileSize());
return true;
} catch (IOException e) {
failDownload("下载失败【downloadUrl:"
+ mEntity.getUrl()
+ "】\n【filePath:"
+ mEntity.getDownloadPath()
+ "】\n"
+ CommonUtil.getPrintException(e));
+ ALog.getExceptionString(e));
} finally {
if (file != null) {
try {
@ -90,10 +97,11 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
}
}
}
return false;
}
@Override protected AbsThreadTask selectThreadTask(SubThreadConfig<DownloadTaskEntity> config) {
switch (mTaskEntity.requestType) {
switch (mTaskEntity.getRequestType()) {
case AbsTaskEntity.D_FTP:
case AbsTaskEntity.D_FTP_DIR:
return new FtpThreadTask(mConstance, (IDownloadListener) mListener, config);
@ -108,6 +116,6 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
ALog.e(TAG, errorMsg);
mConstance.isRunning = false;
mListener.onFail(false);
ErrorHelp.saveError("", mEntity, "", errorMsg);
ErrorHelp.saveError(TAG, "", errorMsg);
}
}

@ -15,8 +15,8 @@
*/
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.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.util.ErrorHelp;
@ -27,6 +27,8 @@ import java.util.Set;
* ftp文件夹下载工具
*/
public class FtpDirDownloadUtil extends AbsGroupUtil {
private String TAG = "FtpDirDownloadUtil";
public FtpDirDownloadUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) {
super(listener, taskEntity);
}
@ -38,30 +40,35 @@ public class FtpDirDownloadUtil extends AbsGroupUtil {
@Override protected void onStart() {
super.onStart();
if (mGTEntity.getEntity().getFileSize() > 1) {
onPre();
startDownload();
} else {
new FtpDirInfoThread(mGTEntity, new OnFileInfoCallback() {
@Override public void onComplete(String url, int code) {
if (code >= 200 && code < 300) {
for (DownloadEntity entity : mGTEntity.entity.getSubTask()) {
mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
}
mActualTaskNum = mGTEntity.entity.getSubTask().size();
mGroupSize = mActualTaskNum;
mTotalLen = mGTEntity.entity.getFileSize();
@Override public void onComplete(String url, CompleteInfo info) {
if (info.code >= 200 && info.code < 300) {
onPre();
startDownload();
}
}
@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);
ErrorHelp.saveError("D_FTP_DIR", mGTEntity.getEntity(), "", errorMsg);
ErrorHelp.saveError(TAG, "", errorMsg);
}
}).start();
}
}
private void startDownload() {
if (mCompleteNum == mGroupSize) {
mListener.onComplete();
return;
}
int i = 0;
Set<String> keys = mExeMap.keySet();
for (String key : keys) {
@ -71,6 +78,10 @@ public class FtpDirDownloadUtil extends AbsGroupUtil {
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.common.AbsFtpInfoThread;
import com.arialyy.aria.core.common.CompleteInfo;
import com.arialyy.aria.core.common.OnFileInfoCallback;
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.inf.AbsTaskEntity;
import com.arialyy.aria.util.CommonUtil;
import java.nio.charset.Charset;
import java.util.ArrayList;
@ -37,7 +40,7 @@ class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DownloadGro
}
@Override protected String setRemotePath() {
return mTaskEntity.urlEntity.remotePath;
return mTaskEntity.getUrlEntity().remotePath;
}
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
@ -48,28 +51,43 @@ class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DownloadGro
@Override protected void onPreComplete(int code) {
super.onPreComplete(code);
mEntity.setFileSize(mSize);
mCallback.onComplete(mEntity.getKey(), code);
mCallback.onComplete(mEntity.getKey(), new CompleteInfo(code));
}
/**
* FTP文件夹的子任务实体 在这生成
*/
private void addEntity(String remotePath, FTPFile ftpFile) {
final FtpUrlEntity urlEntity = mTaskEntity.urlEntity;
final FtpUrlEntity urlEntity = mTaskEntity.getUrlEntity().clone();
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);
int lastIndex = remotePath.lastIndexOf("/");
String fileName = lastIndex < 0 ? CommonUtil.keyToHashKey(remotePath)
: 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.setGroupChild(true);
entity.setFileSize(ftpFile.getSize());
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) {
mEntity.setUrls(new ArrayList<String>());
}
if (mEntity.getSubTask() == null) {
mEntity.setSubTasks(new ArrayList<DownloadEntity>());
}
mEntity.getSubTask().add(entity);
mEntity.getSubEntities().add(entity);
mTaskEntity.getSubTaskEntities().add(taskEntity);
}
}

@ -16,6 +16,7 @@
package com.arialyy.aria.core.download.downloader;
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.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
@ -31,15 +32,15 @@ class FtpFileInfoThread extends AbsFtpInfoThread<DownloadEntity, DownloadTaskEnt
}
@Override protected String setRemotePath() {
return mTaskEntity.urlEntity.remotePath;
return mTaskEntity.getUrlEntity().remotePath;
}
@Override protected void onPreComplete(int code) {
super.onPreComplete(code);
if (mSize != mTaskEntity.getEntity().getFileSize()) {
mTaskEntity.isNewTask = true;
mTaskEntity.setNewTask(true);
}
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下载任务
*/
class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity> {
private final String TAG = "FtpDownloadThreadTask";
private final String TAG = "FtpThreadTask";
FtpThreadTask(StateConstance constance, IDownloadListener listener,
SubThreadConfig<DownloadTaskEntity> downloadInfo) {
@ -71,7 +71,7 @@ class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity>
return;
}
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 + "】");
is = client.retrieveFileStream(remotePath);
reply = client.getReplyCode();

@ -17,13 +17,17 @@ package com.arialyy.aria.core.download.downloader;
import android.text.TextUtils;
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.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
@ -54,7 +58,7 @@ class HttpFileInfoThread implements Runnable {
conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
conn.setConnectTimeout(mConnectTimeOut);
conn.setRequestMethod(mTaskEntity.requestEnum.name);
//conn.setChunkedStreamingMode(0);
conn.connect();
handleConnect(conn);
} catch (IOException e) {
@ -63,7 +67,7 @@ class HttpFileInfoThread implements Runnable {
+ "】\n【filePath:"
+ mEntity.getDownloadPath()
+ "】\n"
+ CommonUtil.getPrintException(e), true);
+ ALog.getExceptionString(e), true);
} finally {
if (conn != null) {
conn.disconnect();
@ -74,62 +78,122 @@ class HttpFileInfoThread implements Runnable {
private void handleConnect(HttpURLConnection conn) throws IOException {
long len = conn.getContentLength();
if (len < 0) {
String temp = conn.getHeaderField(mTaskEntity.contentLength);
String temp = conn.getHeaderField("Content-Length");
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();
boolean isComplete = false;
boolean end = false;
if (TextUtils.isEmpty(mEntity.getMd5Code())) {
String md5Code = conn.getHeaderField(mTaskEntity.md5Key);
String md5Code = conn.getHeaderField("Content-MD5");
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();
if (!TextUtils.isEmpty(disposition)) {
String disposition = conn.getHeaderField("Content-Disposition");
if (mTaskEntity.isUseServerFileName() && !TextUtils.isEmpty(disposition)) {
mEntity.setDisposition(CommonUtil.encryptBASE64(disposition));
if (disposition.contains(mTaskEntity.dispositionFileKey)) {
String[] infos = disposition.split("=");
mEntity.setServerFileName(URLDecoder.decode(infos[1], "utf-8"));
if (disposition.contains(";")) {
String[] infos = disposition.split(";");
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 (!checkLen(len)) return;
if (!checkLen(len) && !isChunked) {
return;
}
mEntity.setFileSize(len);
mTaskEntity.isSupportBP = true;
isComplete = true;
mTaskEntity.setSupportBP(true);
end = true;
} 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);
mTaskEntity.isSupportBP = false;
isComplete = true;
mTaskEntity.setSupportBP(false);
end = true;
} else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:404", true);
} else if (code == HttpURLConnection.HTTP_MOVED_TEMP
|| code == HttpURLConnection.HTTP_MOVED_PERM
|| code == HttpURLConnection.HTTP_SEE_OTHER) {
mTaskEntity.redirectUrl = conn.getHeaderField(mTaskEntity.redirectUrlKey);
mEntity.setRedirect(true);
mEntity.setRedirectUrl(mTaskEntity.redirectUrl);
handle302Turn(conn);
handleUrlReTurn(conn, conn.getHeaderField("Location"));
} else {
failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:" + code, true);
}
if (isComplete) {
if (end) {
mTaskEntity.setChunked(isChunked);
mTaskEntity.update();
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跳转
*/
private void handle302Turn(HttpURLConnection conn) throws IOException {
String newUrl = conn.getHeaderField(mTaskEntity.redirectUrlKey);
ALog.d(TAG, "30x跳转,location【 " + mTaskEntity.redirectUrlKey + "】" + "新url为【" + newUrl + "】");
private void handleUrlReTurn(HttpURLConnection conn, String newUrl) throws IOException {
ALog.d(TAG, "30x跳转,新url为【" + newUrl + "】");
if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null") || !newUrl.startsWith(
"http")) {
if (onFileInfoListener != null) {
@ -137,7 +201,13 @@ class HttpFileInfoThread implements Runnable {
}
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");
conn = (HttpURLConnection) new URL(newUrl).openConnection();
conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
@ -157,7 +227,7 @@ class HttpFileInfoThread implements Runnable {
*/
private boolean checkLen(long len) {
if (len != mEntity.getFileSize()) {
mTaskEntity.isNewTask = true;
mTaskEntity.setNewTask(true);
}
if (len < 0) {
failDownload("任务【" + mEntity.getUrl() + "】下载失败,文件长度小于0", true);

@ -27,6 +27,8 @@ import com.arialyy.aria.util.CommonUtil;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
@ -71,16 +73,65 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
conn = ConnectionHelp.setConnectParam(mConfig.TASK_ENTITY, conn);
conn.setConnectTimeout(STATE.CONNECT_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.seek(mConfig.START_LOCATION);
if (mTaskEntity.isChunked()) {
readChunk(is, file);
} else {
readNormal(is, file);
}
if (STATE.isCancel || STATE.isStop) {
return;
}
handleComplete();
} catch (MalformedURLException e) {
fail(mChildCurrentLocation, "下载链接异常", e);
} catch (IOException e) {
fail(mChildCurrentLocation, "下载失败【" + mConfig.URL + "】", e);
} catch (Exception e) {
fail(mChildCurrentLocation, "获取流失败", e);
} finally {
try {
if (file != null) {
file.close();
}
if (is != null) {
is.close();
}
if (conn != null) {
conn.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 读取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){
if (STATE.isCancel || STATE.isStop) {
break;
}
if (mSleepTime > 0) {
@ -89,11 +140,17 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
file.write(buffer, 0, len);
progress(len);
}
if (STATE.isCancel || STATE.isStop){
return;
}
/**
* 处理完成配置文件的更新或事件回调
*
* @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++;
@ -105,7 +162,10 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
STATE.isRunning = false;
mListener.onComplete();
}
if (STATE.isFail()){
} else {
STATE.FAIL_NUM++;
}
if (STATE.isFail()) {
STATE.isRunning = false;
mListener.onFail(false);
}
@ -114,27 +174,6 @@ final class HttpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEnt
STATE.isRunning = false;
mListener.onComplete();
}
} catch (MalformedURLException e) {
fail(mChildCurrentLocation, "下载链接异常", e);
} catch (IOException e) {
fail(mChildCurrentLocation, "下载失败【" + mConfig.URL + "】", e);
} catch (Exception e) {
fail(mChildCurrentLocation, "获取流失败", e);
} finally {
try {
if (file != null) {
file.close();
}
if (is != null) {
is.close();
}
if (conn != null) {
conn.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override protected String getTaskType() {

@ -16,6 +16,7 @@
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.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadTaskEntity;
@ -28,7 +29,7 @@ import com.arialyy.aria.util.ErrorHelp;
* D_HTTP\FTP单任务下载工具
*/
public class SimpleDownloadUtil implements IUtil, Runnable {
private static final String TAG = "SimpleDownloadUtil";
private String TAG = "SimpleDownloadUtil";
private IDownloadListener mListener;
private Downloader mDownloader;
private DownloadTaskEntity mTaskEntity;
@ -85,14 +86,14 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
private void failDownload(String msg, boolean needRetry) {
mListener.onFail(needRetry);
ErrorHelp.saveError("HTTP_DOWNLOAD", mTaskEntity.getEntity(), msg, "");
ErrorHelp.saveError(TAG, msg, "");
}
@Override public void run() {
mListener.onPre();
if (mTaskEntity.getEntity().getFileSize() <= 1
|| mTaskEntity.refreshInfo
|| mTaskEntity.requestType == AbsTaskEntity.D_FTP) {
|| mTaskEntity.isRefreshInfo()
|| mTaskEntity.getRequestType() == AbsTaskEntity.D_FTP) {
new Thread(createInfoThread()).start();
} else {
mDownloader.start();
@ -103,10 +104,10 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
* 通过链接类型创建不同的获取文件信息的线程
*/
private Runnable createInfoThread() {
switch (mTaskEntity.requestType) {
switch (mTaskEntity.getRequestType()) {
case AbsTaskEntity.D_FTP:
return new FtpFileInfoThread(mTaskEntity, new OnFileInfoCallback() {
@Override public void onComplete(String url, int code) {
@Override public void onComplete(String url, CompleteInfo info) {
mDownloader.start();
}
@ -116,7 +117,7 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
});
case AbsTaskEntity.D_HTTP:
return new HttpFileInfoThread(mTaskEntity, new OnFileInfoCallback() {
@Override public void onComplete(String url, int code) {
@Override public void onComplete(String url, CompleteInfo info) {
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.Parcelable;
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.
@ -31,7 +31,7 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
/**
* 单位转换后的速度
*/
@Ignore private String convertSpeed = "";
@Ignore private String convertSpeed;
/**
* 下载失败计数每次开始都重置为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;
/**

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

@ -17,8 +17,6 @@ package com.arialyy.aria.core.inf;
import android.os.Parcel;
import android.os.Parcelable;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.Ignore;
/**
* 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 isRedirect = false; //是否重定向
private String redirectUrl = ""; //重定向链接
private String redirectUrl; //重定向链接
public String getUrl() {
return url;

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

@ -18,8 +18,7 @@ package com.arialyy.aria.core.inf;
import com.arialyy.aria.core.FtpUrlEntity;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.Ignore;
import com.arialyy.aria.orm.Primary;
import com.arialyy.aria.orm.annotation.Ignore;
import java.util.HashMap;
import java.util.Map;
@ -55,103 +54,75 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
*/
public static final int U_FTP = 0xA2;
/**
* Task实体对应的key
*/
@Primary public String key = "";
/**
* 账号和密码
*/
@Ignore public FtpUrlEntity urlEntity;
@Ignore private FtpUrlEntity urlEntity;
/**
* 刷新信息 {@code true} 重新刷新下载信息
*/
@Ignore public boolean refreshInfo = false;
@Ignore private boolean refreshInfo = false;
/**
* 是否是新任务{@code true} 新任务
*/
@Ignore public boolean isNewTask = false;
@Ignore private boolean isNewTask = false;
/**
* 任务状态和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}
*/
public int requestType = D_HTTP;
private int requestType = D_HTTP;
/**
* http 请求头
*/
public Map<String, String> headers = new HashMap<>();
private Map<String, String> headers = new HashMap<>();
/**
* 字符编码默认为"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
*/
public String md5Key = "Content-MD5";
/**
* 是否使用服务器通过content-disposition传递的文件名内容格式{@code attachment;filename=***}
* 是否使用服务器通过content-disposition传递的文件名内容格式{@code attachment; filename="filename.jpg"}
* {@code true} 使用
*/
public 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";
private boolean useServerFileName = false;
/**
* 重定向链接
*/
public String redirectUrl = "";
private String redirectUrl = "";
/**
* 删除任务时是否删除已下载完成的文件
* 未完成的任务不管true还是false都会删除文件
* {@code true} 删除任务数据库记录并且删除已经下载完成的文件
* {@code false} 如果任务已经完成只删除任务数据库记录
*/
@Ignore public boolean removeFile = false;
@Ignore private boolean removeFile = false;
/**
* 是否支持断点, {@code true} 为支持断点
*/
public boolean isSupportBP = true;
private boolean isSupportBP = true;
/**
* 状态码
*/
public int code;
private int code;
public abstract ENTITY getEntity();
@ -164,12 +135,7 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
return getEntity().getState();
}
@Override public void deleteData() {
if (getEntity() != null) {
getEntity().deleteData();
}
super.deleteData();
}
public abstract String getKey();
@Override public void update() {
if (getEntity() != null) {
@ -177,4 +143,104 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
}
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;
import com.arialyy.aria.orm.Ignore;
import com.arialyy.aria.orm.annotation.Ignore;
/**
* Created by lyy on 2017/2/23.
@ -42,7 +42,7 @@ public interface IEntity {
*/
@Ignore int STATE_WAIT = 3;
/**
* 下载中
* 正在执行
*/
@Ignore int STATE_RUNNING = 4;
/**
@ -54,7 +54,7 @@ public interface IEntity {
*/
@Ignore int STATE_POST_PRE = 6;
/**
* 取消下载
* 删除任务
*/
@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;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.common.RequestEnum;
import java.util.Map;
/**
* Created by AriaL on 2017/6/29.
*/
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();
}

@ -15,8 +15,6 @@
*/
package com.arialyy.aria.core.inf;
import com.arialyy.aria.core.inf.IEventListener;
/**
* 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 com.arialyy.aria.core.download.DownloadEntity;
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.orm.DbEntity;
import java.io.File;
import java.util.List;
import java.util.UUID;
/**
* Created by Aria.Lao on 2017/11/1.
* 任务实体工厂
*/
class DTEntityFactory implements ITEntityFactory<DownloadEntity, DownloadTaskEntity> {
private static final String TAG = "DTEntityFactory";
private static volatile DTEntityFactory INSTANCE = null;
class DTEFactory implements INormalTEFactory<DownloadEntity, DownloadTaskEntity> {
private static final String TAG = "DTEFactory";
private static volatile DTEFactory INSTANCE = null;
private DTEntityFactory() {
private DTEFactory() {
}
public static DTEntityFactory getInstance() {
public static DTEFactory getInstance() {
if (INSTANCE == null) {
synchronized (DTEntityFactory.class) {
INSTANCE = new DTEntityFactory();
synchronized (DTEFactory.class) {
INSTANCE = new DTEFactory();
}
}
return INSTANCE;
@ -45,18 +48,24 @@ class DTEntityFactory implements ITEntityFactory<DownloadEntity, DownloadTaskEnt
/**
* 通过下载实体创建任务实体
*/
@Override public DownloadTaskEntity create(DownloadEntity entity) {
DownloadTaskEntity taskEntity =
DbEntity.findFirst(DownloadTaskEntity.class, "key=? and isGroupTask='false' and url=?",
private DownloadTaskEntity create(DownloadEntity entity) {
List<DTEWrapper> wrapper = DbEntity.findRelationData(DTEWrapper.class,
"DownloadTaskEntity.key=? and DownloadTaskEntity.isGroupTask='false' and DownloadTaskEntity.url=?",
entity.getDownloadPath(), entity.getUrl());
DownloadTaskEntity taskEntity;
if (wrapper != null && !wrapper.isEmpty()) {
taskEntity = wrapper.get(0).taskEntity;
if (taskEntity == null) {
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);
} else if (taskEntity.getEntity() == null || TextUtils.isEmpty(taskEntity.getEntity().getUrl())) {
taskEntity.setEntity(entity);
}
} else {
taskEntity = new DownloadTaskEntity();
}
taskEntity.setKey(entity.getDownloadPath());
taskEntity.setUrl(entity.getUrl());
taskEntity.setEntity(entity);
return taskEntity;
}
@ -80,6 +89,8 @@ class DTEntityFactory implements ITEntityFactory<DownloadEntity, DownloadTaskEnt
entity = new DownloadEntity();
entity.setUrl(downloadUrl);
entity.setGroupChild(false);
entity.setGroupName(null);
entity.setDownloadPath(UUID.randomUUID().toString().replace("-", "")); //设置临时路径
}
File file = new File(entity.getDownloadPath());
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.
*/
interface ITEntityFactory<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>> {
/**
* 通过信息实体创建任务实体
*/
TASK_ENTITY create(ENTITY entity);
interface INormalTEFactory<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>> {
/**
* 通过key创建任务只适应于单任务

@ -18,7 +18,6 @@ package com.arialyy.aria.core.manager;
import android.support.v4.util.LruCache;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
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.upload.UploadTaskEntity;
import com.arialyy.aria.util.ALog;
@ -29,7 +28,7 @@ import java.util.concurrent.locks.ReentrantLock;
/**
* Created by Aria.Lao on 2017/11/1.
* 任务实体管理器负责
* 任务实体管理器
*/
public class TEManager {
private static final String TAG = "TaskManager";
@ -51,18 +50,17 @@ public class TEManager {
}
/**
* 通过key创建任务只适应于单任务不能用于HTTP任务组可用于Ftp文件夹
* 如果是任务组请使用{@link #createGTEntity(Class, List)}
* 通过key创建任务只适应于单任务
*
* @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;
lock.lock();
try {
AbsTaskEntity tEntity = cache.get(convertKey(key));
if (tEntity == null || tEntity.getClass() != clazz) {
ITEntityFactory factory = chooseFactory(clazz);
INormalTEFactory factory = chooseNormalFactory(clazz);
if (factory == null) {
ALog.e(TAG, "任务实体创建失败");
return null;
@ -77,23 +75,44 @@ public class TEManager {
}
/**
* 创建任务实体
* 通过key创建不需要缓存的任务实体只适应于单任务
*
* @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;
lock.lock();
try {
String groupName = CommonUtil.getMd5Code(urls);
AbsTaskEntity tEntity = cache.get(convertKey(groupName));
if (tEntity == null || tEntity.getClass() != clazz) {
IGTEntityFactory factory = chooseGroupFactory(clazz);
IGTEFactory factory = chooseGroupFactory(clazz);
if (factory == null) {
ALog.e(TAG, "任务实体创建失败");
return null;
}
tEntity = factory.create(groupName, urls);
tEntity = factory.getGTE(groupName, urls);
cache.put(convertKey(groupName), tEntity);
}
return (TE) tEntity;
@ -103,23 +122,23 @@ public class TEManager {
}
/**
* 通过实体创建任务
* 通过ftp文件夹路径创建FTP文件夹实体
*
* @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;
lock.lock();
try {
AbsTaskEntity tEntity = cache.get(convertKey(absEntity.getKey()));
AbsTaskEntity tEntity = cache.get(convertKey(key));
if (tEntity == null || tEntity.getClass() != clazz) {
ITEntityFactory factory = chooseFactory(clazz);
IGTEFactory factory = chooseGroupFactory(clazz);
if (factory == null) {
ALog.e(TAG, "任务实体创建失败");
return null;
}
tEntity = factory.create(absEntity);
cache.put(convertKey(absEntity.getKey()), tEntity);
tEntity = factory.getFTE(key);
cache.put(convertKey(key), tEntity);
}
return (TE) tEntity;
} finally {
@ -127,26 +146,26 @@ public class TEManager {
}
}
private IGTEntityFactory chooseGroupFactory(Class clazz) {
private IGTEFactory chooseGroupFactory(Class clazz) {
if (clazz == DownloadGroupTaskEntity.class) {
return DGTEntityFactory.getInstance();
return DGTEFactory.getInstance();
}
return null;
}
private ITEntityFactory chooseFactory(Class clazz) {
private INormalTEFactory chooseNormalFactory(Class clazz) {
if (clazz == DownloadTaskEntity.class) {
return DTEntityFactory.getInstance();
return DTEFactory.getInstance();
} else if (clazz == UploadTaskEntity.class) {
return UTEntityFactory.getInstance();
} else if (clazz == DownloadGroupTaskEntity.class) {
return DGTEntityFactory.getInstance();
return UTEFactory.getInstance();
}
return null;
}
/**
* 从任务实体管理器中获取任务实体
* 从缓存中获取单任务实体如果任务实体不存在则创建任务实体
*
* @return 创建失败返回null
*/
public <TE extends AbsTaskEntity> TE getTEntity(Class<TE> clazz, String key) {
final Lock lock = this.lock;
@ -154,7 +173,53 @@ public class TEManager {
try {
AbsTaskEntity tEntity = cache.get(convertKey(key));
if (tEntity == 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 {
return (TE) tEntity;
}
@ -189,7 +254,7 @@ public class TEManager {
final Lock lock = this.lock;
lock.lock();
try {
return cache.put(convertKey(te.key), te) != null;
return cache.put(convertKey(te.getKey()), te) != null;
} finally {
lock.unlock();
}
@ -210,6 +275,7 @@ public class TEManager {
}
private String convertKey(String key) {
key = key.trim();
final Lock lock = this.lock;
lock.lock();
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;
import android.text.TextUtils;
import com.arialyy.aria.core.upload.UploadEntity;
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.util.Regular;
import java.util.List;
import java.util.regex.Pattern;
/**
* Created by Aria.Lao on 2017/11/1.
* 任务实体工厂
*/
class UTEntityFactory implements ITEntityFactory<UploadEntity, UploadTaskEntity> {
private static final String TAG = "DTEntityFactory";
private static volatile UTEntityFactory INSTANCE = null;
class UTEFactory implements INormalTEFactory<UploadEntity, UploadTaskEntity> {
private static final String TAG = "DTEFactory";
private static volatile UTEFactory INSTANCE = null;
private UTEntityFactory() {
private UTEFactory() {
}
public static UTEntityFactory getInstance() {
public static UTEFactory getInstance() {
if (INSTANCE == null) {
synchronized (UTEntityFactory.class) {
INSTANCE = new UTEntityFactory();
synchronized (UTEFactory.class) {
INSTANCE = new UTEFactory();
}
}
return INSTANCE;
}
@Override public UploadTaskEntity create(UploadEntity entity) {
UploadTaskEntity uTaskEntity =
DbEntity.findFirst(UploadTaskEntity.class, "key=?", entity.getFilePath());
private UploadTaskEntity create(UploadEntity entity) {
List<UTEWrapper> wrapper =
DbEntity.findRelationData(UTEWrapper.class, "UploadTaskEntity.key=?",
entity.getFilePath());
if (wrapper != null && !wrapper.isEmpty()) {
UploadTaskEntity uTaskEntity = wrapper.get(0).taskEntity;
if (uTaskEntity == null) {
uTaskEntity = new UploadTaskEntity();
uTaskEntity.entity = entity;
}
if (uTaskEntity.entity == null) {
uTaskEntity.entity = entity;
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;
}
}
@Override public UploadTaskEntity create(String key) {
@ -67,14 +79,12 @@ class UTEntityFactory implements ITEntityFactory<UploadEntity, UploadTaskEntity>
UploadEntity entity = UploadEntity.findFirst(UploadEntity.class, "filePath=?", filePath);
if (entity == null) {
entity = new UploadEntity();
//String regex = "[/|\\\\|//]";
String regex = Regular.REG_FILE_NAME;
Pattern p = Pattern.compile(regex);
String[] strs = p.split(filePath);
String fileName = strs[strs.length - 1];
entity.setFileName(fileName);
entity.setFilePath(filePath);
entity.insert();
}
return entity;
}

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

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

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

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

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

@ -13,20 +13,16 @@
* See the License for the specific language governing permissions and
* 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.AbsTarget;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import java.util.List;
/**
* 任务组通过组创建任务
* Created by Aria.Lao on 2017/11/1.
* Created by AriaL on 2017/6/29.
*/
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) {
mTaskEntity.state = state;
mTaskEntity.setState(state);
mEntity.setState(state);
mEntity.setComplete(state == IEntity.STATE_COMPLETE);
if (state == IEntity.STATE_CANCEL) {
mTaskEntity.deleteData();
mEntity.deleteData();
return;
} else if (mEntity.isComplete()) {
mEntity.setCompleteTime(System.currentTimeMillis());

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

@ -19,15 +19,17 @@ import android.os.Parcel;
import android.os.Parcelable;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.orm.Foreign;
import com.arialyy.aria.orm.Primary;
import com.arialyy.aria.orm.annotation.Primary;
/**
* Created by lyy on 2017/2/9.
* 上传文件实体
*/
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.normal.NormalCmdFactory;
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.scheduler.ISchedulerListener;
import com.arialyy.aria.core.scheduler.UploadSchedulers;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CheckUtil;
@ -36,7 +35,6 @@ import java.util.Set;
*/
public class UploadReceiver extends AbsReceiver<UploadEntity> {
private static final String TAG = "UploadReceiver";
public ISchedulerListener<UploadTask> listener;
/**
* 加载HTTP单文件上传任务
@ -72,10 +70,32 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
return DbEntity.findFirst(UploadEntity.class, "filePath=?", filePath) != null;
}
/**
* 获取所有普通上传任务
* 获取未完成的普通任务列表{@link #getAllNotCompletTask()}
* 获取已经完成的普通任务列表{@link #getAllCompleteTask()}
*/
@Override public List<UploadEntity> getTaskList() {
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() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(NormalCmdFactory.getInstance()
@ -93,7 +113,7 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
@Override public void removeAllTask(boolean removeFile) {
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();
Set<String> keys = am.getReceiver().keySet();
@ -104,7 +124,6 @@ public class UploadReceiver extends AbsReceiver<UploadEntity> {
@Override public void destroy() {
targetName = null;
listener = null;
}
/**

@ -16,16 +16,19 @@
package com.arialyy.aria.core.upload;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.inf.AbsUploadTarget;
import com.arialyy.aria.core.manager.TEManager;
import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.core.delegate.HttpHeaderDelegate;
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.
* 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) {
this.mTargetName = targetName;
@ -33,24 +36,19 @@ public class UploadTarget extends AbsUploadTarget<UploadTarget, UploadEntity, Up
}
private void initTask(String filePath) {
mTaskEntity = TEManager.getInstance().getTEntity(UploadTaskEntity.class, 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());
initTarget(filePath);
//http暂时不支持断点上传
mTaskEntity.isSupportBP = false;
mTaskEntity.requestType = AbsTaskEntity.U_HTTP;
mTaskEntity.setSupportBP(false);
mTaskEntity.setRequestType(AbsTaskEntity.U_HTTP);
mDelegate = new HttpHeaderDelegate<>(this, mTaskEntity);
}
/**
* 设置userAgent
*/
public UploadTarget setUserAngent(@NonNull String userAgent) {
mTaskEntity.userAgent = userAgent;
mTaskEntity.setUserAgent(userAgent);
return this;
}
@ -60,7 +58,7 @@ public class UploadTarget extends AbsUploadTarget<UploadTarget, UploadEntity, Up
* @param attachment 附件key
*/
public UploadTarget setAttachment(@NonNull String attachment) {
mTaskEntity.attachment = attachment;
mTaskEntity.setAttachment(attachment);
return this;
}
@ -70,7 +68,19 @@ public class UploadTarget extends AbsUploadTarget<UploadTarget, UploadEntity, Up
* @param contentType tipmultipart/form-data
*/
public UploadTarget setContentType(String contentType) {
mTaskEntity.contentType = contentType;
mTaskEntity.setContentType(contentType);
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;
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.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
@ -39,8 +40,7 @@ class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity>
}
@Override protected String setRemotePath() {
String url = mEntity.getUrl();
return mTaskEntity.urlEntity.remotePath + "/" + mEntity.getFileName();
return mTaskEntity.getUrlEntity().remotePath + "/" + mEntity.getFileName();
}
/**
@ -57,6 +57,7 @@ class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity>
//远程文件已完成
if (ftpFile.getSize() == mEntity.getFileSize()) {
isComplete = true;
ALog.d(TAG, "FTP服务器上已存在该文件【" + ftpFile.getName() + "】");
} else {
ALog.w(TAG, "FTP服务器已存在未完成的文件【"
+ ftpFile.getName()
@ -64,16 +65,16 @@ class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity>
+ ftpFile.getSize()
+ "】"
+ "尝试从位置:"
+ ftpFile.getSize()
+ (ftpFile.getSize() - 1)
+ "开始上传");
File configFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
Properties pro = CommonUtil.loadConfig(configFile);
String key = mEntity.getFileName() + "_record_" + 0;
mTaskEntity.isNewTask = false;
mTaskEntity.setNewTask(false);
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);
}
}
@ -82,6 +83,6 @@ class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity>
@Override protected void onPreComplete(int 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.
* FTP 单线程上传任务需要FTP 服务器给用户打开删除和读入IO的权限
* FTP 单线程上传任务需要FTP 服务器给用户打开append和write的权限
*/
class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
private final String TAG = "FtpUploadThreadTask";
@ -112,9 +112,9 @@ class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
}
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(
("/" + mTaskEntity.urlEntity.remotePath + mEntity.getFileName()).getBytes(charSet),
("/" + mTaskEntity.getUrlEntity().remotePath + "/" + mEntity.getFileName()).getBytes(charSet),
SERVER_CHARSET);
}

@ -15,6 +15,7 @@
*/
package com.arialyy.aria.core.upload.uploader;
import android.util.Log;
import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig;
@ -65,30 +66,33 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
try {
url = new URL(mEntity.getUrl());
mHttpConn = (HttpURLConnection) url.openConnection();
mHttpConn.setRequestMethod(mTaskEntity.getRequestEnum().name);
mHttpConn.setUseCaches(false);
mHttpConn.setDoOutput(true);
mHttpConn.setDoInput(true);
mHttpConn.setRequestProperty("Connection", "Keep-Alive");
mHttpConn.setRequestProperty("Content-Type",
mTaskEntity.contentType + "; boundary=" + BOUNDARY);
mHttpConn.setRequestProperty("User-Agent", mTaskEntity.userAgent);
mTaskEntity.getContentType() + "; boundary=" + BOUNDARY);
mHttpConn.setRequestProperty("User-Agent", mTaskEntity.getUserAgent());
mHttpConn.setConnectTimeout(5000);
//mHttpConn.setRequestProperty("Range", "bytes=" + 0 + "-" + "100");
//内部缓冲区---分段上传防止oom
mHttpConn.setChunkedStreamingMode(1024);
//添加Http请求头部
Set<String> keys = mTaskEntity.headers.keySet();
Set<String> keys = mTaskEntity.getHeaders().keySet();
for (String key : keys) {
mHttpConn.setRequestProperty(key, mTaskEntity.headers.get(key));
mHttpConn.setRequestProperty(key, mTaskEntity.getHeaders().get(key));
}
mOutputStream = mHttpConn.getOutputStream();
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) {
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));
mListener.onComplete();
} catch (Exception e) {
@ -119,7 +123,7 @@ class HttpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
.append("\"")
.append(LINE_END);
writer.append("Content-Type: text/plain; charset=")
.append(mTaskEntity.charSet)
.append(mTaskEntity.getCharSet())
.append(LINE_END);
writer.append(LINE_END);
writer.append(value).append(LINE_END);

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

@ -50,7 +50,7 @@ class Uploader extends AbsFileer<UploadEntity, UploadTaskEntity> {
*/
protected void checkTask() {
mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
if (!mTaskEntity.isSupportBP) {
if (!mTaskEntity.isSupportBP()) {
isNewTask = true;
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;
}
@Override protected AbsThreadTask selectThreadTask(SubThreadConfig<UploadTaskEntity> config) {
switch (mTaskEntity.requestType) {
switch (mTaskEntity.getRequestType()) {
case AbsTaskEntity.U_FTP:
return new FtpThreadTask(mConstance, mListener, config);
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;
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.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
@ -32,9 +30,15 @@ import java.util.Map;
* 数据库配置信息
*/
class DBConfig {
/*adb pull /mnt/sdcard/Android/data/com.arialyy.simple/files/DB/AriaLyyDb d:/db*/
static Map<String, Class> mapping = new HashMap<>();
static String DB_NAME;
static int VERSION = 23;
static int VERSION = 31;
/**
* 是否将数据库保存在Sd卡{@code true}
*/
static final boolean SAVE_IN_SDCARD = false;
static {
if (TextUtils.isEmpty(DB_NAME)) {
@ -46,13 +50,11 @@ class DBConfig {
}
static {
mapping.put("DownloadEntity", DownloadEntity.class);
mapping.put("DownloadGroupTaskEntity", DownloadGroupTaskEntity.class);
mapping.put("DownloadGroupEntity", DownloadGroupEntity.class);
mapping.put("DownloadTaskEntity", DownloadTaskEntity.class);
mapping.put("DownloadGroupTaskEntity", DownloadGroupTaskEntity.class);
mapping.put("UploadEntity", UploadEntity.class);
mapping.put("UploadTaskEntity", UploadTaskEntity.class);
mapping.put("ErrorEntity", ErrorEntity.class);
//mapping.put("UrlMapping", UrlMapping.class);
mapping.put("DownloadEntity", DownloadEntity.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;
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.Map;
/**
* Created by lyy on 2015/11/2.
* 所有数据库实体父类
*/
public class DbEntity {
public abstract class DbEntity {
private static final Object LOCK = new Object();
protected int rowID = -1;
protected long rowID = -1;
protected DbEntity() {
}
///**
// * 关键字模糊检索全文
// *
// * @param column 需要查找的列
// * @param mathSql 关键字语法,exsimple “white OR green”、“blue AND red”、“white NOT green”
// */
//public static <T extends DbEntity> List<T> searchData(Class<T> clazz, String column, String mathSql) {
// return DbUtil.getInstance().searchData(clazz, column, mathSql);
//}
/**
* 查询关联数据
*
* @param expression 查询条件
*/
public static <T extends AbsWrapper> List<T> findRelationData(Class<T> clazz,
String... expression) {
return DelegateWrapper.getInstance().findRelationData(clazz, expression);
}
/**
* 检查某个字段的值是否存在
@ -53,21 +47,21 @@ public class DbEntity {
* @return {@code true}该字段的对应的value已存在
*/
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) {
DbUtil.getInstance().clean(clazz);
DelegateWrapper.getInstance().clean(clazz);
}
/**
* 直接执行sql语句
*/
public static void exeSql(String sql) {
DbUtil.getInstance().exeSql(sql);
DelegateWrapper.getInstance().exeSql(sql);
}
/**
@ -76,7 +70,7 @@ public class DbEntity {
* @return 没有数据返回null
*/
public static <T extends DbEntity> List<T> findAllData(Class<T> clazz) {
DbUtil util = DbUtil.getInstance();
DelegateWrapper util = DelegateWrapper.getInstance();
return util.findAllData(clazz);
}
@ -97,7 +91,7 @@ public class DbEntity {
* @return 没有数据返回null
*/
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);
}
@ -110,25 +104,11 @@ public class DbEntity {
* @return 没有数据返回null
*/
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);
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>
*/
public static <T extends DbEntity> void deleteData(Class<T> clazz, String... expression) {
DbUtil util = DbUtil.getInstance();
DelegateWrapper util = DelegateWrapper.getInstance();
util.delData(clazz, expression);
}
@ -151,11 +131,12 @@ public class DbEntity {
* 修改数据
*/
public void update() {
DbUtil.getInstance().modifyData(this);
DelegateWrapper.getInstance().modifyData(this);
}
/**
* 保存自身如果表中已经有数据则更新数据否则插入数据
* 只有 target中checkEntity成功后才能保存创建实体部分也不允许保存
*/
public void save() {
synchronized (LOCK) {
@ -171,58 +152,14 @@ public class DbEntity {
* 查找数据在表中是否存在
*/
private boolean thisIsExist() {
DbUtil util = DbUtil.getInstance();
return util.isExist(getClass(), rowID);
DelegateWrapper util = DelegateWrapper.getInstance();
return rowID != -1 && util.isExist(getClass(), rowID);
}
/**
* 插入数据
* 插入数据只有 target中checkEntity成功后才能插入创建实体部分也不允许操作
*/
public void insert() {
DbUtil.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();
}
DelegateWrapper.getInstance().insertData(this);
}
}

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