From 39ac574d0c31770217b75555c1f7eb1f0c229a7b Mon Sep 17 00:00:00 2001 From: e <511455842@qq.com> Date: Mon, 12 Feb 2018 21:08:52 +0800 Subject: [PATCH 01/22] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=94=AF=E6=8C=81post?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Aria/build.gradle | 4 ++-- .../aria/core/upload/uploader/HttpThreadTask.java | 2 ++ .../com/arialyy/simple/upload/HttpUploadActivity.java | 10 ++++++---- .../com/arialyy/aria/core/upload/UploadTaskEntity.java | 2 +- build.gradle | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Aria/build.gradle b/Aria/build.gradle index f95e9d8f..4d7ee364 100644 --- a/Aria/build.gradle +++ b/Aria/build.gradle @@ -23,8 +23,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' diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java index 8783aaeb..3143737f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/HttpThreadTask.java @@ -65,9 +65,11 @@ class HttpThreadTask extends AbsThreadTask { try { url = new URL(mEntity.getUrl()); mHttpConn = (HttpURLConnection) url.openConnection(); + mHttpConn.setRequestMethod(mTaskEntity.requestEnum.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); diff --git a/app/src/main/java/com/arialyy/simple/upload/HttpUploadActivity.java b/app/src/main/java/com/arialyy/simple/upload/HttpUploadActivity.java index 92089de2..c0b942c7 100644 --- a/app/src/main/java/com/arialyy/simple/upload/HttpUploadActivity.java +++ b/app/src/main/java/com/arialyy/simple/upload/HttpUploadActivity.java @@ -21,6 +21,7 @@ import butterknife.Bind; import butterknife.OnClick; import com.arialyy.annotations.Upload; import com.arialyy.aria.core.Aria; +import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.upload.UploadTask; import com.arialyy.frame.util.FileUtil; import com.arialyy.frame.util.show.L; @@ -37,7 +38,7 @@ public class HttpUploadActivity extends BaseActivity { private static final String TAG = "HttpUploadActivity"; @Bind(R.id.pb) HorizontalProgressBarWithNumber mPb; - private static final String FILE_PATH = "/mnt/sdcard/test.txt"; + private static final String FILE_PATH = "/mnt/sdcard/test.apk"; @Override protected int setLayoutId() { return R.layout.activity_upload; @@ -51,10 +52,11 @@ public class HttpUploadActivity extends BaseActivity { @OnClick(R.id.upload) void upload() { Aria.upload(HttpUploadActivity.this).load(FILE_PATH) - //.setUploadUrl( - // "http://lib-test.xzxyun.com:8042/Api/upload?data={\"type\":\"1\",\"fileType\":\".txt\"}") - .setUploadUrl("http://192.168.1.6:8080/upload/sign_file/").setAttachment("file") + .setUploadUrl( + "http://lib-test.xzxyun.com:8042/Api/upload?data={\"type\":\"1\",\"fileType\":\".apk\"}") + //.setUploadUrl("http://192.168.1.6:8080/upload/sign_file/").setAttachment("file") //.addHeader("iplanetdirectorypro", "11a09102fb934ad0bc206f9c611d7933") + .setRequestMode(RequestEnum.POST) .start(); } diff --git a/aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskEntity.java b/aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskEntity.java index 11410be7..83ad03af 100644 --- a/aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskEntity.java +++ b/aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskEntity.java @@ -27,7 +27,7 @@ import java.util.Map; public class UploadTaskEntity extends AbsNormalTaskEntity { public String attachment; //文件上传需要的key public String contentType = "multipart/form-data"; //上传的文件类型 - public String userAgent = "User-Agent"; + public String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)"; @OneToOne(table = UploadEntity.class, key = "filePath") public UploadEntity entity; public String filePath = ""; diff --git a/build.gradle b/build.gradle index 40de7a5e..c525f86b 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ task clean(type: Delete) { ext { userOrg = 'arialyy' groupId = 'com.arialyy.aria' - publishVersion = '3.3.14' + publishVersion = '3.3.15' // publishVersion = '1.0.3' //FTP插件 repoName='maven' desc = 'android 下载框架' From d935e20822501d545d4986ad9c51c866367e426e Mon Sep 17 00:00:00 2001 From: laoyuyu <511455842@qq.com> Date: Wed, 28 Feb 2018 21:14:21 +0800 Subject: [PATCH 02/22] fix bug --- .gitignore | 3 ++- .../main/java/com/arialyy/aria/core/AriaManager.java | 4 ++-- .../arialyy/aria/core/download/DownloadReceiver.java | 1 + .../arialyy/simple/download/SingleTaskActivity.java | 11 ++++++++--- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 6b0f8a6a..04f27198 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ /.idea .idea /cache -*.log \ No newline at end of file +*.log +uml \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java index 9f7316c5..bddd61f9 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java @@ -288,8 +288,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) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java index 21ca515b..844ee9dc 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java @@ -207,6 +207,7 @@ public class DownloadReceiver extends AbsReceiver { /** * 取消注册,如果是Activity或fragment,Aria会界面销毁时自动调用该方法。 + * 如果在activity中一定要调用该方法,那么请在onDestroy()中调用 * 如果是Dialog或popupwindow,需要你在撤销界面时调用该方法 */ @Override public void unRegister() { diff --git a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java index 18123af9..fd2d1acb 100644 --- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java @@ -46,7 +46,7 @@ public class SingleTaskActivity extends BaseActivity { private static final String DOWNLOAD_URL = //"http://kotlinlang.org/docs/kotlin-docs.pdf"; //"https://atom-installer.github.com/v1.13.0/AtomSetup.exe?s=1484074138&ext=.exe"; - //"http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk"; + "http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk"; //"http://sitcac.daxincf.cn/wp-content/uploads/swift_vido/01/element.mp4_1"; //"http://120.25.196.56:8000/filereq?id=15692406294&ipncid=105635&client=android&filename=20170819185541.avi"; //"http://down2.xiaoshuofuwuqi.com/d/file/filetxt/20170608/14/%BA%DA%CE%D7%CA%A6%E1%C8%C6%F0.txt"; @@ -58,7 +58,7 @@ public class SingleTaskActivity extends BaseActivity { //"http://ox.konsung.net:5555/ksdc-web/download/downloadFile/?fileName=ksdc_1.0.2.apk&rRange=0-"; //"http://gdown.baidu.com/data/wisegame/0904344dee4a2d92/QQ_718.apk"; //"http://qudao.5535.cn/one/game.html?game=531&cpsuser=xiaoeryu2"; - "https://bogoe-res.mytbz.com/tbzengsong/If You're Happy.mp3"; + //"https://bogoe-res.mytbz.com/tbzengsong/If You're Happy.mp3"; //"http://ozr0ucjs5.bkt.clouddn.com/51_box-104_20180131202610.apk"; @Bind(R.id.start) Button mStart; @Bind(R.id.stop) Button mStop; @@ -67,7 +67,7 @@ public class SingleTaskActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Aria.download(this).register(); + Aria.upload(this).register(); } /** @@ -240,4 +240,9 @@ public class SingleTaskActivity extends BaseActivity { super.onDestroy(); //Aria.download(this).unRegister(); } + + @Override protected void onStop() { + super.onStop(); + Aria.download(this).unRegister(); + } } \ No newline at end of file From 066bbbd0061aea27794f9f2757e12409f6bdc951 Mon Sep 17 00:00:00 2001 From: laoyuyu <511455842@qq.com> Date: Fri, 2 Mar 2018 14:43:49 +0800 Subject: [PATCH 03/22] fix bug https://github.com/AriaLyy/Aria/issues/200 --- .../main/java/com/arialyy/aria/core/AriaManager.java | 2 +- .../com/arialyy/aria/core/scheduler/AbsSchedulers.java | 10 +++++++--- .../arialyy/simple/download/SingleTaskActivity.java | 8 +++++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java index bddd61f9..688010dc 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java @@ -347,7 +347,7 @@ import org.xml.sax.SAXException; if (TextUtils.isEmpty(key)) { throw new IllegalArgumentException("未知类型"); } - key += isDownload ? DOWNLOAD : UPLOAD; + key += (isDownload ? DOWNLOAD : UPLOAD) + obj.hashCode(); return key; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java b/Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java index 83f82b28..35a030d1 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java +++ b/Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java @@ -54,12 +54,12 @@ abstract class AbsSchedulers listener = mObservers.get(targetName); + AbsSchedulerListener 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 + "】观察者"); } @@ -73,12 +73,16 @@ abstract class AbsSchedulers>> iter = mObservers.entrySet().iterator(); iter.hasNext(); ) { Map.Entry> 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(); + } + /** * 创建代理类 * diff --git a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java index fd2d1acb..58a781ce 100644 --- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java @@ -16,6 +16,7 @@ package com.arialyy.simple.download; +import android.content.Intent; import android.os.Bundle; import android.os.Environment; import android.util.Log; @@ -67,7 +68,7 @@ public class SingleTaskActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Aria.upload(this).register(); + Aria.download(this).register(); } /** @@ -207,7 +208,8 @@ public class SingleTaskActivity extends BaseActivity { startD(); break; case R.id.stop: - Aria.download(this).load(DOWNLOAD_URL).stop(); + //Aria.download(this).load(DOWNLOAD_URL).stop(); + startActivity(new Intent(this, SingleTaskActivity.class)); //Aria.download(this).load(DOWNLOAD_URL).removeRecord(); break; case R.id.cancel: @@ -243,6 +245,6 @@ public class SingleTaskActivity extends BaseActivity { @Override protected void onStop() { super.onStop(); - Aria.download(this).unRegister(); + //Aria.download(this).unRegister(); } } \ No newline at end of file From a7174340ae375481b75585037d93bca2e2f34e7a Mon Sep 17 00:00:00 2001 From: laoyuyu Date: Fri, 9 Mar 2018 22:01:31 +0800 Subject: [PATCH 04/22] =?UTF-8?q?=E4=BC=98=E5=8C=96target=E7=BB=93?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I7ec154c9d5d5319b5dc8fdbf908f4358dbf4baaf --- .../com/arialyy/aria/core/AriaManager.java | 23 +- .../aria/core/delegate/FtpDelegate.java | 64 ++++++ .../core/delegate/HttpHeaderDelegate.java | 202 +++++++++++++++++ .../aria/core/download/AbsDownloadTarget.java | 110 +++++++++ .../aria/core/download/BaseGroupTarget.java | 155 +++++-------- .../aria/core/download/BaseNormalTarget.java | 200 +++++++++++++++++ .../core/download/DownloadGroupEntity.java | 2 +- .../core/download/DownloadGroupTarget.java | 209 +++++++++++++++++- .../aria/core/download/DownloadReceiver.java | 27 ++- .../aria/core/download/DownloadTarget.java | 135 +++++------ .../core/download/FtpDirDownloadTarget.java | 82 +++---- .../aria/core/download/FtpDownloadTarget.java | 95 +++----- .../aria/core/inf/AbsDownloadTarget.java | 151 ------------- .../com/arialyy/aria/core/inf/AbsTarget.java | 195 ++++++---------- .../aria/core/inf/AbsUploadTarget.java | 65 ------ .../com/arialyy/aria/core/inf/IFtpTarget.java | 45 ++++ .../aria/core/inf/IHttpHeaderTarget.java | 79 +++++++ .../com/arialyy/aria/core/inf/ITarget.java | 45 ++-- .../arialyy/aria/core/queue/AbsTaskQueue.java | 6 +- .../aria/core/upload/AbsUploadTarget.java | 28 +++ .../aria/core/upload/BaseNormalTarget.java | 139 ++++++++++++ .../aria/core/upload/FtpUploadTarget.java | 78 ++----- .../aria/core/upload/UploadReceiver.java | 2 - .../aria/core/upload/UploadTarget.java | 64 ++++-- .../java/com/arialyy/aria/util/CheckUtil.java | 28 +++ .../com/arialyy/aria/util/CommonUtil.java | 26 +++ .../download/group/DownloadGroupActivity.java | 2 +- .../group/FTPDirDownloadActivity.java | 2 +- 28 files changed, 1509 insertions(+), 750 deletions(-) create mode 100644 Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java create mode 100644 Aria/src/main/java/com/arialyy/aria/core/delegate/HttpHeaderDelegate.java create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/inf/AbsDownloadTarget.java delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java create mode 100644 Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java create mode 100644 Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java create mode 100644 Aria/src/main/java/com/arialyy/aria/core/upload/AbsUploadTarget.java create mode 100644 Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java diff --git a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java index 9f7316c5..59a744aa 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java @@ -97,7 +97,7 @@ import org.xml.sax.SAXException; } /** - * 设置Aria 日志级别 + * 设置Aria的日志级别 * * @param level {@link ALog#LOG_LEVEL_VERBOSE} */ @@ -106,20 +106,34 @@ import org.xml.sax.SAXException; } /** - * 设置上传任务的执行队列类型 + * 设置上传任务的执行队列类型,后续版本会删除该api,请使用: + *
+   *   
+   *     Aria.get(this).getUploadConfig().setQueueMod(mod.tag)
+   *   
+   * 
    *
    * @param mod {@link QueueMod}
+   * @deprecated 后续版本会删除该api
    */
+  @Deprecated
   public AriaManager setUploadQueueMod(QueueMod mod) {
     mUConfig.setQueueMod(mod.tag);
     return this;
   }
 
   /**
-   * 设置下载任务的执行队列类型
+   * 设置下载任务的执行队列类型,后续版本会删除该api,请使用:
+   * 
+   *   
+   *     Aria.get(this).getDownloadConfig().setQueueMod(mod.tag)
+   *   
+   * 
    *
    * @param mod {@link QueueMod}
+   * @deprecated 后续版本会删除该api
    */
+  @Deprecated
   public AriaManager setDownloadQueueMod(QueueMod mod) {
     mDConfig.setQueueMod(mod.tag);
     return this;
@@ -270,7 +284,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) {
diff --git a/Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java b/Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java
new file mode 100644
index 00000000..578c478f
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java
@@ -0,0 +1,64 @@
+/*
+ * 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>
+    implements IFtpTarget {
+  private static final String TAG = "FtpDelegate";
+  private ENTITY mEntity;
+  private TASK_ENTITY mTaskEntity;
+
+  public FtpDelegate(TASK_ENTITY mTaskEntity) {
+    this.mTaskEntity = mTaskEntity;
+    mEntity = mTaskEntity.getEntity();
+  }
+
+  @Override public TARGET charSet(String charSet) {
+    if (TextUtils.isEmpty(charSet)) return (TARGET) this;
+    mTaskEntity.charSet = charSet;
+    return (TARGET) this;
+  }
+
+  @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 (TARGET) this;
+    } else if (TextUtils.isEmpty(password)) {
+      ALog.e(TAG, "密码不能为null");
+      return (TARGET) this;
+    }
+    mTaskEntity.urlEntity.needLogin = true;
+    mTaskEntity.urlEntity.user = userName;
+    mTaskEntity.urlEntity.password = password;
+    mTaskEntity.urlEntity.account = account;
+    return (TARGET) this;
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/delegate/HttpHeaderDelegate.java b/Aria/src/main/java/com/arialyy/aria/core/delegate/HttpHeaderDelegate.java
new file mode 100644
index 00000000..628b1501
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/delegate/HttpHeaderDelegate.java
@@ -0,0 +1,202 @@
+/*
+ * 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.download.DownloadEntity;
+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>
+    implements IHttpHeaderTarget {
+  private static final String TAG = "HttpHeaderDelegate";
+  private ENTITY mEntity;
+  private TASK_ENTITY mTaskEntity;
+
+  public HttpHeaderDelegate(TASK_ENTITY mTaskEntity) {
+    this.mTaskEntity = mTaskEntity;
+    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 (TARGET) this;
+    } else if (TextUtils.isEmpty(value)) {
+      ALog.w(TAG, "设置header失败,header对应的value不能为null");
+      return (TARGET) this;
+    }
+    if (mTaskEntity.headers.get(key) == null) {
+      mTaskEntity.headers.put(key, value);
+      mTaskEntity.update();
+    } else if (!mTaskEntity.headers.get(key).equals(value)) {
+      mTaskEntity.headers.put(key, value);
+      mTaskEntity.update();
+    }
+    return (TARGET) this;
+  }
+
+  /**
+   * 给url请求添加一组header数据
+   * 如果新的header数据和数据保存的不一致,则更新数据库中对应的header数据
+   *
+   * @param headers 一组http header数据
+   */
+  @Override
+  public TARGET addHeaders(@NonNull Map headers) {
+    if (headers.size() == 0) {
+      ALog.w(TAG, "设置header失败,map没有header数据");
+      return (TARGET) this;
+    }
+    /*
+      两个map比较逻辑
+      1、比对key是否相同
+      2、如果key相同,比对value是否相同
+      3、只有当上面两个步骤中key 和 value都相同时才能任务两个map数据一致
+     */
+    boolean mapEquals = false;
+    if (mTaskEntity.headers.size() == headers.size()) {
+      int i = 0;
+      Set keys = mTaskEntity.headers.keySet();
+      for (String key : keys) {
+        if (headers.containsKey(key)) {
+          i++;
+        } else {
+          break;
+        }
+      }
+      if (i == mTaskEntity.headers.size()) {
+        int j = 0;
+        Collection values = mTaskEntity.headers.values();
+        for (String value : values) {
+          if (headers.containsValue(value)) {
+            j++;
+          } else {
+            break;
+          }
+        }
+        if (j == mTaskEntity.headers.size()) {
+          mapEquals = true;
+        }
+      }
+    }
+
+    if (!mapEquals) {
+      mTaskEntity.headers.clear();
+      Set keys = headers.keySet();
+      for (String key : keys) {
+        mTaskEntity.headers.put(key, headers.get(key));
+      }
+      mTaskEntity.update();
+    }
+
+    return (TARGET) this;
+  }
+
+  /**
+   * 设置请求类型,POST或GET,默认为在GET
+   * 只试用于HTTP请求
+   *
+   * @param requestEnum {@link RequestEnum}
+   */
+  @Override
+  public TARGET setRequestMode(RequestEnum requestEnum) {
+    mTaskEntity.requestEnum = requestEnum;
+    return (TARGET) this;
+  }
+
+  /**
+   * 如果你的下载链接的header中含有md5码信息,那么你可以通过设置key,来获取从header获取该md5码信息。
+   * key默认值为:Content-MD5
+   * 获取md5信息:{@link DownloadEntity#getMd5Code()}
+   */
+  @Override
+  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
+   */
+  @Override
+  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()}
+   */
+  @Override
+  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.update();
+    }
+    return (TARGET) this;
+  }
+
+  /**
+   * 从文件描述信息{@link #setHeaderDispositionKey(String)}中含有文件名信息,你可以通过设置key来获取header中的文件名
+   * key默认值为:attachment;filename
+   * 获取文件名信息:{@link DownloadEntity#getServerFileName()}
+   */
+  @Override
+  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.update();
+    }
+    return (TARGET) this;
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java
new file mode 100644
index 00000000..b9e33158
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java
@@ -0,0 +1,110 @@
+/*
+ * 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.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.ALog;
+import com.arialyy.aria.util.CommonUtil;
+
+/**
+ * Created by lyy on 2017/2/28.
+ */
+abstract class AbsDownloadTarget
+    extends AbsTarget {
+
+  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();
+    }
+  }
+
+  /**
+   * 重定向后,新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();
+  }
+
+  /**
+   * 设置target类型
+   *
+   * @return {@link #HTTP}、{@link #FTP}、{@link #GROUP_HTTP}、{@link #GROUP_FTP_DIR}
+   */
+  protected abstract int getTargetType();
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java
index e6ed4274..4ace4af0 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/BaseGroupTarget.java
@@ -16,32 +16,29 @@
 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 com.arialyy.aria.core.manager.SubTaskManager;
+import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
+import com.arialyy.aria.core.queue.DownloadTaskQueue;
 import com.arialyy.aria.orm.DbEntity;
-import com.arialyy.aria.util.CommonUtil;
+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
-    extends AbsDownloadTarget {
+abstract class BaseGroupTarget
+    extends AbsDownloadTarget {
+  private static final String TAG = "BaseGroupTarget";
 
-  List mUrls = new ArrayList<>();
-  String mGroupName;
   /**
-   * 子任务文件名
+   * 组任务名
    */
-  private List mSubTaskFileName = new ArrayList<>();
+  String mGroupName;
   /**
-   * 是否已经设置了文件路径
+   * 文件夹临时路径
    */
-  private boolean isSetDirPathed = false;
+  private String mDirPathTemp;
 
   private SubTaskManager mSubTaskManager;
 
@@ -67,6 +64,21 @@ abstract class BaseGroupTarget
    *
-   * @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();
-    }
-
-    mEntity.setDirPath(groupDirPath);
-    if (!TextUtils.isEmpty(mEntity.getDirPath())) {
-      reChangeDirPath(groupDirPath);
-    } else {
-      mEntity.setSubTasks(createSubTask());
-    }
-    mEntity.update();
+  public TARGET setDirPath(String dirPath) {
+    mDirPathTemp = dirPath;
     return (TARGET) this;
   }
 
+  @Override public boolean isRunning() {
+    DownloadGroupTask task = DownloadGroupTaskQueue.getInstance().getTask(mEntity.getKey());
+    return task != null && task.isRunning();
+  }
+
   /**
    * 改变任务组文件夹路径,修改文件夹路径会将子任务所有路径更换
    *
@@ -133,81 +129,38 @@ abstract class BaseGroupTarget subTaskFileName) {
-
-    return setSubFileName(subTaskFileName);
-  }
-
-  /**
-   * 设置子任务文件名,该方法必须在{@link #setDownloadDirPath(String)}之后调用,否则不生效
+   * @return {@code true} 合法
    */
-  public TARGET setSubFileName(List subTaskFileName) {
-    if (subTaskFileName == null || subTaskFileName.isEmpty()) return (TARGET) this;
-    mSubTaskFileName.addAll(subTaskFileName);
-    if (mUrls.size() != subTaskFileName.size()) {
-      throw new IllegalArgumentException("下载链接数必须要和保存路径的数量一致");
+  boolean checkDirPath() {
+    final String dirPath = mDirPathTemp;
+    if (TextUtils.isEmpty(dirPath)) {
+      ALog.e(TAG, "文件夹路径不能为null");
+      return false;
+    } else if (!dirPath.startsWith("/")) {
+      ALog.e(TAG, "文件夹路径【" + dirPath + "】错误");
+      return false;
     }
-    if (isSetDirPathed) {
-      List entities = mEntity.getSubTask();
-      int i = 0;
-      for (DownloadEntity entity : entities) {
-        if (i < mSubTaskFileName.size()) {
-          String newName = mSubTaskFileName.get(i);
-          updateSubFileName(entity, newName);
-        }
-        i++;
-      }
+    File file = new File(dirPath);
+    if (file.isFile()) {
+      ALog.e(TAG, "路径【" + dirPath + "】是文件,请设置文件夹路径");
+      return false;
     }
-    return (TARGET) this;
-  }
 
-  /**
-   * 更新子任务文件名
-   */
-  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));
+    if (!mEntity.getDirPath().equals(dirPath)) {
+      if (!file.exists()) {
+        file.mkdirs();
       }
-      CommonUtil.renameDownloadConfig(oldFile.getName(), newName);
-      DbEntity.exeSql(
-          "UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'");
-      entity.setDownloadPath(newPath);
-      entity.setFileName(newName);
-      entity.update();
+      mEntity.setDirPath(dirPath);
+      reChangeDirPath(dirPath);
+      mEntity.update();
     }
-  }
 
-  /**
-   * 创建子任务
-   */
-  private List createSubTask() {
-    List 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;
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java
new file mode 100644
index 00000000..b488685e
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java
@@ -0,0 +1,200 @@
+/*
+ * 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
+    extends AbsDownloadTarget {
+
+  private static final String TAG = "BaseNormalTarget";
+  /**
+   * 资源地址
+   */
+  protected String url;
+
+  /**
+   * 通过实体初始化target
+   */
+  void initTarget(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;
+  }
+
+  /**
+   * 通过地址初始化target
+   */
+  void initTarget(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;
+  }
+
+  /**
+   * 将任务设置为最高优先级任务,最高优先级任务有以下特点:
+   * 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() {
+    return getTargetType() < GROUP_HTTP && checkUrl() && checkFilePath();
+  }
+
+  /**
+   * 检查并设置普通任务的文件保存路径
+   *
+   * @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();
+      }
+    }
+    //设置文件保存路径,如果新文件路径和就文件路径不同,则修改路径
+    if (!filePath.equals(mEntity.getDownloadPath())) {
+      if (!mTaskEntity.refreshInfo && DbEntity.checkDataExist(DownloadEntity.class,
+          "downloadPath=?", filePath)) {
+        ALog.e(TAG, "保存路径【" + filePath + "】已经被其它任务占用,请设置其它保存路径");
+        return false;
+      }
+      File oldFile = new File(mEntity.getDownloadPath());
+      File newFile = new File(filePath);
+      if (TextUtils.isEmpty(mEntity.getDownloadPath()) || oldFile.renameTo(newFile)) {
+        mEntity.setDownloadPath(filePath);
+        mEntity.setFileName(newFile.getName());
+        mTaskEntity.key = filePath;
+        mTaskEntity.update();
+        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;
+    }
+    String temp = url.substring(index + 3, url.length());
+    if (temp.contains("//")) {
+      temp = url.substring(0, index + 3) + temp.replaceAll("//", "/");
+      ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp);
+      mEntity.setUrl(temp);
+      mEntity.update();
+    }
+    return true;
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java
index cb714c38..c6697a5e 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java
@@ -34,7 +34,7 @@ public class DownloadGroupEntity extends AbsGroupEntity {
   /**
    * 任务组下载文件的文件夹地址
    *
-   * @see DownloadGroupTarget#setDownloadDirPath(String)
+   * @see DownloadGroupTarget#setDirPath(String)
    */
   private String dirPath = "";
 
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
index 9bd63dd7..903f8b7e 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
@@ -15,21 +15,34 @@
  */
 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.orm.DbEntity;
 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.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
 
 /**
  * Created by AriaL on 2017/6/29.
  * 下载任务组
  */
-public class DownloadGroupTarget
-    extends BaseGroupTarget {
+public class DownloadGroupTarget extends BaseGroupTarget {
   private final String TAG = "DownloadGroupTarget";
+  /**
+   * 子任务下载地址,
+   */
+  private List mUrls = new ArrayList<>();
+
+  /**
+   * 子任务文件名
+   */
+  private List mSubNameTemp = new ArrayList<>();
 
   DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) {
     this.mTargetName = targetName;
@@ -80,16 +93,190 @@ public class DownloadGroupTarget
    * 如果你是使用{@link DownloadReceiver#load(DownloadGroupEntity)}进行下载操作,那么你需要设置任务组的下载地址
    */
   public DownloadGroupTarget setGroupUrl(List 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 subTaskFileName) {
+    return setSubFileName(subTaskFileName);
+  }
+
+  /**
+   * 设置子任务文件名,该方法必须在{@link #setDirPath(String)}之后调用,否则不生效
+   */
+  public DownloadGroupTarget setSubFileName(List subTaskFileName) {
+    if (subTaskFileName == null || subTaskFileName.isEmpty()) {
+      return this;
+    }
+    mSubNameTemp.clear();
+    mSubNameTemp.addAll(subTaskFileName);
+    return this;
+  }
+
+  /**
+   * 创建子任务
+   */
+  private List createSubTask() {
+    List list = new ArrayList<>();
+    for (int i = 0, len = mUrls.size(); i < len; i++) {
+      DownloadEntity entity = new DownloadEntity();
+      entity.setUrl(mUrls.get(i));
+      String fileName =
+          mSubNameTemp.isEmpty() ? CommonUtil.createFileName(entity.getUrl()) : mSubNameTemp.get(i);
+      entity.setDownloadPath(mEntity.getDirPath() + "/" + fileName);
+      entity.setGroupName(mGroupName);
+      entity.setGroupChild(true);
+      entity.setFileName(fileName);
+      entity.insert();
+      list.add(entity);
+    }
+    return list;
+  }
+
+  @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;
+      }
+
+      //文件夹路径通过后,并且该实体没有子任务,则创建子任务
+      if (mEntity.getSubTask() == null || mEntity.getSubTask().isEmpty()) {
+        mEntity.setSubTasks(createSubTask());
+        mTaskEntity.update();
+      } else {
+        updateSingleSubFileName();
+      }
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * 更新所有改动的子任务文件名
+   */
+  private void updateSingleSubFileName() {
+    List entities = mEntity.getSubTask();
+    int i = 0;
+    for (DownloadEntity 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 delItem = new HashSet<>();
+
+    Map reSetUrl = new WeakHashMap<>();
+    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;
+      }
+
+      String temp = url.substring(index + 3, url.length());
+      if (temp.contains("//")) {
+        temp = url.substring(0, index + 3) + temp.replaceAll("//", "/");
+        ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp);
+        reSetUrl.put(i, temp);
+      }
+      i++;
+    }
+
+    Set keys = reSetUrl.keySet();
+    for (Integer index : keys) {
+      mUrls.set(index, reSetUrl.get(index));
+    }
+
+    for (int index : delItem) {
+      mUrls.remove(index);
+      if (mSubNameTemp != null && !mSubNameTemp.isEmpty()) {
+        mSubNameTemp.remove(index);
+      }
+    }
+
+    mEntity.setGroupName(CommonUtil.getMd5Code(mUrls));
+    mEntity.update();
+
+    return true;
+  }
+
+  /**
+   * 更新单个子任务文件名
+   */
+  private void updateSingleSubFileName(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();
+    }
+  }
+
+  /**
+   * 如果用户设置了子任务文件名,检查子任务文件名
+   *
+   * @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;
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
index 21ca515b..e4efccb6 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
@@ -27,7 +27,6 @@ import com.arialyy.aria.core.inf.AbsReceiver;
 import com.arialyy.aria.core.inf.AbsTarget;
 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.CheckUtil;
 import com.arialyy.aria.util.CommonUtil;
@@ -41,7 +40,6 @@ import java.util.Set;
  */
 public class DownloadReceiver extends AbsReceiver {
   private final String TAG = "DownloadReceiver";
-  public ISchedulerListener listener;
 
   /**
    * 设置最大下载速度,单位:kb
@@ -114,8 +112,18 @@ public class DownloadReceiver extends AbsReceiver {
 
   /**
    * 加载下载地址,如果任务组的中的下载地址改变了,则任务从新的一个任务组
+   *
+   * @param urls 人刷谁
    */
+  @Deprecated
   public DownloadGroupTarget load(List urls) {
+    return loadGroup(urls);
+  }
+
+  /**
+   * 加载下载地址,如果任务组的中的下载地址改变了,则任务从新的一个任务组
+   */
+  public DownloadGroupTarget loadGroup(List urls) {
     CheckUtil.checkDownloadUrls(urls);
     return new DownloadGroupTarget(urls, targetName);
   }
@@ -170,12 +178,24 @@ public class DownloadReceiver extends AbsReceiver {
   }
 
   /**
-   * 使用任务组实体执行任务组的实体执行任务组的下载操作
+   * 使用任务组实体执行任务组的实体执行任务组的下载操作,后续版本会删除该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);
   }
 
@@ -232,7 +252,6 @@ public class DownloadReceiver extends AbsReceiver {
 
   @Override public void destroy() {
     targetName = null;
-    listener = null;
   }
 
   /**
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java
index 5a8b20ed..d29b6d79 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java
@@ -16,35 +16,27 @@
 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 {
-  protected String url;
+public class DownloadTarget extends BaseNormalTarget
+    implements IHttpHeaderTarget {
+  private static final String TAG = "DownloadTarget";
+  private HttpHeaderDelegate 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;
+    initTarget(entity, targetName, refreshInfo);
+    initTHis();
   }
 
   DownloadTarget(String url, String targetName) {
@@ -52,14 +44,12 @@ 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);
+    initTHis();
+  }
+
+  private void initTHis() {
+    mDelegate = new HttpHeaderDelegate<>(mTaskEntity);
   }
 
   /**
@@ -75,25 +65,15 @@ public class DownloadTarget
   }
 
   /**
-   * 将任务设置为最高优先级任务,最高优先级任务有以下特点:
-   * 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 +81,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 +95,35 @@ 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 headers) {
+    return mDelegate.addHeaders(headers);
+  }
+
+  @Override public DownloadTarget setRequestMode(RequestEnum requestEnum) {
+    return mDelegate.setRequestMode(requestEnum);
+  }
+
+  @Override public DownloadTarget setHeaderMd5Key(String md5Key) {
+    return mDelegate.setHeaderMd5Key(md5Key);
+  }
+
+  @Override public DownloadTarget setHeaderContentLengthKey(String contentLength) {
+    return mDelegate.setHeaderContentLengthKey(contentLength);
+  }
+
+  @Override public DownloadTarget setHeaderDispositionKey(String dispositionKey) {
+    return mDelegate.setHeaderDispositionKey(dispositionKey);
   }
 
-  @Override public boolean isRunning() {
-    DownloadTask task = DownloadTaskQueue.getInstance().getTask(mEntity.getKey());
-    return task != null && task.isRunning();
+  @Override public DownloadTarget setHeaderDispositionFileKey(String dispositionFileKey) {
+    return mDelegate.setHeaderDispositionFileKey(dispositionFileKey);
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
index f7c51df7..ffeacb14 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
@@ -16,18 +16,20 @@
 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 {
+public class FtpDirDownloadTarget extends BaseGroupTarget implements
+    IFtpTarget {
   private final String TAG = "FtpDirDownloadTarget";
+  private FtpDelegate mDelegate;
 
   FtpDirDownloadTarget(String url, String targetName) {
     mTargetName = targetName;
@@ -42,51 +44,57 @@ public class FtpDirDownloadTarget
     }
     mTaskEntity.requestType = AbsTaskEntity.D_FTP_DIR;
     mEntity = mTaskEntity.entity;
+
+    mDelegate = new FtpDelegate<>(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() {
+    return getTargetType() == GROUP_FTP_DIR && checkDirPath() && checkUrl();
   }
 
   /**
-   * 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;
     }
-    mTaskEntity.urlEntity.needLogin = true;
-    mTaskEntity.urlEntity.user = userName;
-    mTaskEntity.urlEntity.password = password;
-    mTaskEntity.urlEntity.account = account;
-    return this;
+    int index = url.indexOf("://");
+    if (index == -1) {
+      ALog.e(TAG, "下载失败,url【" + url + "】不合法");
+      return false;
+    }
+    String temp = url.substring(index + 3, url.length());
+    if (temp.contains("//")) {
+      temp = url.substring(0, index + 3) + temp.replaceAll("//", "/");
+      ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp);
+      mGroupName = temp;
+      mEntity.setGroupName(temp);
+      mEntity.update();
+    }
+    return true;
+  }
+
+  @Override public FtpDirDownloadTarget charSet(String charSet) {
+    return mDelegate.charSet(charSet);
+  }
+
+  @Override public FtpDirDownloadTarget login(String userName, String password) {
+    return mDelegate.login(userName, password);
   }
 
-  @Override public boolean isRunning() {
-    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);
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
index ccc18455..d9b7b54b 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
@@ -16,21 +16,22 @@
 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 {
+public class FtpDownloadTarget extends BaseNormalTarget
+    implements IFtpTarget {
   private final String TAG = "FtpDownloadTarget";
+  private FtpDelegate mDelegate;
 
   FtpDownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) {
-    super(entity, targetName, refreshInfo);
+    initTarget(entity, targetName, refreshInfo);
     init(refreshInfo);
   }
 
@@ -39,7 +40,7 @@ public class FtpDownloadTarget extends DownloadTarget {
   }
 
   FtpDownloadTarget(String url, String targetName, boolean refreshInfo) {
-    super(url, targetName);
+    initTarget(url, targetName, refreshInfo);
     init(refreshInfo);
   }
 
@@ -49,6 +50,19 @@ public class FtpDownloadTarget extends DownloadTarget {
     mTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(url);
     mTaskEntity.refreshInfo = refreshInfo;
     mTaskEntity.requestType = AbsTaskEntity.D_FTP;
+
+    mDelegate = new FtpDelegate<>(mTaskEntity);
+  }
+
+  /**
+   * 设置文件保存文件夹路径
+   *
+   * @param filePath 文件保存路径
+   * @deprecated {@link #setFilePath(String)} 请使用这个api
+   */
+  @Deprecated
+  public FtpDownloadTarget setDownloadPath(@NonNull String filePath) {
+    return setFilePath(filePath);
   }
 
   /**
@@ -57,69 +71,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;
-    }
-    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) {
+    return mDelegate.login(userName, password);
+  }
+
+  @Override public FtpDownloadTarget login(String userName, String password, String account) {
+    return mDelegate.login(userName, password, account);
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsDownloadTarget.java
deleted file mode 100644
index f5909a1f..00000000
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsDownloadTarget.java
+++ /dev/null
@@ -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
-    extends AbsTarget {
-
-  /**
-   * 如果你的下载链接的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();
-  }
-}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
index 6e2d69c4..742f4af6 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
@@ -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,8 +28,6 @@ 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.
@@ -65,27 +61,12 @@ public abstract class AbsTarget headers) {
-    return addHeaders(headers, false);
-  }
-
-  /**
-   * 给url请求添加头部
-   *
-   * @param refreshHeader 更新数据库中保存的头部信息
-   */
-  public TARGET addHeaders(Map headers, boolean refreshHeader) {
-    if (headers != null && headers.size() > 0) {
-      Set keys = headers.keySet();
-      for (String key : keys) {
-        mTaskEntity.headers.put(key, headers.get(key));
-      }
-    }
-    if (refreshHeader) {
-      mTaskEntity.update();
-    }
-    return (TARGET) this;
-  }
-
-  /**
-   * 设置请求类型,POST或GET,默认为在GET
-   * 只试用于HTTP请求
+   * 检查实体是否合法
    *
-   * @param requestEnum {@link RequestEnum}
+   * @return {@code true} 合法
    */
-  public TARGET setRequestMode(RequestEnum requestEnum) {
-    mTaskEntity.requestEnum = requestEnum;
-    return (TARGET) this;
-  }
-
-  /**
-   * 开始任务
-   */
-  @Override public void start() {
-    AriaManager.getInstance(AriaManager.APP)
-        .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START,
-            checkTaskType()))
-        .exe();
-  }
+  protected abstract boolean checkEntity();
 
   protected int checkTaskType() {
     int taskType = 0;
@@ -238,53 +156,76 @@ public abstract class AbsTarget cmds = new ArrayList<>();
-    int taskType = checkTaskType();
-    cmds.add(
-        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();
+    if (checkEntity()) {
+      List cmds = new ArrayList<>();
+      int taskType = checkTaskType();
+      cmds.add(
+          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 +235,23 @@ public abstract class AbsTarget 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;
   }
+
+
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java
deleted file mode 100644
index be6541f1..00000000
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java
+++ /dev/null
@@ -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
-    extends AbsTarget {
-
-  /**
-   * 设置上传路径
-   *
-   * @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();
-  }
-}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java
new file mode 100644
index 00000000..5f5a68fd
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.arialyy.aria.core.inf;
+
+/**
+ * Created by laoyuyu on 2018/3/9.
+ */
+public interface IFtpTarget {
+  /**
+   * 设置字符编码
+   */
+  TARGET charSet(String charSet);
+
+  /**
+   * ftp 用户登录信。
+   * 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)}
+   *
+   * @param userName ftp用户名
+   * @param password ftp用户密码
+   */
+  TARGET login(String userName, String password);
+
+  /**
+   * ftp 用户登录信息
+   * 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)}
+   *
+   * @param userName ftp用户名
+   * @param password ftp用户密码
+   * @param account ftp账号
+   */
+  TARGET login(String userName, String password, String account);
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java
new file mode 100644
index 00000000..8cd41def
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java
@@ -0,0 +1,79 @@
+/*
+ * 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 {
+
+  /**
+   * 给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 headers);
+
+  /**
+   * 设置HTTP请求类型
+   *
+   * @param requestEnum {@link RequestEnum}
+   */
+  TARGET setRequestMode(RequestEnum requestEnum);
+
+  /**
+   * 如果你的下载链接的header中含有md5码信息,那么你可以通过设置key,来获取从header获取该md5码信息。
+   * key默认值为:Content-MD5
+   * 获取md5信息:{@link DownloadEntity#getMd5Code()}
+   */
+  TARGET setHeaderMd5Key(String md5Key);
+
+  /**
+   * 如果你的文件长度是放在header中,那么你需要配置key来让Aria知道正确的文件长度
+   * key默认值为:Content-Length
+   */
+  TARGET setHeaderContentLengthKey(String contentLength);
+
+  /**
+   * 如果你的下载链接的header中含有文件描述信息,那么你可以通过设置key,来获取从header获取该文件描述信息。
+   * key默认值为:Content-Disposition
+   * 获取文件描述信息:{@link DownloadEntity#getDisposition()}
+   */
+  TARGET setHeaderDispositionKey(String dispositionKey);
+
+  /**
+   * 从文件描述信息{@link #setHeaderDispositionKey(String)}中含有文件名信息,你可以通过设置key来获取header中的文件名
+   * key默认值为:attachment;filename
+   * 获取文件名信息:{@link DownloadEntity#getServerFileName()}
+   */
+  TARGET setHeaderDispositionFileKey(String dispositionFileKey);
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java
index 527e8078..21149e0f 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java
@@ -15,53 +15,51 @@
  */
 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 {
+
   /**
-   * 任务文件大小
+   * 获取任务状态
+   *
+   * @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 headers);
+  int getPercent();
 
   /**
-   * 设置请求类型
-   *
-   * @param requestEnum {@link RequestEnum}
+   * 获取任务进度,如果任务存在,则返回当前进度
    */
-  TARGET setRequestMode(RequestEnum requestEnum);
+  long getCurrentProgress();
 
   /**
    * 开始下载
@@ -82,5 +80,4 @@ public interface ITarget {
    * 取消下载
    */
   void cancel();
-
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java
index b8c02a25..2c90fc26 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java
@@ -150,10 +150,10 @@ abstract class AbsTaskQueue
+    extends AbsTarget {
+
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java
new file mode 100644
index 00000000..9a2a31b4
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java
@@ -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.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
+    extends AbsUploadTarget {
+  private static final String TAG = "BaseNormalTarget";
+
+  protected void initTarget(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());
+  }
+
+  /**
+   * 设置上传路径
+   *
+   * @param uploadUrl 上传路径
+   */
+  public abstract TARGET setUploadUrl(@NonNull String uploadUrl);
+
+  /**
+   * 上传任务是否存在
+   *
+   * @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() {
+    return checkUrl() && checkFilePath();
+  }
+
+  /**
+   * 检查上传文件路径是否合法
+   *
+   * @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;
+    }
+
+    if (filePath.contains("//")) {
+      filePath = filePath.replaceAll("//", "/");
+      ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + filePath);
+      mEntity.setFilePath(filePath);
+      mEntity.update();
+    }
+    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;
+    }
+    String temp = url.substring(index + 3, url.length());
+    if (temp.contains("//")) {
+      temp = url.substring(0, index + 3) + temp.replaceAll("//", "/");
+      ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp);
+      mEntity.setUrl(temp);
+      mEntity.update();
+    }
+    return true;
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java
index 7bcccac5..8892c8b8 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java
@@ -16,13 +16,12 @@
 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.inf.IFtpTarget;
 import com.arialyy.aria.core.manager.TEManager;
-import com.arialyy.aria.util.ALog;
 import com.arialyy.aria.util.CheckUtil;
 import com.arialyy.aria.util.CommonUtil;
 import java.io.File;
@@ -31,9 +30,10 @@ import java.io.File;
  * Created by Aria.Lao on 2017/7/27.
  * ftp单任务上传
  */
-public class FtpUploadTarget
-    extends AbsUploadTarget {
+public class FtpUploadTarget extends BaseNormalTarget
+    implements IFtpTarget {
   private final String TAG = "FtpUploadTarget";
+  private FtpDelegate mDelegate;
 
   FtpUploadTarget(String filePath, String targetName) {
     this.mTargetName = targetName;
@@ -41,15 +41,9 @@ 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());
+    initTarget(filePath);
     mTaskEntity.requestType = AbsTaskEntity.U_FTP;
+    mDelegate = new FtpDelegate<>(mTaskEntity);
   }
 
   /**
@@ -57,6 +51,7 @@ public class FtpUploadTarget
    *
    * @param uploadUrl 上传路径
    */
+  @Override
   public FtpUploadTarget setUploadUrl(@NonNull String uploadUrl) {
     uploadUrl = CheckUtil.checkUrl(uploadUrl);
     if (!uploadUrl.endsWith("/")) {
@@ -70,55 +65,26 @@ public class FtpUploadTarget
   }
 
   /**
-   * 设置字符编码
+   * 添加任务
    */
-  public FtpUploadTarget charSet(String charSet) {
-    if (TextUtils.isEmpty(charSet)) return this;
-    mTaskEntity.charSet = charSet;
-    return this;
+  public void add() {
+    if (checkEntity()) {
+      AriaManager.getInstance(AriaManager.APP)
+          .setCmd(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE,
+              checkTaskType()))
+          .exe();
+    }
   }
 
-  /**
-   * ftp 用户登录信。
-   * 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)}
-   *
-   * @param userName ftp用户名
-   * @param password ftp用户密码
-   */
-  public FtpUploadTarget login(String userName, String password) {
-    return login(userName, password, null);
+  @Override public FtpUploadTarget charSet(String charSet) {
+    return mDelegate.charSet(charSet);
   }
 
-  /**
-   * 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;
-    }
-    mTaskEntity.urlEntity.needLogin = true;
-    mTaskEntity.urlEntity.user = userName;
-    mTaskEntity.urlEntity.password = password;
-    mTaskEntity.urlEntity.account = account;
-    return this;
+  @Override public FtpUploadTarget login(String userName, String password) {
+    return mDelegate.login(userName, password);
   }
 
-  /**
-   * 添加任务
-   */
-  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) {
+    return mDelegate.login(userName, password, account);
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java
index a86c2219..3d9b6040 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java
@@ -36,7 +36,6 @@ import java.util.Set;
  */
 public class UploadReceiver extends AbsReceiver {
   private static final String TAG = "UploadReceiver";
-  public ISchedulerListener listener;
 
   /**
    * 加载HTTP单文件上传任务
@@ -104,7 +103,6 @@ public class UploadReceiver extends AbsReceiver {
 
   @Override public void destroy() {
     targetName = null;
-    listener = null;
   }
 
   /**
diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java
index b3b49956..eeacbfd9 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java
@@ -16,16 +16,21 @@
 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 com.arialyy.aria.util.CheckUtil;
+import java.util.Map;
 
 /**
  * Created by lyy on 2017/2/28.
- * http 当文件上传
+ * http 单文件上传
  */
-public class UploadTarget extends AbsUploadTarget {
+public class UploadTarget extends BaseNormalTarget
+    implements IHttpHeaderTarget {
+  private static final String TAG = "UploadTarget";
+  private HttpHeaderDelegate mDelegate;
 
   UploadTarget(String filePath, String targetName) {
     this.mTargetName = targetName;
@@ -33,17 +38,22 @@ public class UploadTarget extends AbsUploadTarget(mTaskEntity);
+  }
+
+  @Override public UploadTarget setUploadUrl(@NonNull String uploadUrl) {
+    uploadUrl = CheckUtil.checkUrl(uploadUrl);
+    if (mEntity.getUrl().equals(uploadUrl)) {
+      return this;
+    }
+    mEntity.setUrl(uploadUrl);
+    mEntity.update();
+    return this;
   }
 
   /**
@@ -73,4 +83,32 @@ public class UploadTarget extends AbsUploadTarget headers) {
+    return mDelegate.addHeaders(headers);
+  }
+
+  @Override public UploadTarget setRequestMode(RequestEnum requestEnum) {
+    return mDelegate.setRequestMode(requestEnum);
+  }
+
+  @Override public UploadTarget setHeaderMd5Key(String md5Key) {
+    return mDelegate.setHeaderMd5Key(md5Key);
+  }
+
+  @Override public UploadTarget setHeaderContentLengthKey(String contentLength) {
+    return mDelegate.setHeaderContentLengthKey(contentLength);
+  }
+
+  @Override public UploadTarget setHeaderDispositionKey(String dispositionKey) {
+    return mDelegate.setHeaderDispositionKey(dispositionKey);
+  }
+
+  @Override public UploadTarget setHeaderDispositionFileKey(String dispositionFileKey) {
+    return mDelegate.setHeaderDispositionFileKey(dispositionFileKey);
+  }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java b/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java
index 103a5153..1f67935c 100644
--- a/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java
@@ -109,6 +109,34 @@ public class CheckUtil {
     return url;
   }
 
+  ///**
+  // * 检查普通任务的下载地址
+  // *
+  // * @return {@code true}地址合法
+  // */
+  //public static boolean checkUrl(DownloadEntity entity, String url) {
+  //  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;
+  //  }
+  //  String temp = url.substring(index + 3, url.length());
+  //  if (temp.contains("//")) {
+  //    temp = url.substring(0, index + 3) + temp.replaceAll("//", "/");
+  //    ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp);
+  //    entity.setUrl(temp);
+  //    entity.update();
+  //  }
+  //  return true;
+  //}
+
   /**
    * 检测下载链接组是否为null
    */
diff --git a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
index ee215f6f..f52ef139 100644
--- a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
@@ -73,6 +73,32 @@ import java.util.regex.Pattern;
 public class CommonUtil {
   private static final String TAG = "CommonUtil";
 
+  /**
+   * 创建文件名,如果url链接有后缀名,则使用url中的后缀名
+   *
+   * @return url 的 hashKey
+   */
+  public static 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);
+    }
+    return fileName;
+  }
+
   /**
    * 分割获取url,协议,ip/域名,端口,内容
    *
diff --git a/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java b/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java
index 75397bd1..4762fe1f 100644
--- a/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java
+++ b/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java
@@ -80,7 +80,7 @@ public class DownloadGroupActivity extends BaseActivity
Date: Mon, 12 Mar 2018 21:51:30 +0800
Subject: [PATCH 05/22] chunked

---
 .../arialyy/aria/core/common/AbsFileer.java   |  6 ++-
 .../aria/core/common/CompleteInfo.java        | 31 +++++++++++
 .../aria/core/common/OnFileInfoCallback.java  | 19 ++++++-
 .../core/download/DownloadTaskEntity.java     |  6 +++
 .../download/downloader/ConnectionHelp.java   |  1 +
 .../downloader/DownloadGroupUtil.java         |  3 +-
 .../downloader/FtpDirDownloadUtil.java        |  5 +-
 .../download/downloader/FtpDirInfoThread.java |  3 +-
 .../downloader/FtpFileInfoThread.java         |  3 +-
 .../downloader/HttpFileInfoThread.java        | 35 +++++++++++--
 .../download/downloader/HttpThreadTask.java   | 51 ++++++++++++++-----
 .../downloader/SimpleDownloadUtil.java        |  5 +-
 .../upload/uploader/FtpFileInfoThread.java    |  3 +-
 .../upload/uploader/SimpleUploadUtil.java     |  5 +-
 .../java/com/arialyy/aria/orm/DBConfig.java   |  2 +-
 DEV_LOG.md                                    |  2 +
 .../simple/download/SingleTaskActivity.java   | 15 +++---
 build.gradle                                  |  2 +-
 18 files changed, 156 insertions(+), 41 deletions(-)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/common/CompleteInfo.java

diff --git a/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java b/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
index c7fb1145..bf30ff74 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
@@ -129,7 +129,11 @@ public abstract class AbsFileer {
    */
   public String groupName = "";
 
+  /**
+   * 是否是chunk模式
+   */
+  public boolean isChunked = false;
+
   /**
    * 该任务是否属于任务组
    */
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
index a4a2dfd4..6135ec6f 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
@@ -86,6 +86,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, ")
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
index 937f535f..7699077d 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
@@ -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;
@@ -99,7 +100,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) {
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java
index cba16bd5..719785c2 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java
@@ -15,6 +15,7 @@
  */
 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;
@@ -41,8 +42,8 @@ public class FtpDirDownloadUtil extends AbsGroupUtil {
       startDownload();
     } else {
       new FtpDirInfoThread(mGTEntity, new OnFileInfoCallback() {
-        @Override public void onComplete(String url, int code) {
-          if (code >= 200 && code < 300) {
+        @Override public void onComplete(String url, CompleteInfo info) {
+          if (info.code >= 200 && info.code < 300) {
             for (DownloadEntity entity : mGTEntity.entity.getSubTask()) {
               mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
             }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java
index caec83c6..8b4bf128 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java
@@ -17,6 +17,7 @@ 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;
@@ -48,7 +49,7 @@ class FtpDirInfoThread extends AbsFtpInfoThread> headers = conn.getHeaderFields();
+    Map> headers = conn.getHeaderFields();
+    boolean isChunked = false;
+    //https://my.oschina.net/ososchina/blog/666761
+    if (conn.getHeaderField("Transfer-Encoding").equals("chunked")) {
+      isChunked = true;
+      StringBuffer sb = new StringBuffer();
+      byte[] buffer = new byte[1024];
+      InputStream is = conn.getInputStream();
+      int l = 0;
+      //while (true){
+      //  is.read()
+      //}
+    }
     if (!TextUtils.isEmpty(disposition)) {
       mEntity.setDisposition(CommonUtil.encryptBASE64(disposition));
       if (disposition.contains(mTaskEntity.dispositionFileKey)) {
@@ -95,12 +114,16 @@ class HttpFileInfoThread implements Runnable {
 
     mTaskEntity.code = code;
     if (code == HttpURLConnection.HTTP_PARTIAL) {
-      if (!checkLen(len)) return;
+      if (!checkLen(len) && !isChunked) {
+        return;
+      }
       mEntity.setFileSize(len);
       mTaskEntity.isSupportBP = true;
       isComplete = true;
     } else if (code == HttpURLConnection.HTTP_OK) {
-      if (!checkLen(len)) return;
+      if (!checkLen(len) && !isChunked) {
+        return;
+      }
       mEntity.setFileSize(len);
       mTaskEntity.isSupportBP = false;
       isComplete = true;
@@ -117,10 +140,12 @@ class HttpFileInfoThread implements Runnable {
       failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:" + code, true);
     }
     if (isComplete) {
+      mTaskEntity.isChunked = isChunked;
+      mTaskEntity.update();
       if (onFileInfoListener != null) {
-        onFileInfoListener.onComplete(mEntity.getUrl(), code);
+        CompleteInfo info = new CompleteInfo(code);
+        onFileInfoListener.onComplete(mEntity.getUrl(), info);
       }
-      mTaskEntity.update();
     }
   }
 
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
index 8b6f09c5..eadf2132 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
@@ -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,25 +73,21 @@ final class HttpThreadTask extends AbsThreadTask 0) {
-          Thread.sleep(mSleepTime);
-        }
-        file.write(buffer, 0, len);
-        progress(len);
+
+      if (mTaskEntity.isChunked) {
+        readChunk(is, file);
+      } else {
+        readNormal(is, file);
       }
-      if (STATE.isCancel || STATE.isStop){
+
+      if (STATE.isCancel || STATE.isStop) {
         return;
       }
       //支持断点的处理
@@ -105,7 +103,7 @@ final class HttpThreadTask extends AbsThreadTask 0) {
+        Thread.sleep(mSleepTime);
+      }
+      file.write(buffer, 0, len);
+      progress(len);
+    }
+  }
+
   @Override protected String getTaskType() {
     return "HTTP_DOWNLOAD";
   }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java
index ee99b3a5..3d2dc31b 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java
@@ -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;
@@ -106,7 +107,7 @@ public class SimpleDownloadUtil implements IUtil, Runnable {
     switch (mTaskEntity.requestType) {
       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();
           }
 
diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpFileInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpFileInfoThread.java
index 987330d2..f31ae371 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpFileInfoThread.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpFileInfoThread.java
@@ -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;
@@ -82,6 +83,6 @@ class FtpFileInfoThread extends AbsFtpInfoThread
 
   @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));
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/SimpleUploadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/SimpleUploadUtil.java
index 94c9d486..423237a5 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/SimpleUploadUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/SimpleUploadUtil.java
@@ -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;
@@ -51,8 +52,8 @@ public class SimpleUploadUtil implements IUtil, Runnable {
     switch (mTaskEntity.requestType) {
       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();
diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java b/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java
index 5196af1b..877223ea 100644
--- a/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java
+++ b/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java
@@ -34,7 +34,7 @@ import java.util.Map;
 class DBConfig {
   static Map mapping = new HashMap<>();
   static String DB_NAME;
-  static int VERSION = 23;
+  static int VERSION = 24;
 
   static {
     if (TextUtils.isEmpty(DB_NAME)) {
diff --git a/DEV_LOG.md b/DEV_LOG.md
index 8caf37f3..b032d00e 100644
--- a/DEV_LOG.md
+++ b/DEV_LOG.md
@@ -1,4 +1,6 @@
 ## 开发日志
+  + v_3.3.16
+    - 修复一个activity启动多次,无法进行回掉的bug https://github.com/AriaLyy/Aria/issues/200
   + v_3.3.14
     - 修复ftp上传和下载的兼容性问题
     - 如果url中的path有"//"将替换为"/"
diff --git a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
index 58a781ce..96fc98ac 100644
--- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
+++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
@@ -47,7 +47,7 @@ public class SingleTaskActivity extends BaseActivity {
   private static final String DOWNLOAD_URL =
       //"http://kotlinlang.org/docs/kotlin-docs.pdf";
       //"https://atom-installer.github.com/v1.13.0/AtomSetup.exe?s=1484074138&ext=.exe";
-      "http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk";
+      //"http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk";
       //"http://sitcac.daxincf.cn/wp-content/uploads/swift_vido/01/element.mp4_1";
       //"http://120.25.196.56:8000/filereq?id=15692406294&ipncid=105635&client=android&filename=20170819185541.avi";
       //"http://down2.xiaoshuofuwuqi.com/d/file/filetxt/20170608/14/%BA%DA%CE%D7%CA%A6%E1%C8%C6%F0.txt";
@@ -61,6 +61,8 @@ public class SingleTaskActivity extends BaseActivity {
       //"http://qudao.5535.cn/one/game.html?game=531&cpsuser=xiaoeryu2";
       //"https://bogoe-res.mytbz.com/tbzengsong/If You're Happy.mp3";
       //"http://ozr0ucjs5.bkt.clouddn.com/51_box-104_20180131202610.apk";
+      "http://kf.lyfz.net/api/v1/we_chat/Business/getMaterial?company_id=51454009d703c86c91353f61011ecf2f&appid=wx88c6052d06eaaf7d&media_id=qpkQb72KqNkZhBNIUw7asF0LuJouXCTBd3A-rS2bYl7H4kvTZstEXD3F-pDVeqA-&type=3";
+      //"https://www.baidu.com/link?url=_LFCuTPtnzFxVJByJ504QymRywIA1Z_T5xUxe9ZLuxcGM0C_RcdpWyB1eGjbJC-e5wv5wAKM4WmLMAS5KeF6EZJHB8Va3YqZUiaErqK_pxm&wd=&eqid=e8583fe70002d126000000065a99f864";
   @Bind(R.id.start) Button mStart;
   @Bind(R.id.stop) Button mStop;
   @Bind(R.id.cancel) Button mCancel;
@@ -222,15 +224,12 @@ public class SingleTaskActivity extends BaseActivity {
   private void startD() {
     //Aria.get(this).setLogLevel(ALog.LOG_CLOSE);
     //Aria.download(this).load("aaaa.apk");
-    Map map = new HashMap<>();
-    map.put("User-Agent",
-        "Mozilla/5.0 (Linux; Android 4.4.4; Nexus 5 Build/KTU84P; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 Mobile MQQBrowser/6.2 TBS/043722 Safari/537.36");
-    map.put("Cookie",
-        "BAIDUID=DFC7EF42C60AD1ACF0BA94389AA67F13:FG=1; H_WISE_SIDS=121192_104493_114745_121434_119046_100098_120212_121140_118882_118858_118850_118820_118792_121254_121534_121214_117588_117242_117431_119974_120597_121043_121422_120943_121175_121272_117552_120482_121013_119962_119145_120851_120841_120034_121325_116407_121109_120654_110085_120708; PSINO=7; BDORZ=AE84CDB3A529C0F8A2B9DCDD1D18B695");
     Aria.download(SingleTaskActivity.this)
         .load(DOWNLOAD_URL)
-        //.addHeader("groupName", "value")
-        .addHeaders(map)
+        //.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
+        .addHeader("Accept-Encoding", "gzip, deflate")
+        .addHeader("DNT", "1")
+        //.addHeader("Cookie", "BAIDUID=648E5FF020CC69E8DD6F492D1068AAA9:FG=1; BIDUPSID=648E5FF020CC69E8DD6F492D1068AAA9; PSTM=1519099573; BD_UPN=12314753; locale=zh; BDSVRTM=0")
         //.setRequestMode(RequestEnum.POST)
         .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/ggsg1.apk")
         .resetState()
diff --git a/build.gradle b/build.gradle
index c525f86b..9d7946bb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -39,7 +39,7 @@ task clean(type: Delete) {
 ext {
   userOrg = 'arialyy'
   groupId = 'com.arialyy.aria'
-  publishVersion = '3.3.15'
+  publishVersion = '3.3.16_dev'
 //  publishVersion = '1.0.3'  //FTP插件
   repoName='maven'
   desc = 'android 下载框架'

From 402086d7ddf9eec04772c39487c4369b88c97211 Mon Sep 17 00:00:00 2001
From: laoyuyu <=>
Date: Tue, 13 Mar 2018 17:26:00 +0800
Subject: [PATCH 06/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=9F=90=E4=BA=9B?=
 =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8range=20=E8=BF=94=E5=9B=9E=E4=B8=8D?=
 =?UTF-8?q?=E4=BA=86=E9=95=BF=E5=BA=A6=E7=9A=84bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Change-Id: I4a239898bdf0926c6ef2ad58e3fde51e06dd597d
---
 .../aria/core/delegate/FtpDelegate.java       | 16 ++---
 .../core/delegate/HttpHeaderDelegate.java     | 35 ++++++-----
 .../aria/core/download/DownloadTarget.java    |  2 +-
 .../core/download/FtpDirDownloadTarget.java   |  2 +-
 .../aria/core/download/FtpDownloadTarget.java |  2 +-
 .../download/downloader/ConnectionHelp.java   | 45 +++++++-------
 .../downloader/HttpFileInfoThread.java        | 34 +++++++----
 .../download/downloader/HttpThreadTask.java   | 59 +++++++++++--------
 .../com/arialyy/aria/core/inf/ITarget.java    |  1 -
 .../aria/core/upload/FtpUploadTarget.java     |  4 +-
 .../aria/core/upload/UploadTarget.java        |  2 +-
 .../ftp/parser/MacOsPeterFTPEntryParser.java  |  3 +-
 DEV_LOG.md                                    |  1 +
 app/src/main/assets/aria_config.xml           |  4 +-
 .../simple/download/SingleTaskActivity.java   |  8 ++-
 15 files changed, 126 insertions(+), 92 deletions(-)

diff --git a/Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java b/Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java
index 578c478f..c4a830b6 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/delegate/FtpDelegate.java
@@ -31,16 +31,18 @@ public class FtpDelegate headers) {
     if (headers.size() == 0) {
       ALog.w(TAG, "设置header失败,map没有header数据");
-      return (TARGET) this;
+      return mTarget;
     }
     /*
       两个map比较逻辑
@@ -123,7 +126,7 @@ public class HttpHeaderDelegate
   }
 
   private void initTHis() {
-    mDelegate = new HttpHeaderDelegate<>(mTaskEntity);
+    mDelegate = new HttpHeaderDelegate<>(this, mTaskEntity);
   }
 
   /**
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
index ffeacb14..cb7b2d01 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
@@ -45,7 +45,7 @@ public class FtpDirDownloadTarget extends BaseGroupTarget
     mTaskEntity.requestType = AbsTaskEntity.D_FTP_DIR;
     mEntity = mTaskEntity.entity;
 
-    mDelegate = new FtpDelegate<>(mTaskEntity);
+    mDelegate = new FtpDelegate<>(this, mTaskEntity);
   }
 
   @Override protected int getTargetType() {
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
index d9b7b54b..518f3142 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java
@@ -51,7 +51,7 @@ public class FtpDownloadTarget extends BaseNormalTarget
     mTaskEntity.refreshInfo = refreshInfo;
     mTaskEntity.requestType = AbsTaskEntity.D_FTP;
 
-    mDelegate = new FtpDelegate<>(mTaskEntity);
+    mDelegate = new FtpDelegate<>(this, mTaskEntity);
   }
 
   /**
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
index 6135ec6f..702f253c 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
@@ -15,6 +15,7 @@
  */
 package com.arialyy.aria.core.download.downloader;
 
+import android.util.Log;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.util.SSLContextUtil;
 import java.io.IOException;
@@ -80,28 +81,28 @@ class ConnectionHelp {
       conn.setRequestProperty("User-Agent",
           "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
     }
-    if (keys == null || !keys.contains("Accept")) {
-      StringBuilder accept = new StringBuilder();
-      accept.append("image/gif, ")
-          .append("image/jpeg, ")
-          .append("image/pjpeg, ")
-          .append("image/webp, ")
-          .append("image/apng, ")
-          .append("application/xml, ")
-          .append("application/xaml+xml, ")
-          .append("application/xhtml+xml, ")
-          .append("application/x-shockwave-flash, ")
-          .append("application/x-ms-xbap, ")
-          .append("application/x-ms-application, ")
-          .append("application/msword, ")
-          .append("application/vnd.ms-excel, ")
-          .append("application/vnd.ms-xpsdocument, ")
-          .append("application/vnd.ms-powerpoint, ")
-          .append("text/plain, ")
-          .append("text/html, ")
-          .append("*/*");
-      conn.setRequestProperty("Accept", accept.toString());
-    }
+    //if (keys == null || !keys.contains("Accept")) {
+    //  StringBuilder accept = new StringBuilder();
+    //  accept.append("image/gif, ")
+    //      .append("image/jpeg, ")
+    //      .append("image/pjpeg, ")
+    //      .append("image/webp, ")
+    //      .append("image/apng, ")
+    //      .append("application/xml, ")
+    //      .append("application/xaml+xml, ")
+    //      .append("application/xhtml+xml, ")
+    //      .append("application/x-shockwave-flash, ")
+    //      .append("application/x-ms-xbap, ")
+    //      .append("application/x-ms-application, ")
+    //      .append("application/msword, ")
+    //      .append("application/vnd.ms-excel, ")
+    //      .append("application/vnd.ms-xpsdocument, ")
+    //      .append("application/vnd.ms-powerpoint, ")
+    //      .append("text/plain, ")
+    //      .append("text/html, ")
+    //      .append("*/*");
+    //  conn.setRequestProperty("Accept", accept.toString());
+    //}
     if (keys == null || !keys.contains("Accept-Encoding")) {
       conn.setRequestProperty("Accept-Encoding", "identity");
     }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
index 1a51ab7f..0bfaceb0 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
@@ -15,7 +15,9 @@
  */
 package com.arialyy.aria.core.download.downloader;
 
+import android.location.Address;
 import android.text.TextUtils;
+import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.common.CompleteInfo;
 import com.arialyy.aria.core.common.OnFileInfoCallback;
@@ -27,7 +29,9 @@ import com.arialyy.aria.util.CommonUtil;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.HttpURLConnection;
+import java.net.InetAddress;
 import java.net.URL;
+import java.net.URLConnection;
 import java.net.URLDecoder;
 import java.util.List;
 import java.util.Map;
@@ -58,10 +62,7 @@ class HttpFileInfoThread implements Runnable {
       conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
       conn.setRequestProperty("Range", "bytes=" + 0 + "-");
       conn.setConnectTimeout(mConnectTimeOut);
-      conn.setRequestMethod(mTaskEntity.requestEnum.name);
-      conn.setDoOutput(true);
-      conn.setDoInput(true);
-      conn.setChunkedStreamingMode(0);
+      //conn.setChunkedStreamingMode(0);
       conn.connect();
       handleConnect(conn);
     } catch (IOException e) {
@@ -83,6 +84,17 @@ class HttpFileInfoThread implements Runnable {
     if (len < 0) {
       String temp = conn.getHeaderField(mTaskEntity.contentLength);
       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;
@@ -90,20 +102,22 @@ class HttpFileInfoThread implements Runnable {
       String md5Code = conn.getHeaderField(mTaskEntity.md5Key);
       mEntity.setMd5Code(md5Code);
     }
-    String disposition = conn.getHeaderField(mTaskEntity.dispositionKey);
+
     Map> headers = conn.getHeaderFields();
     boolean isChunked = false;
     //https://my.oschina.net/ososchina/blog/666761
-    if (conn.getHeaderField("Transfer-Encoding").equals("chunked")) {
+    final String str = conn.getHeaderField("Transfer-Encoding");
+    if (!TextUtils.isEmpty(str) && str.equals("chunked")) {
       isChunked = true;
-      StringBuffer sb = new StringBuffer();
-      byte[] buffer = new byte[1024];
-      InputStream is = conn.getInputStream();
-      int l = 0;
+      //StringBuffer sb = new StringBuffer();
+      //byte[] buffer = new byte[1024];
+      //InputStream is = conn.getInputStream();
+      //int l = 0;
       //while (true){
       //  is.read()
       //}
     }
+    String disposition = conn.getHeaderField(mTaskEntity.dispositionKey);
     if (!TextUtils.isEmpty(disposition)) {
       mEntity.setDisposition(CommonUtil.encryptBASE64(disposition));
       if (disposition.contains(mTaskEntity.dispositionFileKey)) {
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
index eadf2132..9f0be85c 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
@@ -90,28 +90,7 @@ final class HttpThreadTask extends AbsThreadTask {
-
   /**
    * 获取任务状态
    *
diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java
index 8892c8b8..34922b45 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java
@@ -21,10 +21,8 @@ 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.IFtpTarget;
-import com.arialyy.aria.core.manager.TEManager;
 import com.arialyy.aria.util.CheckUtil;
 import com.arialyy.aria.util.CommonUtil;
-import java.io.File;
 
 /**
  * Created by Aria.Lao on 2017/7/27.
@@ -43,7 +41,7 @@ public class FtpUploadTarget extends BaseNormalTarget
   private void initTask(String filePath) {
     initTarget(filePath);
     mTaskEntity.requestType = AbsTaskEntity.U_FTP;
-    mDelegate = new FtpDelegate<>(mTaskEntity);
+    mDelegate = new FtpDelegate<>(this, mTaskEntity);
   }
 
   /**
diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java
index eeacbfd9..1fb08fb7 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java
@@ -43,7 +43,7 @@ public class UploadTarget extends BaseNormalTarget
     //http暂时不支持断点上传
     mTaskEntity.isSupportBP = false;
     mTaskEntity.requestType = AbsTaskEntity.U_HTTP;
-    mDelegate = new HttpHeaderDelegate<>(mTaskEntity);
+    mDelegate = new HttpHeaderDelegate<>(this, mTaskEntity);
   }
 
   @Override public UploadTarget setUploadUrl(@NonNull String uploadUrl) {
diff --git a/AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/MacOsPeterFTPEntryParser.java b/AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/MacOsPeterFTPEntryParser.java
index fd96c8d0..5752a9b9 100644
--- a/AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/MacOsPeterFTPEntryParser.java
+++ b/AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/MacOsPeterFTPEntryParser.java
@@ -29,7 +29,8 @@ import org.apache.commons.net.ftp.FTPFile;
  * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
  * @since 3.1
  */
-public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
+public class
+MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
 
   static final String DEFAULT_DATE_FORMAT = "MMM d yyyy"; //Nov 9 2001
 
diff --git a/DEV_LOG.md b/DEV_LOG.md
index b032d00e..f69f117e 100644
--- a/DEV_LOG.md
+++ b/DEV_LOG.md
@@ -1,6 +1,7 @@
 ## 开发日志
   + v_3.3.16
     - 修复一个activity启动多次,无法进行回掉的bug https://github.com/AriaLyy/Aria/issues/200
+    - 优化target代码结构
   + v_3.3.14
     - 修复ftp上传和下载的兼容性问题
     - 如果url中的path有"//"将替换为"/"
diff --git a/app/src/main/assets/aria_config.xml b/app/src/main/assets/aria_config.xml
index ce92a575..7268c227 100644
--- a/app/src/main/assets/aria_config.xml
+++ b/app/src/main/assets/aria_config.xml
@@ -5,13 +5,13 @@
   
 
     
-    
+    
 
     
     
 
     
-    
+    
 
     
     
diff --git a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
index 96fc98ac..be887ca3 100644
--- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
+++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
@@ -29,6 +29,7 @@ import android.widget.Toast;
 import butterknife.Bind;
 import com.arialyy.annotations.Download;
 import com.arialyy.aria.core.Aria;
+import com.arialyy.aria.core.common.RequestEnum;
 import com.arialyy.aria.core.download.DownloadTarget;
 import com.arialyy.aria.core.download.DownloadTask;
 import com.arialyy.aria.core.inf.IEntity;
@@ -61,8 +62,9 @@ public class SingleTaskActivity extends BaseActivity {
       //"http://qudao.5535.cn/one/game.html?game=531&cpsuser=xiaoeryu2";
       //"https://bogoe-res.mytbz.com/tbzengsong/If You're Happy.mp3";
       //"http://ozr0ucjs5.bkt.clouddn.com/51_box-104_20180131202610.apk";
-      "http://kf.lyfz.net/api/v1/we_chat/Business/getMaterial?company_id=51454009d703c86c91353f61011ecf2f&appid=wx88c6052d06eaaf7d&media_id=qpkQb72KqNkZhBNIUw7asF0LuJouXCTBd3A-rS2bYl7H4kvTZstEXD3F-pDVeqA-&type=3";
+      //"http://kf.lyfz.net/api/v1/we_chat/Business/getMaterial?company_id=51454009d703c86c91353f61011ecf2f&appid=wx88c6052d06eaaf7d&media_id=qpkQb72KqNkZhBNIUw7asF0LuJouXCTBd3A-rS2bYl7H4kvTZstEXD3F-pDVeqA-&type=3";
       //"https://www.baidu.com/link?url=_LFCuTPtnzFxVJByJ504QymRywIA1Z_T5xUxe9ZLuxcGM0C_RcdpWyB1eGjbJC-e5wv5wAKM4WmLMAS5KeF6EZJHB8Va3YqZUiaErqK_pxm&wd=&eqid=e8583fe70002d126000000065a99f864";
+      "http://58.210.9.131/tpk/sipgt/TDLYZTGH.tpk";
   @Bind(R.id.start) Button mStart;
   @Bind(R.id.stop) Button mStop;
   @Bind(R.id.cancel) Button mCancel;
@@ -230,8 +232,8 @@ public class SingleTaskActivity extends BaseActivity {
         .addHeader("Accept-Encoding", "gzip, deflate")
         .addHeader("DNT", "1")
         //.addHeader("Cookie", "BAIDUID=648E5FF020CC69E8DD6F492D1068AAA9:FG=1; BIDUPSID=648E5FF020CC69E8DD6F492D1068AAA9; PSTM=1519099573; BD_UPN=12314753; locale=zh; BDSVRTM=0")
-        //.setRequestMode(RequestEnum.POST)
-        .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/ggsg1.apk")
+        .setRequestMode(RequestEnum.GET)
+        .setFilePath(Environment.getExternalStorageDirectory().getPath() + "/ggsg1.apk")
         .resetState()
         .start();
     //.add();

From f2e566ba7e00d7b7dfe1a035a662d7385ec8bcb3 Mon Sep 17 00:00:00 2001
From: laoyuyu <511455842@qq.com>
Date: Tue, 13 Mar 2018 21:54:39 +0800
Subject: [PATCH 07/22] =?UTF-8?q?=E6=B7=BB=E5=8A=A0chunled=20=E6=94=AF?=
 =?UTF-8?q?=E6=8C=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../arialyy/aria/core/common/AbsFileer.java   |  6 +-----
 .../aria/core/download/BaseGroupTarget.java   |  2 +-
 .../aria/core/download/BaseNormalTarget.java  | 12 +++++++----
 .../core/download/DownloadGroupTarget.java    |  4 ++++
 .../core/download/FtpDirDownloadTarget.java   |  8 ++++---
 .../downloader/HttpFileInfoThread.java        | 21 ++++---------------
 .../download/downloader/HttpThreadTask.java   |  9 ++++----
 .../aria/core/scheduler/AbsSchedulers.java    |  2 +-
 DEV_LOG.md                                    |  3 ++-
 app/src/main/assets/aria_config.xml           |  2 +-
 .../simple/download/SingleTaskActivity.java   |  8 +++----
 11 files changed, 36 insertions(+), 41 deletions(-)

diff --git a/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java b/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
index bf30ff74..c7fb1145 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
@@ -129,11 +129,7 @@ public abstract class AbsFileer
   /**
    * 文件夹临时路径
    */
-  private String mDirPathTemp;
+  protected String mDirPathTemp;
 
   private SubTaskManager mSubTaskManager;
 
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java
index b488685e..d2daf220 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java
@@ -47,6 +47,9 @@ abstract class BaseNormalTarget
     }
     mEntity = mTaskEntity.entity;
     mTaskEntity.refreshInfo = refreshInfo;
+    if (mEntity != null) {
+      mTempFilePath = mEntity.getDownloadPath();
+    }
   }
 
   /**
@@ -61,6 +64,9 @@ abstract class BaseNormalTarget
     }
     mEntity = mTaskEntity.entity;
     mTaskEntity.refreshInfo = refreshInfo;
+    if (mEntity != null) {
+      mTempFilePath = mEntity.getDownloadPath();
+    }
   }
 
   /**
@@ -97,8 +103,7 @@ abstract class BaseNormalTarget
    *
    * @deprecated {@link #isRunning()}
    */
-  @Deprecated
-  public boolean isDownloading() {
+  @Deprecated public boolean isDownloading() {
     return isRunning();
   }
 
@@ -121,8 +126,7 @@ abstract class BaseNormalTarget
    *
    * @return {@code true}合法
    */
-  @Override
-  protected boolean checkEntity() {
+  @Override protected boolean checkEntity() {
     return getTargetType() < GROUP_HTTP && checkUrl() && checkFilePath();
   }
 
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
index 903f8b7e..6dc2d36f 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
@@ -56,6 +56,10 @@ public class DownloadGroupTarget extends BaseGroupTarget {
           TEManager.getInstance().createTEntity(DownloadGroupTaskEntity.class, groupEntity);
     }
     mEntity = mTaskEntity.entity;
+
+    if (mEntity != null) {
+      mDirPathTemp = mEntity.getDirPath();
+    }
   }
 
   DownloadGroupTarget(List urls, String targetName) {
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
index cb7b2d01..04b09e5c 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java
@@ -26,8 +26,8 @@ import com.arialyy.aria.util.ALog;
  * Created by Aria.Lao on 2017/7/26.
  * ftp文件夹下载
  */
-public class FtpDirDownloadTarget extends BaseGroupTarget implements
-    IFtpTarget {
+public class FtpDirDownloadTarget extends BaseGroupTarget
+    implements IFtpTarget {
   private final String TAG = "FtpDirDownloadTarget";
   private FtpDelegate mDelegate;
 
@@ -44,7 +44,9 @@ public class FtpDirDownloadTarget extends BaseGroupTarget
     }
     mTaskEntity.requestType = AbsTaskEntity.D_FTP_DIR;
     mEntity = mTaskEntity.entity;
-
+    if (mEntity != null) {
+      mDirPathTemp = mEntity.getDirPath();
+    }
     mDelegate = new FtpDelegate<>(this, mTaskEntity);
   }
 
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
index 0bfaceb0..6a05844f 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
@@ -15,9 +15,7 @@
  */
 package com.arialyy.aria.core.download.downloader;
 
-import android.location.Address;
 import android.text.TextUtils;
-import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.common.CompleteInfo;
 import com.arialyy.aria.core.common.OnFileInfoCallback;
@@ -27,11 +25,8 @@ import com.arialyy.aria.util.ALog;
 import com.arialyy.aria.util.CheckUtil;
 import com.arialyy.aria.util.CommonUtil;
 import java.io.IOException;
-import java.io.InputStream;
 import java.net.HttpURLConnection;
-import java.net.InetAddress;
 import java.net.URL;
-import java.net.URLConnection;
 import java.net.URLDecoder;
 import java.util.List;
 import java.util.Map;
@@ -86,11 +81,11 @@ class HttpFileInfoThread implements Runnable {
       len = TextUtils.isEmpty(temp) ? -1 : Long.parseLong(temp);
       // 某些服务,如果设置了conn.setRequestProperty("Range", "bytes=" + 0 + "-");
       // 会返回 Content-Range: bytes 0-225427911/225427913
-      if (len < 0){
+      if (len < 0) {
         temp = conn.getHeaderField("Content-Range");
-        if (TextUtils.isEmpty(temp)){
+        if (TextUtils.isEmpty(temp)) {
           len = -1;
-        }else {
+        } else {
           int start = temp.indexOf("/");
           len = Long.parseLong(temp.substring(start + 1, temp.length()));
         }
@@ -103,19 +98,11 @@ class HttpFileInfoThread implements Runnable {
       mEntity.setMd5Code(md5Code);
     }
 
-    Map> headers = conn.getHeaderFields();
+    //Map> headers = conn.getHeaderFields();
     boolean isChunked = false;
-    //https://my.oschina.net/ososchina/blog/666761
     final String str = conn.getHeaderField("Transfer-Encoding");
     if (!TextUtils.isEmpty(str) && str.equals("chunked")) {
       isChunked = true;
-      //StringBuffer sb = new StringBuffer();
-      //byte[] buffer = new byte[1024];
-      //InputStream is = conn.getInputStream();
-      //int l = 0;
-      //while (true){
-      //  is.read()
-      //}
     }
     String disposition = conn.getHeaderField(mTaskEntity.dispositionKey);
     if (!TextUtils.isEmpty(disposition)) {
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
index 9f0be85c..68850799 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpThreadTask.java
@@ -90,7 +90,7 @@ final class HttpThreadTask extends AbsThreadTask>> iter =
diff --git a/DEV_LOG.md b/DEV_LOG.md
index f69f117e..a35dc6c3 100644
--- a/DEV_LOG.md
+++ b/DEV_LOG.md
@@ -1,7 +1,8 @@
 ## 开发日志
   + v_3.3.16
     - 修复一个activity启动多次,无法进行回掉的bug https://github.com/AriaLyy/Aria/issues/200
-    - 优化target代码结构
+    - 优化target代码结构,移除路径被占用的提示
+    - 添加支持chunked模式的下载
   + v_3.3.14
     - 修复ftp上传和下载的兼容性问题
     - 如果url中的path有"//"将替换为"/"
diff --git a/app/src/main/assets/aria_config.xml b/app/src/main/assets/aria_config.xml
index 7268c227..9cd82f96 100644
--- a/app/src/main/assets/aria_config.xml
+++ b/app/src/main/assets/aria_config.xml
@@ -5,7 +5,7 @@
   
 
     
-    
+    
 
     
     
diff --git a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
index be887ca3..f92518ee 100644
--- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
+++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
@@ -200,7 +200,7 @@ public class SingleTaskActivity extends BaseActivity {
       mStart.setText("恢复");
       mStart.setTextColor(getResources().getColor(android.R.color.holo_blue_light));
       setBtState(true);
-    } else if (target.isDownloading()) {
+    } else if (target.isRunning()) {
       setBtState(false);
     }
     getBinding().setFileSize(target.getConvertFileSize());
@@ -212,12 +212,12 @@ public class SingleTaskActivity extends BaseActivity {
         startD();
         break;
       case R.id.stop:
-        //Aria.download(this).load(DOWNLOAD_URL).stop();
-        startActivity(new Intent(this, SingleTaskActivity.class));
+        Aria.download(this).load(DOWNLOAD_URL).stop();
+        //startActivity(new Intent(this, SingleTaskActivity.class));
         //Aria.download(this).load(DOWNLOAD_URL).removeRecord();
         break;
       case R.id.cancel:
-        //Aria.download(this).load(DOWNLOAD_URL).cancel();
+        Aria.download(this).load(DOWNLOAD_URL).cancel();
         Aria.download(this).load(DOWNLOAD_URL).removeRecord();
         break;
     }

From fbe3b137e1353032adb5917c22bbedec85b4707d Mon Sep 17 00:00:00 2001
From: laoyuyu <511455842@qq.com>
Date: Sat, 17 Mar 2018 10:26:11 +0800
Subject: [PATCH 08/22] bug fix

---
 .../com/arialyy/aria/core/AriaManager.java    |  4 +--
 .../aria/core/delegate/ParamContainer.java    | 35 +++++++++++++++++++
 .../aria/core/download/BaseNormalTarget.java  | 11 ++----
 .../core/download/DownloadGroupTarget.java    | 12 -------
 .../core/download/FtpDirDownloadTarget.java   |  8 -----
 .../com/arialyy/aria/core/inf/IFtpTarget.java |  2 --
 .../aria/core/upload/BaseNormalTarget.java    | 14 --------
 .../java/com/arialyy/aria/util/CheckUtil.java | 34 ------------------
 DEV_LOG.md                                    |  1 +
 .../simple/download/FtpDownloadActivity.java  |  6 ++--
 .../simple/download/SingleTaskActivity.java   | 24 +++----------
 .../simple/upload/FtpUploadActivity.java      |  4 +--
 build.gradle                                  |  2 +-
 13 files changed, 50 insertions(+), 107 deletions(-)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/delegate/ParamContainer.java

diff --git a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
index 068ccdc6..c7c5968a 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
@@ -111,7 +111,7 @@ import org.xml.sax.SAXException;
    *   
    *     Aria.get(this).getUploadConfig().setQueueMod(mod.tag)
    *   
-   * 
+   * 
* * @param mod {@link QueueMod} * @deprecated 后续版本会删除该api @@ -128,7 +128,7 @@ import org.xml.sax.SAXException; * * Aria.get(this).getDownloadConfig().setQueueMod(mod.tag) * - *
+   * 
* * @param mod {@link QueueMod} * @deprecated 后续版本会删除该api diff --git a/Aria/src/main/java/com/arialyy/aria/core/delegate/ParamContainer.java b/Aria/src/main/java/com/arialyy/aria/core/delegate/ParamContainer.java new file mode 100644 index 00000000..a9cbca87 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/delegate/ParamContainer.java @@ -0,0 +1,35 @@ +/* + * 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 java.util.HashMap; +import java.util.Map; + +/** + * Created by AriaL on 2018/3/17. + * 参数容器,用来临时存储链式命令的需要的参数。 + */ +public class ParamContainer { + + public String url; + public String filePath; + public String charSet; + public Map header = new HashMap<>(); + + // ftp 相关的 + public String userName, userPw, userAccount; + public boolean needLogin; +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java index d2daf220..af02d37b 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java @@ -147,7 +147,7 @@ abstract class BaseNormalTarget File file = new File(filePath); if (file.isDirectory()) { if (getTargetType() == HTTP) { - ALog.e(TAG, "保存路径【" + filePath + "】不能为文件夹,路径需要是完整的文件路径,如:/mnt/sdcard/game.zip"); + ALog.e(TAG, "下载失败,保存路径【" + filePath + "】不能为文件夹,路径需要是完整的文件路径,如:/mnt/sdcard/game.zip"); return false; } else if (getTargetType() == FTP) { filePath += mEntity.getFileName(); @@ -157,7 +157,7 @@ abstract class BaseNormalTarget if (!filePath.equals(mEntity.getDownloadPath())) { if (!mTaskEntity.refreshInfo && DbEntity.checkDataExist(DownloadEntity.class, "downloadPath=?", filePath)) { - ALog.e(TAG, "保存路径【" + filePath + "】已经被其它任务占用,请设置其它保存路径"); + ALog.e(TAG, "下载失败,保存路径【" + filePath + "】已经被其它任务占用,请设置其它保存路径"); return false; } File oldFile = new File(mEntity.getDownloadPath()); @@ -192,13 +192,6 @@ abstract class BaseNormalTarget ALog.e(TAG, "下载失败,url【" + url + "】不合法"); return false; } - String temp = url.substring(index + 3, url.length()); - if (temp.contains("//")) { - temp = url.substring(0, index + 3) + temp.replaceAll("//", "/"); - ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp); - mEntity.setUrl(temp); - mEntity.update(); - } return true; } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java index 6dc2d36f..07ef9efb 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java @@ -200,7 +200,6 @@ public class DownloadGroupTarget extends BaseGroupTarget { } Set delItem = new HashSet<>(); - Map reSetUrl = new WeakHashMap<>(); int i = 0; for (String url : mUrls) { if (TextUtils.isEmpty(url)) { @@ -220,20 +219,9 @@ public class DownloadGroupTarget extends BaseGroupTarget { continue; } - String temp = url.substring(index + 3, url.length()); - if (temp.contains("//")) { - temp = url.substring(0, index + 3) + temp.replaceAll("//", "/"); - ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp); - reSetUrl.put(i, temp); - } i++; } - Set keys = reSetUrl.keySet(); - for (Integer index : keys) { - mUrls.set(index, reSetUrl.get(index)); - } - for (int index : delItem) { mUrls.remove(index); if (mSubNameTemp != null && !mSubNameTemp.isEmpty()) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java index 04b09e5c..b71c8b35 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java @@ -77,14 +77,6 @@ public class FtpDirDownloadTarget extends BaseGroupTarget ALog.e(TAG, "下载失败,url【" + url + "】不合法"); return false; } - String temp = url.substring(index + 3, url.length()); - if (temp.contains("//")) { - temp = url.substring(0, index + 3) + temp.replaceAll("//", "/"); - ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp); - mGroupName = temp; - mEntity.setGroupName(temp); - mEntity.update(); - } return true; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java index 5f5a68fd..519b4393 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/IFtpTarget.java @@ -26,7 +26,6 @@ public interface IFtpTarget { /** * ftp 用户登录信。 - * 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)} * * @param userName ftp用户名 * @param password ftp用户密码 @@ -35,7 +34,6 @@ public interface IFtpTarget { /** * ftp 用户登录信息 - * 设置登录信息需要在设置上传链接之后{@link #setUploadUrl(String)} * * @param userName ftp用户名 * @param password ftp用户密码 diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java index 9a2a31b4..a7014c98 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java @@ -98,13 +98,6 @@ abstract class BaseNormalTarget ALog.e(TAG, "上传失败,文件【" + filePath + "】不能死文件夹"); return false; } - - if (filePath.contains("//")) { - filePath = filePath.replaceAll("//", "/"); - ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + filePath); - mEntity.setFilePath(filePath); - mEntity.update(); - } return true; } @@ -127,13 +120,6 @@ abstract class BaseNormalTarget ALog.e(TAG, "上传失败,url【" + url + "】不合法"); return false; } - String temp = url.substring(index + 3, url.length()); - if (temp.contains("//")) { - temp = url.substring(0, index + 3) + temp.replaceAll("//", "/"); - ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp); - mEntity.setUrl(temp); - mEntity.update(); - } return true; } } diff --git a/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java b/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java index 1f67935c..65cd9b53 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java @@ -100,43 +100,9 @@ public class CheckUtil { if (index == -1) { throw new IllegalArgumentException("url不合法"); } - String temp = url.substring(index + 3, url.length()); - if (temp.contains("//")) { - temp = url.substring(0, index + 3) + temp.replaceAll("//", "/"); - ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp); - return temp; - } return url; } - ///** - // * 检查普通任务的下载地址 - // * - // * @return {@code true}地址合法 - // */ - //public static boolean checkUrl(DownloadEntity entity, String url) { - // 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; - // } - // String temp = url.substring(index + 3, url.length()); - // if (temp.contains("//")) { - // temp = url.substring(0, index + 3) + temp.replaceAll("//", "/"); - // ALog.w(TAG, "url中含有//,//将转换为/,转换后的url为:" + temp); - // entity.setUrl(temp); - // entity.update(); - // } - // return true; - //} - /** * 检测下载链接组是否为null */ diff --git a/DEV_LOG.md b/DEV_LOG.md index a35dc6c3..8b93501f 100644 --- a/DEV_LOG.md +++ b/DEV_LOG.md @@ -3,6 +3,7 @@ - 修复一个activity启动多次,无法进行回掉的bug https://github.com/AriaLyy/Aria/issues/200 - 优化target代码结构,移除路径被占用的提示 - 添加支持chunked模式的下载 + - 去掉上一个版本"//"的限制 + v_3.3.14 - 修复ftp上传和下载的兼容性问题 - 如果url中的path有"//"将替换为"/" diff --git a/app/src/main/java/com/arialyy/simple/download/FtpDownloadActivity.java b/app/src/main/java/com/arialyy/simple/download/FtpDownloadActivity.java index 9fc20cc0..0e6e7b32 100644 --- a/app/src/main/java/com/arialyy/simple/download/FtpDownloadActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/FtpDownloadActivity.java @@ -37,7 +37,7 @@ import java.io.File; public class FtpDownloadActivity extends BaseActivity { //private final String URL = "ftp://192.168.1.9:21/下载/AriaPrj.zip"; //private final String URL = "ftp://182.92.180.213:21/video/572fed5c2ad48_1024.jpg"; - private final String URL = "ftp://192.168.1.6:21/download/AriaPrj.zip"; + private final String URL = "ftp://192.168.1.7:21/download//AriaPrj.zip"; //private final String URL = "ftp://d:d@dygodj8.com:12311/咖啡风暴HD大陆公映意语中字[飘花www.piaohua.com].mp4"; @Override protected void init(Bundle savedInstanceState) { @@ -59,10 +59,10 @@ public class FtpDownloadActivity extends BaseActivity { @@ -49,22 +46,9 @@ public class SingleTaskActivity extends BaseActivity { //"http://kotlinlang.org/docs/kotlin-docs.pdf"; //"https://atom-installer.github.com/v1.13.0/AtomSetup.exe?s=1484074138&ext=.exe"; //"http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk"; - //"http://sitcac.daxincf.cn/wp-content/uploads/swift_vido/01/element.mp4_1"; - //"http://120.25.196.56:8000/filereq?id=15692406294&ipncid=105635&client=android&filename=20170819185541.avi"; - //"http://down2.xiaoshuofuwuqi.com/d/file/filetxt/20170608/14/%BA%DA%CE%D7%CA%A6%E1%C8%C6%F0.txt"; - //"http://tinghuaapp.oss-cn-shanghai.aliyuncs.com/20170612201739607815"; - //"http://static.gaoshouyou.com/d/36/69/2d3699acfa69e9632262442c46516ad8.apk"; - //"http://oqcpqqvuf.bkt.clouddn.com/ceshi.txt"; - //"http://down8.androidgame-store.com/201706122321/97967927DD4E53D9905ECAA7874C8128/new/game1/19/45319/com.neuralprisma-2.5.2.174-2000174_1494784835.apk?f=web_1"; - //不支持断点的链接 - //"http://ox.konsung.net:5555/ksdc-web/download/downloadFile/?fileName=ksdc_1.0.2.apk&rRange=0-"; - //"http://gdown.baidu.com/data/wisegame/0904344dee4a2d92/QQ_718.apk"; - //"http://qudao.5535.cn/one/game.html?game=531&cpsuser=xiaoeryu2"; - //"https://bogoe-res.mytbz.com/tbzengsong/If You're Happy.mp3"; - //"http://ozr0ucjs5.bkt.clouddn.com/51_box-104_20180131202610.apk"; - //"http://kf.lyfz.net/api/v1/we_chat/Business/getMaterial?company_id=51454009d703c86c91353f61011ecf2f&appid=wx88c6052d06eaaf7d&media_id=qpkQb72KqNkZhBNIUw7asF0LuJouXCTBd3A-rS2bYl7H4kvTZstEXD3F-pDVeqA-&type=3"; - //"https://www.baidu.com/link?url=_LFCuTPtnzFxVJByJ504QymRywIA1Z_T5xUxe9ZLuxcGM0C_RcdpWyB1eGjbJC-e5wv5wAKM4WmLMAS5KeF6EZJHB8Va3YqZUiaErqK_pxm&wd=&eqid=e8583fe70002d126000000065a99f864"; - "http://58.210.9.131/tpk/sipgt/TDLYZTGH.tpk"; + //不支持断点的链接 + "http://58.210.9.131/tpk/sipgt//TDLYZTGH.tpk"; //chunked 下载 + //"https://static.donguo.me//video/ip/course/pfys_1.mp4"; @Bind(R.id.start) Button mStart; @Bind(R.id.stop) Button mStop; @Bind(R.id.cancel) Button mCancel; @@ -234,7 +218,7 @@ public class SingleTaskActivity extends BaseActivity { //.addHeader("Cookie", "BAIDUID=648E5FF020CC69E8DD6F492D1068AAA9:FG=1; BIDUPSID=648E5FF020CC69E8DD6F492D1068AAA9; PSTM=1519099573; BD_UPN=12314753; locale=zh; BDSVRTM=0") .setRequestMode(RequestEnum.GET) .setFilePath(Environment.getExternalStorageDirectory().getPath() + "/ggsg1.apk") - .resetState() + //.resetState() .start(); //.add(); } diff --git a/app/src/main/java/com/arialyy/simple/upload/FtpUploadActivity.java b/app/src/main/java/com/arialyy/simple/upload/FtpUploadActivity.java index 368e9131..21f8927c 100644 --- a/app/src/main/java/com/arialyy/simple/upload/FtpUploadActivity.java +++ b/app/src/main/java/com/arialyy/simple/upload/FtpUploadActivity.java @@ -35,8 +35,8 @@ import java.io.File; * Ftp 文件上传demo */ public class FtpUploadActivity extends BaseActivity { - private final String FILE_PATH = "/mnt/sdcard/AriaPrj.zip"; - private final String URL = "ftp://192.168.1.6:21/aa/你好"; + private final String FILE_PATH = "/mnt/sdcard/sql.rar"; + private final String URL = "ftp://192.168.1.7:21/aa//你好"; @Override protected void init(Bundle savedInstanceState) { setTile("D_FTP 文件上传"); diff --git a/build.gradle b/build.gradle index 9d7946bb..2a1181a0 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ task clean(type: Delete) { ext { userOrg = 'arialyy' groupId = 'com.arialyy.aria' - publishVersion = '3.3.16_dev' + publishVersion = '3.3.16_dev2' // publishVersion = '1.0.3' //FTP插件 repoName='maven' desc = 'android 下载框架' From 277ac8f4c58c652e6c87bc5ed40baba30e79bdd7 Mon Sep 17 00:00:00 2001 From: laoyuyu <511455842@qq.com> Date: Tue, 20 Mar 2018 19:38:24 +0800 Subject: [PATCH 09/22] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E5=88=A0=E9=99=A4=E4=B8=80=E4=BA=9B=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E7=9A=84api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: If9c79ebd7ddec2cb0f01539f4d38555608e14bea --- .../arialyy/aria/core/common/AbsFileer.java | 34 +++------- .../com/arialyy/aria/core/common/IUtil.java | 18 +++--- .../core/delegate/HttpHeaderDelegate.java | 63 ------------------- .../aria/core/delegate/ParamContainer.java | 35 ----------- .../aria/core/download/AbsDownloadTarget.java | 13 ---- .../aria/core/download/BaseNormalTarget.java | 17 ----- .../aria/core/download/DownloadEntity.java | 6 +- .../aria/core/download/DownloadReceiver.java | 2 +- .../aria/core/download/DownloadTarget.java | 23 +------ .../aria/core/download/DownloadTask.java | 12 +--- .../aria/core/download/FtpDownloadTarget.java | 3 +- .../download/downloader/AbsGroupUtil.java | 3 +- .../download/downloader/ConnectionHelp.java | 44 ++++++------- .../core/download/downloader/Downloader.java | 6 ++ .../downloader/HttpFileInfoThread.java | 17 +++-- .../arialyy/aria/core/inf/AbsTaskEntity.java | 20 ------ .../aria/core/inf/IHttpHeaderTarget.java | 27 -------- .../aria/core/scheduler/AbsSchedulers.java | 4 +- .../aria/core/upload/UploadTarget.java | 16 ----- .../aria/core/upload/uploader/Uploader.java | 2 +- .../java/com/arialyy/aria/orm/DBConfig.java | 2 +- .../simple/download/SingleTaskActivity.java | 2 +- 22 files changed, 67 insertions(+), 302 deletions(-) delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/delegate/ParamContainer.java diff --git a/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java b/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java index c7fb1145..cef4ea3b 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java @@ -36,12 +36,13 @@ import java.util.concurrent.Executors; /** * Created by AriaL on 2017/7/1. - * 文件下载器 + * 任务处理器 */ public abstract class AbsFileer> 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 +50,7 @@ public abstract class AbsFileer header = new HashMap<>(); - - // ftp 相关的 - public String userName, userPw, userAccount; - public boolean needLogin; -} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java index b9e33158..c48943e3 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/AbsDownloadTarget.java @@ -15,13 +15,11 @@ */ package com.arialyy.aria.core.download; -import android.text.TextUtils; 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.ALog; import com.arialyy.aria.util.CommonUtil; /** @@ -72,17 +70,6 @@ abstract class AbsDownloadTarget */ protected String url; - /** - * 通过实体初始化target - */ - void initTarget(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; - if (mEntity != null) { - mTempFilePath = mEntity.getDownloadPath(); - } - } - /** * 通过地址初始化target */ diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java index 91f11d1c..432015ac 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java @@ -43,13 +43,13 @@ public class DownloadEntity extends AbsNormalEntity implements Parcelable { @Foreign(table = DownloadTaskEntity.class, column = "key") private String taskKey = ""; /** - * 通过{@link AbsTaskEntity#md5Key}从服务器的返回信息中获取的文件md5信息,如果服务器没有返回,则不会设置该信息 + * 从服务器的返回信息中获取的文件md5信息,如果服务器没有返回,则不会设置该信息 * 如果你已经设置了该任务的MD5信息,Aria也不会从服务器返回的信息中获取该信息 */ private String md5Code = ""; /** - * 通过{@link AbsTaskEntity#dispositionKey}从服务器的返回信息中获取的文件描述信息 + * 从服务器的返回信息中获取的文件描述信息 */ private String disposition = ""; @@ -117,8 +117,6 @@ public class DownloadEntity extends AbsNormalEntity implements Parcelable { return this; } - - @Override public DownloadEntity clone() throws CloneNotSupportedException { return (DownloadEntity) super.clone(); } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java index 88e125b6..b8101a36 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java @@ -182,7 +182,7 @@ public class DownloadReceiver extends AbsReceiver { * * @param groupEntity 如果加载的任务实体没有子项的下载地址, * 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址 - * @deprecated {@link #loadGroup(DownloadGroupEntity)} + * @deprecated 请使用 {@link #loadGroup(DownloadGroupEntity)} */ @Deprecated public DownloadGroupTarget load(DownloadGroupEntity groupEntity) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java index 3ec327da..8f608f00 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java @@ -35,8 +35,7 @@ public class DownloadTarget extends BaseNormalTarget } DownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) { - initTarget(entity, targetName, refreshInfo); - initTHis(); + this(entity.getUrl(), targetName, refreshInfo); } DownloadTarget(String url, String targetName) { @@ -45,10 +44,6 @@ public class DownloadTarget extends BaseNormalTarget DownloadTarget(String url, String targetName, boolean refreshInfo) { initTarget(url, targetName, refreshInfo); - initTHis(); - } - - private void initTHis() { mDelegate = new HttpHeaderDelegate<>(this, mTaskEntity); } @@ -110,20 +105,4 @@ public class DownloadTarget extends BaseNormalTarget @Override public DownloadTarget setRequestMode(RequestEnum requestEnum) { return mDelegate.setRequestMode(requestEnum); } - - @Override public DownloadTarget setHeaderMd5Key(String md5Key) { - return mDelegate.setHeaderMd5Key(md5Key); - } - - @Override public DownloadTarget setHeaderContentLengthKey(String contentLength) { - return mDelegate.setHeaderContentLengthKey(contentLength); - } - - @Override public DownloadTarget setHeaderDispositionKey(String dispositionKey) { - return mDelegate.setHeaderDispositionKey(dispositionKey); - } - - @Override public DownloadTarget setHeaderDispositionFileKey(String dispositionFileKey) { - return mDelegate.setHeaderDispositionFileKey(dispositionFileKey); - } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java index b45a9478..aeecb62f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java @@ -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,11 @@ public class DownloadTask extends AbsNormalTask { } /** - * 任务下载状态 - * - * @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() { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java index 518f3142..35ce167c 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java @@ -31,8 +31,7 @@ public class FtpDownloadTarget extends BaseNormalTarget private FtpDelegate mDelegate; FtpDownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) { - initTarget(entity, targetName, refreshInfo); - init(refreshInfo); + this(entity.getUrl(), targetName, refreshInfo); } FtpDownloadTarget(String url, String targetName) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java index 7bd318c5..52e56a5d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java @@ -389,7 +389,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); @@ -417,7 +417,6 @@ public abstract class AbsGroupUtil implements IUtil { 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; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java index 702f253c..5929ec66 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java @@ -81,28 +81,28 @@ class ConnectionHelp { conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"); } - //if (keys == null || !keys.contains("Accept")) { - // StringBuilder accept = new StringBuilder(); - // accept.append("image/gif, ") - // .append("image/jpeg, ") - // .append("image/pjpeg, ") - // .append("image/webp, ") - // .append("image/apng, ") - // .append("application/xml, ") - // .append("application/xaml+xml, ") - // .append("application/xhtml+xml, ") - // .append("application/x-shockwave-flash, ") - // .append("application/x-ms-xbap, ") - // .append("application/x-ms-application, ") - // .append("application/msword, ") - // .append("application/vnd.ms-excel, ") - // .append("application/vnd.ms-xpsdocument, ") - // .append("application/vnd.ms-powerpoint, ") - // .append("text/plain, ") - // .append("text/html, ") - // .append("*/*"); - // conn.setRequestProperty("Accept", accept.toString()); - //} + if (keys == null || !keys.contains("Accept")) { + StringBuilder accept = new StringBuilder(); + accept.append("image/gif, ") + .append("image/jpeg, ") + .append("image/pjpeg, ") + .append("image/webp, ") + .append("image/apng, ") + .append("application/xml, ") + .append("application/xaml+xml, ") + .append("application/xhtml+xml, ") + .append("application/x-shockwave-flash, ") + .append("application/x-ms-xbap, ") + .append("application/x-ms-application, ") + .append("application/msword, ") + .append("application/vnd.ms-excel, ") + .append("application/vnd.ms-xpsdocument, ") + .append("application/vnd.ms-powerpoint, ") + .append("text/plain, ") + .append("text/html, ") + .append("*/*"); + conn.setRequestProperty("Accept", accept.toString()); + } if (keys == null || !keys.contains("Accept-Encoding")) { conn.setRequestProperty("Accept-Encoding", "identity"); } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java index e72c97bd..a7baafea 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java @@ -44,6 +44,12 @@ class Downloader extends AbsFileer { AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getUpdateInterval()); } + @Override protected int setNewTaskThreadNum() { + return mEntity.getFileSize() <= SUB_LEN || mTaskEntity.requestType == 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()); diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java index 6a05844f..9e914437 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java @@ -28,8 +28,6 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLDecoder; -import java.util.List; -import java.util.Map; /** * 下载文件信息获取 @@ -77,7 +75,7 @@ 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 @@ -94,7 +92,7 @@ class HttpFileInfoThread implements Runnable { int code = conn.getResponseCode(); boolean isComplete = false; if (TextUtils.isEmpty(mEntity.getMd5Code())) { - String md5Code = conn.getHeaderField(mTaskEntity.md5Key); + String md5Code = conn.getHeaderField("Content-MD5"); mEntity.setMd5Code(md5Code); } @@ -104,7 +102,7 @@ class HttpFileInfoThread implements Runnable { if (!TextUtils.isEmpty(str) && str.equals("chunked")) { isChunked = true; } - String disposition = conn.getHeaderField(mTaskEntity.dispositionKey); + String disposition = conn.getHeaderField("Content-Disposition"); if (!TextUtils.isEmpty(disposition)) { mEntity.setDisposition(CommonUtil.encryptBASE64(disposition)); if (disposition.contains(mTaskEntity.dispositionFileKey)) { @@ -133,10 +131,10 @@ class HttpFileInfoThread implements Runnable { } else if (code == HttpURLConnection.HTTP_MOVED_TEMP || code == HttpURLConnection.HTTP_MOVED_PERM || code == HttpURLConnection.HTTP_SEE_OTHER) { - mTaskEntity.redirectUrl = conn.getHeaderField(mTaskEntity.redirectUrlKey); + mTaskEntity.redirectUrl = conn.getHeaderField("Location"); mEntity.setRedirect(true); mEntity.setRedirectUrl(mTaskEntity.redirectUrl); - handle302Turn(conn); + handle302Turn(conn, mTaskEntity.redirectUrl); } else { failDownload("任务【" + mEntity.getUrl() + "】下载失败,错误码:" + code, true); } @@ -153,9 +151,8 @@ class HttpFileInfoThread implements Runnable { /** * 处理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 handle302Turn(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) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java index b63fad34..f369d93f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java @@ -101,37 +101,17 @@ public abstract class AbsTaskEntity extends DbEntity { */ public RequestEnum requestEnum = RequestEnum.GET; - /** - * 从header中含有的文件md5码信息所需要的key - */ - public String md5Key = "Content-MD5"; - /** * 是否使用服务器通过content-disposition传递的文件名,内容格式{@code attachment;filename=***} * {@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"; - /** * 重定向链接 */ diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java index 8cd41def..72b5aa47 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/IHttpHeaderTarget.java @@ -49,31 +49,4 @@ public interface IHttpHeaderTarget { * @param requestEnum {@link RequestEnum} */ TARGET setRequestMode(RequestEnum requestEnum); - - /** - * 如果你的下载链接的header中含有md5码信息,那么你可以通过设置key,来获取从header获取该md5码信息。 - * key默认值为:Content-MD5 - * 获取md5信息:{@link DownloadEntity#getMd5Code()} - */ - TARGET setHeaderMd5Key(String md5Key); - - /** - * 如果你的文件长度是放在header中,那么你需要配置key来让Aria知道正确的文件长度 - * key默认值为:Content-Length - */ - TARGET setHeaderContentLengthKey(String contentLength); - - /** - * 如果你的下载链接的header中含有文件描述信息,那么你可以通过设置key,来获取从header获取该文件描述信息。 - * key默认值为:Content-Disposition - * 获取文件描述信息:{@link DownloadEntity#getDisposition()} - */ - TARGET setHeaderDispositionKey(String dispositionKey); - - /** - * 从文件描述信息{@link #setHeaderDispositionKey(String)}中含有文件名信息,你可以通过设置key来获取header中的文件名 - * key默认值为:attachment;filename - * 获取文件名信息:{@link DownloadEntity#getServerFileName()} - */ - TARGET setHeaderDispositionFileKey(String dispositionFileKey); } diff --git a/Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java b/Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java index fd8b2be5..a48bb7f5 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java +++ b/Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java @@ -38,8 +38,8 @@ import java.util.concurrent.ConcurrentHashMap; * Created by lyy on 2017/6/4. * 事件调度器,用于处理任务状态的调度 */ -abstract class AbsSchedulers, QUEUE extends ITaskQueue> - implements ISchedulers { +abstract class AbsSchedulers, + QUEUE extends ITaskQueue> implements ISchedulers { private final String TAG = "AbsSchedulers"; protected QUEUE mQueue; diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java index 1fb08fb7..a7b4a042 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java @@ -95,20 +95,4 @@ public class UploadTarget extends BaseNormalTarget @Override public UploadTarget setRequestMode(RequestEnum requestEnum) { return mDelegate.setRequestMode(requestEnum); } - - @Override public UploadTarget setHeaderMd5Key(String md5Key) { - return mDelegate.setHeaderMd5Key(md5Key); - } - - @Override public UploadTarget setHeaderContentLengthKey(String contentLength) { - return mDelegate.setHeaderContentLengthKey(contentLength); - } - - @Override public UploadTarget setHeaderDispositionKey(String dispositionKey) { - return mDelegate.setHeaderDispositionKey(dispositionKey); - } - - @Override public UploadTarget setHeaderDispositionFileKey(String dispositionFileKey) { - return mDelegate.setHeaderDispositionFileKey(dispositionFileKey); - } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/Uploader.java b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/Uploader.java index a8b5b607..dac6b56d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/Uploader.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/uploader/Uploader.java @@ -69,7 +69,7 @@ class Uploader extends AbsFileer { } - @Override protected int getNewTaskThreadNum() { + @Override protected int setNewTaskThreadNum() { return 1; } diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java b/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java index 877223ea..3075d1d4 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java @@ -34,7 +34,7 @@ import java.util.Map; class DBConfig { static Map mapping = new HashMap<>(); static String DB_NAME; - static int VERSION = 24; + static int VERSION = 25; static { if (TextUtils.isEmpty(DB_NAME)) { diff --git a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java index 965e3171..cd0aade9 100644 --- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java @@ -218,7 +218,7 @@ public class SingleTaskActivity extends BaseActivity { //.addHeader("Cookie", "BAIDUID=648E5FF020CC69E8DD6F492D1068AAA9:FG=1; BIDUPSID=648E5FF020CC69E8DD6F492D1068AAA9; PSTM=1519099573; BD_UPN=12314753; locale=zh; BDSVRTM=0") .setRequestMode(RequestEnum.GET) .setFilePath(Environment.getExternalStorageDirectory().getPath() + "/ggsg1.apk") - //.resetState() + .resetState() .start(); //.add(); } From 008228f5c2d5ad929b099fca260d0afec592c830 Mon Sep 17 00:00:00 2001 From: laoyuyu <511455842@qq.com> Date: Wed, 21 Mar 2018 20:17:26 +0800 Subject: [PATCH 10/22] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ifdaa00031d5bba66d318c083effad13dc11aca11 --- .../arialyy/aria/core/common/TaskRecord.java | 32 +++++++++++++++++++ .../aria/core/upload/BaseNormalTarget.java | 5 ++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java diff --git a/Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java b/Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java new file mode 100644 index 00000000..b385f1b8 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/common/TaskRecord.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.arialyy.aria.core.common; + +import com.arialyy.aria.orm.DbEntity; + +/** + * Created by laoyuyu on 2018/3/21. + * 任务上传或下载的记录 + */ +class TaskRecord extends DbEntity{ + /** + * 任务线程数 + */ + public int threadNum; + + //public int re + +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java index a7014c98..4fba7b68 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java @@ -17,9 +17,12 @@ package com.arialyy.aria.core.upload; import android.support.annotation.NonNull; import android.text.TextUtils; +import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.manager.TEManager; import com.arialyy.aria.core.queue.UploadTaskQueue; +import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.util.ALog; +import com.arialyy.aria.util.CommonUtil; import java.io.File; /** @@ -95,7 +98,7 @@ abstract class BaseNormalTarget return false; } if (file.isDirectory()) { - ALog.e(TAG, "上传失败,文件【" + filePath + "】不能死文件夹"); + ALog.e(TAG, "上传失败,文件【" + filePath + "】不能是文件夹"); return false; } return true; From 2db3579f467173059ee219c3c5479420223266b6 Mon Sep 17 00:00:00 2001 From: laoyuyu <511455842@qq.com> Date: Thu, 29 Mar 2018 21:26:39 +0800 Subject: [PATCH 11/22] 3.3.16 --- Aria/build.gradle | 5 ++++- README.md | 16 ++++++++-------- build.gradle | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Aria/build.gradle b/Aria/build.gradle index 4d7ee364..18b2d152 100644 --- a/Aria/build.gradle +++ b/Aria/build.gradle @@ -16,6 +16,9 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + lintOptions { + abortOnError false + } } dependencies { @@ -25,6 +28,6 @@ dependencies { compile project(':AriaAnnotations') compile 'com.arialyy.aria:aria-ftp-plug:1.0.3' -// compile project(':AriaFtpPlug') + // compile project(':AriaFtpPlug') } apply from: 'bintray-release.gradle' diff --git a/README.md b/README.md index 2973c78d..24e42665 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,10 @@ Aria有以下特点: [![Download](https://api.bintray.com/packages/arialyy/maven/AriaApi/images/download.svg)](https://bintray.com/arialyy/maven/AriaApi/_latestVersion) [![Download](https://api.bintray.com/packages/arialyy/maven/AriaCompiler/images/download.svg)](https://bintray.com/arialyy/maven/AriaCompiler/_latestVersion) ```java -compile 'com.arialyy.aria:aria-core:3.3.14' -annotationProcessor 'com.arialyy.aria:aria-compiler:3.3.14' +compile 'com.arialyy.aria:aria-core:3.3.16' +annotationProcessor 'com.arialyy.aria:aria-compiler:3.3.16' ``` -如果出现android support,请将 `compile 'com.arialyy.aria:aria-core:3.3.13'`替换为 +如果出现android support,请将 `compile 'com.arialyy.aria:aria-core:'`替换为 ``` compile('com.arialyy.aria:aria-core:'){ exclude group: 'com.android.support' @@ -103,11 +103,11 @@ protected void onCreate(Bundle savedInstanceState) { ### [更多说明,见WIKI](https://github.com/AriaLyy/Aria/wiki) ### 版本日志 - + v_3.3.14 - - 修复ftp上传和下载的兼容性问题 - - 如果url中的path有"//"将替换为"/" - - 修复http上传成功后,如果服务器没有设置返回码导致上传失败的问题 - - 上传实体UploadEntity增加responseStr字段,http上传完成后,在被`@Upload.onComplete`注解的方法中,可通过`task.getEntity().getResponseStr())`获取服务器返回的数据 + + v_3.3.16 + - 修复一个activity启动多次,无法进行回掉的bug https://github.com/AriaLyy/Aria/issues/200 + - 优化target代码结构,移除路径被占用的提示 + - 添加支持chunked模式的下载 + - 去掉上一个版本"//"的限制 [更多版本记录](https://github.com/AriaLyy/Aria/blob/master/DEV_LOG.md) diff --git a/build.gradle b/build.gradle index 2a1181a0..4aab319a 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ task clean(type: Delete) { ext { userOrg = 'arialyy' groupId = 'com.arialyy.aria' - publishVersion = '3.3.16_dev2' + publishVersion = '3.3.16' // publishVersion = '1.0.3' //FTP插件 repoName='maven' desc = 'android 下载框架' From 2ef9550d86f4ee739785b9d9a785cc75f5cc051d Mon Sep 17 00:00:00 2001 From: laoyuyu <511455842@qq.com> Date: Wed, 4 Apr 2018 21:25:23 +0800 Subject: [PATCH 12/22] =?UTF-8?q?ORM=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/arialyy/aria/core/AriaManager.java | 4 +- .../core/command/normal/CancelAllCmd.java | 47 -- .../aria/core/command/normal/StartCmd.java | 2 - .../arialyy/aria/core/common/AbsFileer.java | 10 +- .../arialyy/aria/core/common/TaskRecord.java | 2 +- .../core/delegate/HttpHeaderDelegate.java | 3 - .../aria/core/download/BaseGroupTarget.java | 4 - .../aria/core/download/BaseNormalTarget.java | 12 +- .../aria/core/download/DownloadEntity.java | 11 +- .../core/download/DownloadGroupEntity.java | 10 +- .../core/download/DownloadGroupTarget.java | 27 +- .../download/DownloadGroupTaskEntity.java | 30 +- .../download/DownloadGroupTaskWrapper.java | 44 ++ .../core/download/DownloadGroupWrapper.java | 41 + .../aria/core/download/DownloadReceiver.java | 72 +- .../aria/core/download/DownloadTarget.java | 1 - .../core/download/DownloadTaskEntity.java | 21 +- .../core/download/DownloadTaskWrapper.java | 44 ++ .../core/download/FtpDirDownloadTarget.java | 12 +- .../aria/core/download/FtpDownloadTarget.java | 1 - .../download/downloader/AbsGroupUtil.java | 37 +- .../downloader/FtpDirDownloadUtil.java | 6 +- .../downloader/HttpFileInfoThread.java | 5 +- .../com/arialyy/aria/core/inf/AbsEntity.java | 2 +- .../arialyy/aria/core/inf/AbsGroupEntity.java | 15 +- .../aria/core/inf/AbsNormalEntity.java | 2 - .../com/arialyy/aria/core/inf/AbsTarget.java | 32 +- .../arialyy/aria/core/inf/AbsTaskEntity.java | 15 +- .../com/arialyy/aria/core/inf/IEntity.java | 2 +- .../aria/core/inf/IUploadListener.java | 2 - .../aria/core/manager/DGTEntityFactory.java | 82 +- .../aria/core/manager/DTEntityFactory.java | 33 +- .../aria/core/manager/ITEntityFactory.java | 4 - .../arialyy/aria/core/manager/TEManager.java | 62 +- .../aria/core/manager/TaskManager.java | 86 --- .../aria/core/manager/UTEntityFactory.java | 32 +- .../core/queue/DownloadGroupTaskQueue.java | 2 +- .../aria/core/upload/BaseNormalTarget.java | 13 +- .../aria/core/upload/FtpUploadTarget.java | 6 +- .../aria/core/upload/UploadEntity.java | 9 +- .../aria/core/upload/UploadReceiver.java | 4 +- .../aria/core/upload/UploadTarget.java | 6 +- .../aria/core/upload/UploadTaskWrapper.java | 45 ++ .../com/arialyy/aria/orm/AbsDelegate.java | 162 ++++ .../UrlMapping.java => orm/AbsWrapper.java} | 17 +- .../com/arialyy/aria/orm/ActionPolicy.java | 62 ++ .../java/com/arialyy/aria/orm/DBConfig.java | 10 +- .../com/arialyy/aria/orm/DatabaseContext.java | 110 +++ .../java/com/arialyy/aria/orm/DbEntity.java | 76 +- .../java/com/arialyy/aria/orm/DbUtil.java | 249 ------ .../com/arialyy/aria/orm/DelegateCommon.java | 221 ++++++ .../com/arialyy/aria/orm/DelegateFind.java | 512 ++++++++++++ .../com/arialyy/aria/orm/DelegateManager.java | 69 ++ .../com/arialyy/aria/orm/DelegateUpdate.java | 186 +++++ .../com/arialyy/aria/orm/DelegateWrapper.java | 155 ++++ .../java/com/arialyy/aria/orm/NormalList.java | 32 - .../java/com/arialyy/aria/orm/SqlHelper.java | 730 +++--------------- .../java/com/arialyy/aria/orm/SqlUtil.java | 118 +-- .../{Foreign.java => annotation/Default.java} | 20 +- .../arialyy/aria/orm/annotation/Foreign.java | 50 ++ .../aria/orm/{ => annotation}/Ignore.java | 2 +- .../{OneToMany.java => annotation/Many.java} | 13 +- .../aria/orm/{ => annotation}/NoNull.java | 2 +- .../{OneToOne.java => annotation/One.java} | 15 +- .../aria/orm/{ => annotation}/Primary.java | 7 +- .../arialyy/aria/orm/annotation/Table.java | 30 + .../Wrapper.java} | 17 +- .../main/java/com/arialyy/aria/util/ALog.java | 2 +- .../java/com/arialyy/aria/util/CheckUtil.java | 28 +- .../com/arialyy/aria/util/CommonUtil.java | 166 ++-- .../java/com/arialyy/aria/util/ErrorHelp.java | 2 + .../download/group/DownloadGroupActivity.java | 4 +- .../group/FTPDirDownloadActivity.java | 2 +- .../multi_download/MultiDownloadActivity.java | 6 +- .../aria/core/upload/UploadTaskEntity.java | 27 +- 75 files changed, 2427 insertions(+), 1575 deletions(-) create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskWrapper.java create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupWrapper.java create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskWrapper.java delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/manager/TaskManager.java create mode 100644 Aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskWrapper.java create mode 100644 Aria/src/main/java/com/arialyy/aria/orm/AbsDelegate.java rename Aria/src/main/java/com/arialyy/aria/{core/UrlMapping.java => orm/AbsWrapper.java} (71%) create mode 100644 Aria/src/main/java/com/arialyy/aria/orm/ActionPolicy.java create mode 100644 Aria/src/main/java/com/arialyy/aria/orm/DatabaseContext.java delete mode 100644 Aria/src/main/java/com/arialyy/aria/orm/DbUtil.java create mode 100644 Aria/src/main/java/com/arialyy/aria/orm/DelegateCommon.java create mode 100644 Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java create mode 100644 Aria/src/main/java/com/arialyy/aria/orm/DelegateManager.java create mode 100644 Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java create mode 100644 Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java delete mode 100644 Aria/src/main/java/com/arialyy/aria/orm/NormalList.java rename Aria/src/main/java/com/arialyy/aria/orm/{Foreign.java => annotation/Default.java} (79%) create mode 100644 Aria/src/main/java/com/arialyy/aria/orm/annotation/Foreign.java rename Aria/src/main/java/com/arialyy/aria/orm/{ => annotation}/Ignore.java (95%) rename Aria/src/main/java/com/arialyy/aria/orm/{OneToMany.java => annotation/Many.java} (83%) rename Aria/src/main/java/com/arialyy/aria/orm/{ => annotation}/NoNull.java (95%) rename Aria/src/main/java/com/arialyy/aria/orm/{OneToOne.java => annotation/One.java} (82%) rename Aria/src/main/java/com/arialyy/aria/orm/{ => annotation}/Primary.java (87%) create mode 100644 Aria/src/main/java/com/arialyy/aria/orm/annotation/Table.java rename Aria/src/main/java/com/arialyy/aria/orm/{PrimaryAndForeign.java => annotation/Wrapper.java} (72%) diff --git a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java index c7c5968a..efaca07f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java @@ -41,7 +41,7 @@ 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.CommonUtil; import java.io.File; @@ -77,7 +77,7 @@ import org.xml.sax.SAXException; private Configuration.UploadConfig mUConfig; private AriaManager(Context context) { - DbUtil.init(context.getApplicationContext()); + DelegateWrapper.init(context.getApplicationContext()); APP = context.getApplicationContext(); regAppLifeCallback(context); initConfig(); diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java index 3f3efe11..cd0197fb 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java @@ -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 extends AbsNormalCmd { @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 allEntity = DbEntity.findAllData(DownloadGroupTaskEntity.class); - if (allEntity == null || allEntity.size() == 0) return; - for (DownloadGroupTaskEntity entity : allEntity) { - CommonUtil.delDownloadGroupTaskConfig(removeFile, entity); - } - } - - /** - * 处理上传的删除 - */ - private void handleUploadRemove() { - List allEntity = DbEntity.findAllData(UploadTaskEntity.class); - if (allEntity == null || allEntity.size() == 0) return; - for (UploadTaskEntity entity : allEntity) { - CommonUtil.delUploadTaskConfig(removeFile, entity); - } - } - - /** - * 处理下载的删除 - */ - private void handleDownloadRemove() { - List allEntity = DbEntity.findAllData(DownloadTaskEntity.class); - if (allEntity == null || allEntity.size() == 0) return; - for (DownloadTaskEntity entity : allEntity) { - CommonUtil.delDownloadTaskConfig(removeFile, entity); - } } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java index 82120c32..62824b10 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java @@ -77,7 +77,6 @@ class StartCmd extends AbsNormalCmd { || task.getState() == IEntity.STATE_OTHER || task.getState() == IEntity.STATE_POST_PRE || task.getState() == IEntity.STATE_COMPLETE) { - //startTask(); resumeTask(); } else { sendWaitState(); @@ -85,7 +84,6 @@ class StartCmd extends AbsNormalCmd { } } else { if (!task.isRunning()) { - //startTask(); resumeTask(); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java b/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java index cef4ea3b..c8868aeb 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java @@ -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; @@ -89,7 +91,6 @@ public abstract class AbsFileer extends AbsDownloadTarget { - private static final String TAG = "BaseGroupTarget"; /** * 组任务名 @@ -60,7 +58,6 @@ abstract class BaseGroupTarget public TARGET setGroupAlias(String alias) { if (TextUtils.isEmpty(alias)) return (TARGET) this; mEntity.setAlias(alias); - mEntity.update(); return (TARGET) this; } @@ -158,7 +155,6 @@ abstract class BaseGroupTarget } mEntity.setDirPath(dirPath); reChangeDirPath(dirPath); - mEntity.update(); } return true; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java index d26f86f2..141d5fb3 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java @@ -29,7 +29,6 @@ import java.io.File; abstract class BaseNormalTarget extends AbsDownloadTarget { - private static final String TAG = "BaseNormalTarget"; /** * 资源地址 */ @@ -42,9 +41,6 @@ abstract class BaseNormalTarget 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; if (mEntity != null) { @@ -110,7 +106,11 @@ abstract class BaseNormalTarget * @return {@code true}合法 */ @Override protected boolean checkEntity() { - return getTargetType() < GROUP_HTTP && checkUrl() && checkFilePath(); + boolean b = getTargetType() < GROUP_HTTP && checkUrl() && checkFilePath(); + if (b) { + mTaskEntity.save(mEntity); + } + return b; } /** @@ -149,7 +149,7 @@ abstract class BaseNormalTarget mEntity.setDownloadPath(filePath); mEntity.setFileName(newFile.getName()); mTaskEntity.key = filePath; - mTaskEntity.update(); + //mTaskEntity.update(); CommonUtil.renameDownloadConfig(oldFile.getName(), newFile.getName()); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java index 432015ac..89704153 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java @@ -21,8 +21,8 @@ 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.annotation.Foreign; +import com.arialyy.aria.orm.annotation.Primary; import com.arialyy.aria.util.CommonUtil; /** @@ -35,12 +35,7 @@ public class DownloadEntity extends AbsNormalEntity implements Parcelable { /** * 所属任务组 */ - @Foreign(table = DownloadGroupEntity.class, column = "groupName") private String groupName = ""; - - /** - * 下载任务实体的key - */ - @Foreign(table = DownloadTaskEntity.class, column = "key") private String taskKey = ""; + @Foreign(parent = DownloadGroupEntity.class, column = "groupName") private String groupName = ""; /** * 从服务器的返回信息中获取的文件md5信息,如果服务器没有返回,则不会设置该信息 diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java index c6697a5e..d90b05eb 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java @@ -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,8 +27,11 @@ import java.util.List; */ public class DownloadGroupEntity extends AbsGroupEntity { - @OneToMany(table = DownloadEntity.class, key = "groupName") private List subtask = - new ArrayList<>(); + //@OneToMany(table = DownloadEntity.class, key = "groupName") private List subtask = + // new ArrayList<>(); + + @Ignore + private List subtask; /** * 任务组下载文件的文件夹地址 diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java index 07ef9efb..1d2b0a8d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java @@ -24,16 +24,13 @@ import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.WeakHashMap; /** * Created by AriaL on 2017/6/29. * 下载任务组 */ public class DownloadGroupTarget extends BaseGroupTarget { - private final String TAG = "DownloadGroupTarget"; /** * 子任务下载地址, */ @@ -50,12 +47,8 @@ public class DownloadGroupTarget extends BaseGroupTarget { 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; + mTaskEntity = TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, mUrls); + mEntity = mTaskEntity.getEntity(); if (mEntity != null) { mDirPathTemp = mEntity.getDirPath(); @@ -66,11 +59,8 @@ public class DownloadGroupTarget extends BaseGroupTarget { 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); - } - mEntity = mTaskEntity.entity; + mTaskEntity = TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, mUrls); + mEntity = mTaskEntity.getEntity(); } /** @@ -88,7 +78,6 @@ public class DownloadGroupTarget extends BaseGroupTarget { } if (mEntity.getFileSize() <= 1 || mEntity.getFileSize() != fileSize) { mEntity.setFileSize(fileSize); - mEntity.update(); } return this; } @@ -137,7 +126,8 @@ public class DownloadGroupTarget extends BaseGroupTarget { entity.setGroupName(mGroupName); entity.setGroupChild(true); entity.setFileName(fileName); - entity.insert(); + // TODO: 2018/4/3 是否需要在这个插入? + //entity.insert(); list.add(entity); } return list; @@ -164,7 +154,6 @@ public class DownloadGroupTarget extends BaseGroupTarget { //文件夹路径通过后,并且该实体没有子任务,则创建子任务 if (mEntity.getSubTask() == null || mEntity.getSubTask().isEmpty()) { mEntity.setSubTasks(createSubTask()); - mTaskEntity.update(); } else { updateSingleSubFileName(); } @@ -230,7 +219,6 @@ public class DownloadGroupTarget extends BaseGroupTarget { } mEntity.setGroupName(CommonUtil.getMd5Code(mUrls)); - mEntity.update(); return true; } @@ -251,7 +239,8 @@ public class DownloadGroupTarget extends BaseGroupTarget { "UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'"); entity.setDownloadPath(newPath); entity.setFileName(newName); - entity.update(); + // TODO: 2018/4/3 是否需要在这个更新? + //entity.update(); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java index 72ecdc31..bd24c154 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java @@ -16,24 +16,42 @@ package com.arialyy.aria.core.download; import com.arialyy.aria.core.inf.AbsGroupTaskEntity; -import com.arialyy.aria.orm.OneToOne; +import com.arialyy.aria.orm.annotation.Foreign; +import com.arialyy.aria.orm.annotation.Ignore; +import com.arialyy.aria.orm.annotation.Primary; /** * Created by AriaL on 2017/7/1. */ public class DownloadGroupTaskEntity extends AbsGroupTaskEntity { - @OneToOne(table = DownloadGroupEntity.class, key = "groupName") public DownloadGroupEntity entity; + @Ignore private DownloadGroupEntity entity; + + @Primary @Foreign(parent = DownloadGroupEntity.class, column = "groupName") + private String key; @Override public DownloadGroupEntity getEntity() { return entity; } + public void setEntity(DownloadGroupEntity entity) { + this.entity = entity; + } + + @Override public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } - public void save(DownloadGroupEntity groupEntity){ - key = groupEntity.getKey(); - entity = groupEntity; - groupEntity.save(); + public void save(DownloadGroupEntity groupEntity) { + if (groupEntity != null) { + key = groupEntity.getKey(); + entity = groupEntity; + groupEntity.save(); + } save(); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskWrapper.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskWrapper.java new file mode 100644 index 00000000..c0f3fbfd --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskWrapper.java @@ -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; + +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 DownloadGroupTaskWrapper extends AbsWrapper { + + @One + public DownloadGroupEntity entity; + + @Many(parentColumn = "key", entityColumn = "groupName") + private List taskEntitys; + + public DownloadGroupTaskEntity taskEntity; + + @Override protected void handleConvert() { + taskEntity = (taskEntitys == null || taskEntitys.isEmpty()) ? null : taskEntitys.get(0); + if (taskEntity != null) { + taskEntity.setEntity(entity); + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupWrapper.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupWrapper.java new file mode 100644 index 00000000..e5a1e9d9 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupWrapper.java @@ -0,0 +1,41 @@ +/* + * 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.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 DownloadGroupWrapper extends AbsWrapper { + + @One + public DownloadGroupEntity groupEntity; + + @Many(parentColumn = "groupName", entityColumn = "groupName") + public List subEntity; + + @Override protected void handleConvert() { + if (subEntity != null && !subEntity.isEmpty()) { + groupEntity.setSubTasks(subEntity); + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java index b8101a36..b65f623f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java @@ -25,9 +25,11 @@ import com.arialyy.aria.core.common.ProxyHelper; 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.orm.DbEntity; +import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CommonUtil; import java.util.ArrayList; @@ -106,14 +108,14 @@ public class DownloadReceiver extends AbsReceiver { *
*/ @Deprecated public DownloadTarget load(@NonNull String url, boolean refreshInfo) { - url = CheckUtil.checkUrl(url); + CheckUtil.checkUrlInvalidThrow(url); return new DownloadTarget(url, targetName, refreshInfo); } /** * 加载下载地址,如果任务组的中的下载地址改变了,则任务从新的一个任务组 * - * @param urls 人刷谁 + * @param urls 任务组子任务下载地址列表 */ @Deprecated public DownloadGroupTarget load(List urls) { @@ -173,7 +175,7 @@ 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); } @@ -203,7 +205,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); } @@ -257,39 +259,55 @@ public class DownloadReceiver extends AbsReceiver { /** * 通过下载链接获取下载实体 + * + * @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 urls) { - CheckUtil.checkDownloadUrls(urls); - String hashCode = CommonUtil.getMd5Code(urls); - return DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", hashCode); + public DownloadGroupTaskEntity getGroupTask(List urls) { + if (urls == null || urls.isEmpty()) { + ALog.e(TAG, "获取任务组实体失败:任务组子任务下载地址列表为null"); + return null; + } + return TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, urls); } /** - * 通过任务组key,获取任务组实体 - * 如果是http,key为所有子任务下载地址拼接后取md5 - * 如果是ftp,key为ftp服务器的文件夹路径 + * 获取FTP文件夹下载任务实体 + * + * @param dirPath FTP文件夹本地保存路径 + * @return 返回对应的任务组实体;如果查找不到对应的数据或路径为null,返回null */ - public DownloadGroupTaskEntity getDownloadGroupTask(String key) { - return DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", key); + public DownloadGroupTaskEntity getFtpDirTask(String dirPath) { + if (TextUtils.isEmpty(dirPath)) { + ALog.e(TAG, "获取FTP文件夹实体失败:文件夹路径为null"); + return null; + } + return TEManager.getInstance().getTEntity(DownloadGroupTaskEntity.class, dirPath); } /** @@ -327,15 +345,25 @@ public class DownloadReceiver extends AbsReceiver { /** * 获取任务组列表 + * + * @return 如果没有任务组列表,则返回null */ public List getGroupTaskList() { - return DownloadEntity.findAllData(DownloadGroupEntity.class); + List wrappers = DbEntity.findRelationData(DownloadGroupWrapper.class); + if (wrappers == null || wrappers.isEmpty()) { + return null; + } + List entities = new ArrayList<>(); + for (DownloadGroupWrapper wrapper : wrappers) { + entities.add(wrapper.groupEntity); + } + return entities; } /** * 获取普通任务和任务组的任务列表 */ - public List getTotleTaskList() { + public List getTotalTaskList() { List list = new ArrayList<>(); List simpleTask = getTaskList(); List groupTask = getGroupTaskList(); diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java index 8f608f00..e7bd9b0f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java @@ -27,7 +27,6 @@ import java.util.Map; */ public class DownloadTarget extends BaseNormalTarget implements IHttpHeaderTarget { - private static final String TAG = "DownloadTarget"; private HttpHeaderDelegate mDelegate; DownloadTarget(DownloadEntity entity, String targetName) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java index 32e2dcb1..a089da27 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java @@ -16,17 +16,19 @@ package com.arialyy.aria.core.download; import com.arialyy.aria.core.inf.AbsNormalTaskEntity; -import com.arialyy.aria.orm.Ignore; -import com.arialyy.aria.orm.NoNull; -import com.arialyy.aria.orm.OneToOne; +import com.arialyy.aria.orm.annotation.Foreign; +import com.arialyy.aria.orm.annotation.Ignore; +import com.arialyy.aria.orm.annotation.NoNull; +import com.arialyy.aria.orm.annotation.Primary; /** * Created by lyy on 2017/1/23. - * 下载任务实体 + * 下载任务实体和下载实体为一对一关系,下载实体删除,任务实体自动删除 */ public class DownloadTaskEntity extends AbsNormalTaskEntity { - @OneToOne(table = DownloadEntity.class, key = "downloadPath") public DownloadEntity entity; + //@OneToOne(table = DownloadEntity.class, key = "downloadPath") public DownloadEntity entity; + @Ignore public DownloadEntity entity; /** * 任务的url @@ -48,6 +50,11 @@ public class DownloadTaskEntity extends AbsNormalTaskEntity { */ public boolean isGroupTask = false; + /** + * Task实体对应的key + */ + @Primary @Foreign(parent = DownloadEntity.class, column = "downloadPath") public String key = ""; + public DownloadTaskEntity() { } @@ -55,6 +62,10 @@ public class DownloadTaskEntity extends AbsNormalTaskEntity { return entity; } + @Override public String getKey() { + return key; + } + public void save(DownloadEntity entity) { this.entity = entity; if (entity != null) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskWrapper.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskWrapper.java new file mode 100644 index 00000000..a2fe9137 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskWrapper.java @@ -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; + +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 DownloadTaskWrapper extends AbsWrapper { + + @One + public DownloadEntity entity; + + @Many(parentColumn = "downloadPath", entityColumn = "key") + private List taskEntitys = null; + + public DownloadTaskEntity taskEntity; + + @Override public void handleConvert() { + taskEntity = (taskEntitys == null || taskEntitys.isEmpty()) ? null : taskEntitys.get(0); + if (taskEntity != null) { + taskEntity.entity = entity; + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java index b71c8b35..7b82e2fd 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java @@ -28,7 +28,6 @@ import com.arialyy.aria.util.ALog; */ public class FtpDirDownloadTarget extends BaseGroupTarget implements IFtpTarget { - private final String TAG = "FtpDirDownloadTarget"; private FtpDelegate mDelegate; FtpDirDownloadTarget(String url, String targetName) { @@ -39,11 +38,8 @@ public class FtpDirDownloadTarget extends BaseGroupTarget 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.requestType = AbsTaskEntity.D_FTP_DIR; - mEntity = mTaskEntity.entity; + mEntity = mTaskEntity.getEntity(); if (mEntity != null) { mDirPathTemp = mEntity.getDirPath(); } @@ -55,7 +51,11 @@ public class FtpDirDownloadTarget extends BaseGroupTarget } @Override protected boolean checkEntity() { - return getTargetType() == GROUP_FTP_DIR && checkDirPath() && checkUrl(); + boolean b = getTargetType() == GROUP_FTP_DIR && checkDirPath() && checkUrl(); + if (b) { + mTaskEntity.save(mEntity); + } + return b; } /** diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java index 35ce167c..3b1e5b54 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDownloadTarget.java @@ -27,7 +27,6 @@ import com.arialyy.aria.util.CommonUtil; */ public class FtpDownloadTarget extends BaseNormalTarget implements IFtpTarget { - private final String TAG = "FtpDownloadTarget"; private FtpDelegate mDelegate; FtpDownloadTarget(DownloadEntity entity, String targetName, boolean refreshInfo) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java index 52e56a5d..012e9fc3 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java @@ -106,7 +106,7 @@ public abstract class AbsGroupUtil implements IUtil { mGTEntity = groupEntity; mExePool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); List tasks = - DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mGTEntity.key); + DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mGTEntity.getKey()); if (tasks != null && !tasks.isEmpty()) { for (DownloadTaskEntity te : tasks) { te.removeFile = mGTEntity.removeFile; @@ -114,10 +114,10 @@ public abstract class AbsGroupUtil implements IUtil { mTasksMap.put(te.getEntity().getUrl(), te); } } - mGroupSize = mGTEntity.entity.getSubTask().size(); + mGroupSize = mGTEntity.getEntity().getSubTask().size(); mTotalLen = groupEntity.getEntity().getFileSize(); isNeedLoadFileSize = mTotalLen <= 1; - for (DownloadEntity entity : mGTEntity.entity.getSubTask()) { + for (DownloadEntity entity : mGTEntity.getEntity().getSubTask()) { File file = new File(entity.getDownloadPath()); if (entity.getState() == IEntity.STATE_COMPLETE && file.exists()) { mCompleteNum++; @@ -190,9 +190,10 @@ public abstract class AbsGroupUtil implements IUtil { * @param url 子任务下载地址 */ public void cancelSubTask(String url) { - List urls = mGTEntity.entity.getUrls(); + List urls = mGTEntity.getEntity().getUrls(); if (urls != null && !urls.isEmpty() && urls.contains(url)) { urls.remove(url); + // TODO: 2018/4/4 有问题 DownloadTaskEntity det = DbEntity.findFirst(DownloadTaskEntity.class, "url=? and isGroupTask='true'", url); if (det != null) { @@ -273,7 +274,7 @@ public abstract class AbsGroupUtil implements IUtil { dt.cancel(); } } - delDownloadInfo(); + CommonUtil.delDownloadGroupTaskConfig(mGTEntity.removeFile, mGTEntity.getEntity()); mGTEntity.deleteData(); } @@ -281,30 +282,6 @@ public abstract class AbsGroupUtil implements IUtil { } - /** - * 删除所有子任务的下载信息 - */ - private void delDownloadInfo() { - List 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(); @@ -418,7 +395,7 @@ public abstract class AbsGroupUtil implements IUtil { taskEntity.headers = mGTEntity.headers; taskEntity.requestEnum = mGTEntity.requestEnum; taskEntity.removeFile = mGTEntity.removeFile; - taskEntity.groupName = mGTEntity.key; + taskEntity.groupName = mGTEntity.getKey(); taskEntity.isGroupTask = true; taskEntity.requestType = mGTEntity.requestType; taskEntity.key = entity.getDownloadPath(); diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java index 719785c2..f2c9665d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java @@ -44,12 +44,12 @@ public class FtpDirDownloadUtil extends AbsGroupUtil { new FtpDirInfoThread(mGTEntity, new OnFileInfoCallback() { @Override public void onComplete(String url, CompleteInfo info) { if (info.code >= 200 && info.code < 300) { - for (DownloadEntity entity : mGTEntity.entity.getSubTask()) { + for (DownloadEntity entity : mGTEntity.getEntity().getSubTask()) { mExeMap.put(entity.getUrl(), createChildDownloadTask(entity)); } - mActualTaskNum = mGTEntity.entity.getSubTask().size(); + mActualTaskNum = mGTEntity.getEntity().getSubTask().size(); mGroupSize = mActualTaskNum; - mTotalLen = mGTEntity.entity.getFileSize(); + mTotalLen = mGTEntity.getEntity().getFileSize(); startDownload(); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java index 9e914437..8e385e82 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java @@ -160,7 +160,10 @@ class HttpFileInfoThread implements Runnable { } return; } - newUrl = CheckUtil.checkUrl(newUrl); + if (!CheckUtil.checkUrl(newUrl)) { + failDownload("下载失败,重定向url错误", false); + return; + } String cookies = conn.getHeaderField("Set-Cookie"); conn = (HttpURLConnection) new URL(newUrl).openConnection(); conn = ConnectionHelp.setConnectParam(mTaskEntity, conn); diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java index cfb731bc..aa297862 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java @@ -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. diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java index 132b78f7..d8250ab7 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java @@ -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 + * 组名,组名为任务地址相加的url的Md5 */ - @Primary @Foreign(table = DownloadGroupTaskEntity.class, column = "key") protected String - groupName = ""; + @Primary protected String groupName = ""; /** * 任务组别名 */ private String alias = ""; - /** - * 子任务链接组 - */ - @NormalList(clazz = String.class) private List urls = new ArrayList<>(); + private List urls = new ArrayList<>(); public List getUrls() { return urls; diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java index 5f03f29a..c6391ae2 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java @@ -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. diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java index 742f4af6..eac0d191 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java @@ -34,17 +34,25 @@ import java.util.List; */ public abstract class AbsTarget implements ITarget { + protected String TAG = ""; protected ENTITY mEntity; protected TASK_ENTITY mTaskEntity; protected String mTargetName; + protected AbsTarget() { + TAG = CommonUtil.getClassName(this); + } + /** - * 重置下载状态,将任务状态设置为未开始状态 + * 重置状态,将任务状态设置为未开始状态 */ public TARGET resetState() { - mTaskEntity.getEntity().setState(IEntity.STATE_WAIT); - mTaskEntity.refreshInfo = true; - mTaskEntity.update(); + if (checkEntity()) { + mTaskEntity.getEntity().setState(IEntity.STATE_WAIT); + mTaskEntity.refreshInfo = true; + } else { + ALog.e(TAG, "重置状态失败"); + } return (TARGET) this; } @@ -96,10 +104,16 @@ public abstract class AbsTarget extends DbEntity { */ public static final int U_FTP = 0xA2; - /** - * Task实体对应的key - */ - @Primary public String key = ""; - /** * 账号和密码 */ @@ -144,12 +138,7 @@ public abstract class AbsTaskEntity 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) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/IEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/IEntity.java index 156a01ce..8ad7c7d1 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/IEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/IEntity.java @@ -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. diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/IUploadListener.java b/Aria/src/main/java/com/arialyy/aria/core/inf/IUploadListener.java index 3387c49d..e6196375 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/IUploadListener.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/IUploadListener.java @@ -15,8 +15,6 @@ */ package com.arialyy.aria.core.inf; -import com.arialyy.aria.core.inf.IEventListener; - /** * Created by lyy on 2017/2/9. * 上传监听 diff --git a/Aria/src/main/java/com/arialyy/aria/core/manager/DGTEntityFactory.java b/Aria/src/main/java/com/arialyy/aria/core/manager/DGTEntityFactory.java index f68d7bad..af0ebce2 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/manager/DGTEntityFactory.java +++ b/Aria/src/main/java/com/arialyy/aria/core/manager/DGTEntityFactory.java @@ -18,6 +18,8 @@ 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.core.download.DownloadGroupTaskWrapper; +import com.arialyy.aria.core.download.DownloadGroupWrapper; import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.util.CommonUtil; import java.util.List; @@ -46,36 +48,56 @@ class DGTEntityFactory implements ITEntityFactory wrapper = + DbEntity.findRelationData(DownloadGroupTaskWrapper.class, "DownloadGroupTaskWrapper.key=?", + entity.getGroupName()); + DownloadGroupTaskEntity dgTaskEntity; + + if (wrapper != null && !wrapper.isEmpty()) { + dgTaskEntity = wrapper.get(0).taskEntity; + if (dgTaskEntity == null) { + dgTaskEntity = new DownloadGroupTaskEntity(); + dgTaskEntity.setEntity(entity); + } else if (dgTaskEntity.getEntity() == null || TextUtils.isEmpty( + dgTaskEntity.getEntity().getKey())) { + dgTaskEntity.setEntity(entity); + } + } else { dgTaskEntity = new DownloadGroupTaskEntity(); - dgTaskEntity.save(entity); - } - if (dgTaskEntity.entity == null || TextUtils.isEmpty(dgTaskEntity.entity.getKey())) { - dgTaskEntity.save(entity); + dgTaskEntity.setEntity(entity); } + return dgTaskEntity; } /** - * 对于任务组,不能使用这个,可用于FTP文件夹下载 + * 对于任务组,不能使用这个,该方法只用于FTP文件夹下载 * - * @deprecated {@link #create(String, List)} + * @deprecated 任务组使用:{@link #create(String, List)} */ @Override @Deprecated public DownloadGroupTaskEntity create(String key) { - DownloadGroupTaskEntity dgTaskEntity = - DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", key); - if (dgTaskEntity == null) { + List wrapper = + DbEntity.findRelationData(DownloadGroupTaskWrapper.class, "DownloadGroupTaskWrapper.key=?", + key); + DownloadGroupTaskEntity dgTaskEntity; + if (wrapper != null && !wrapper.isEmpty()) { + dgTaskEntity = wrapper.get(0).taskEntity; + if (dgTaskEntity == null) { + dgTaskEntity = new DownloadGroupTaskEntity(); + dgTaskEntity.setEntity(getDownloadGroupEntity(key, null)); + } else if (dgTaskEntity.getEntity() == null || TextUtils.isEmpty( + dgTaskEntity.getEntity().getKey())) { + dgTaskEntity.setEntity(getDownloadGroupEntity(key, null)); + } + dgTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(key); + return dgTaskEntity; + } else { dgTaskEntity = new DownloadGroupTaskEntity(); - dgTaskEntity.save(getDownloadGroupEntity(key, null)); + dgTaskEntity.setEntity(getDownloadGroupEntity(key, null)); + dgTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(key); + return dgTaskEntity; } - 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 urls) { @@ -86,13 +108,21 @@ class DGTEntityFactory implements ITEntityFactory urls) { - DownloadGroupEntity entity = - DbEntity.findFirst(DownloadGroupEntity.class, "groupName=?", groupName); - if (entity == null) { - entity = new DownloadGroupEntity(); - entity.setGroupName(groupName); - entity.setUrls(urls); + + List wrapper = + DbEntity.findRelationData(DownloadGroupWrapper.class, "DownloadGroupEntity.groupName=?", + groupName); + DownloadGroupEntity groupEntity; + if (wrapper != null && !wrapper.isEmpty()) { + groupEntity = wrapper.get(0).groupEntity; + if (groupEntity == null) { + groupEntity = new DownloadGroupEntity(); + } + } else { + groupEntity = new DownloadGroupEntity(); } - return entity; + groupEntity.setGroupName(groupName); + groupEntity.setUrls(urls); + return groupEntity; } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/manager/DTEntityFactory.java b/Aria/src/main/java/com/arialyy/aria/core/manager/DTEntityFactory.java index 437b4171..6ec6eb63 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/manager/DTEntityFactory.java +++ b/Aria/src/main/java/com/arialyy/aria/core/manager/DTEntityFactory.java @@ -18,9 +18,11 @@ 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.DownloadTaskWrapper; import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.orm.DbEntity; import java.io.File; +import java.util.List; /** * Created by Aria.Lao on 2017/11/1. @@ -45,19 +47,26 @@ class DTEntityFactory implements ITEntityFactory wrapper = DbEntity.findRelationData(DownloadTaskWrapper.class, + "DownloadTaskEntity.key=? and DownloadTaskEntity.isGroupTask='false' and DownloadTaskEntity.url=?", + entity.getDownloadPath(), entity.getUrl()); + + if (wrapper != null && !wrapper.isEmpty()) { + DownloadTaskEntity taskEntity = wrapper.get(0).taskEntity; + if (taskEntity == null) { + taskEntity = new DownloadTaskEntity(); + taskEntity.entity = entity; + } else if (taskEntity.entity == null || TextUtils.isEmpty(taskEntity.entity.getUrl())) { + taskEntity.entity = entity; + } + + return taskEntity; + } else { + DownloadTaskEntity taskEntity = new DownloadTaskEntity(); + taskEntity.entity = entity; + return taskEntity; } - return taskEntity; } /** diff --git a/Aria/src/main/java/com/arialyy/aria/core/manager/ITEntityFactory.java b/Aria/src/main/java/com/arialyy/aria/core/manager/ITEntityFactory.java index d92f7f2c..d5d2b97d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/manager/ITEntityFactory.java +++ b/Aria/src/main/java/com/arialyy/aria/core/manager/ITEntityFactory.java @@ -22,10 +22,6 @@ import com.arialyy.aria.core.inf.AbsTaskEntity; * Created by Aria.Lao on 2017/11/1. */ interface ITEntityFactory> { - /** - * 通过信息实体创建任务实体 - */ - TASK_ENTITY create(ENTITY entity); /** * 通过key创建任务,只适应于单任务 diff --git a/Aria/src/main/java/com/arialyy/aria/core/manager/TEManager.java b/Aria/src/main/java/com/arialyy/aria/core/manager/TEManager.java index 56018a88..3ed9f3c1 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/manager/TEManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/manager/TEManager.java @@ -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"; @@ -102,31 +101,6 @@ public class TEManager { } } - /** - * 通过实体创建任务 - * - * @return 如果任务实体创建失败,返回null - */ - public TE createTEntity(Class clazz, AbsEntity absEntity) { - final Lock lock = this.lock; - lock.lock(); - try { - AbsTaskEntity tEntity = cache.get(convertKey(absEntity.getKey())); - if (tEntity == null || tEntity.getClass() != clazz) { - ITEntityFactory factory = chooseFactory(clazz); - if (factory == null) { - ALog.e(TAG, "任务实体创建失败"); - return null; - } - tEntity = factory.create(absEntity); - cache.put(convertKey(absEntity.getKey()), tEntity); - } - return (TE) tEntity; - } finally { - lock.unlock(); - } - } - private IGTEntityFactory chooseGroupFactory(Class clazz) { if (clazz == DownloadGroupTaskEntity.class) { return DGTEntityFactory.getInstance(); @@ -146,7 +120,9 @@ public class TEManager { } /** - * 从任务实体管理器中获取任务实体 + * 从缓存中获取任务实体,如果任务实体不存在,则创建任务实体 + * + * @return 创建失败,返回null */ public TE getTEntity(Class clazz, String key) { final Lock lock = this.lock; @@ -154,7 +130,33 @@ public class TEManager { try { AbsTaskEntity tEntity = cache.get(convertKey(key)); if (tEntity == null) { - return null; + return createTEntity(clazz, key); + } else { + return (TE) tEntity; + } + } finally { + lock.unlock(); + } + } + + /** + * 从缓存中获取HTTP任务组的任务实体,如果任务实体不存在,则创建任务实体 + * + * @param urls HTTP任务组的子任务下载地址列表 + * @return 地址列表为null或创建实体失败,返回null + */ + public TE getGTEntity(Class clazz, List 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 +191,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(); } diff --git a/Aria/src/main/java/com/arialyy/aria/core/manager/TaskManager.java b/Aria/src/main/java/com/arialyy/aria/core/manager/TaskManager.java deleted file mode 100644 index e0f17a0b..00000000 --- a/Aria/src/main/java/com/arialyy/aria/core/manager/TaskManager.java +++ /dev/null @@ -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 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 boolean addTask(String key, Class 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> iter = map.entrySet().iterator(); iter.hasNext(); ) { - Map.Entry 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)); - } -} diff --git a/Aria/src/main/java/com/arialyy/aria/core/manager/UTEntityFactory.java b/Aria/src/main/java/com/arialyy/aria/core/manager/UTEntityFactory.java index 629daa5d..fa2e8a60 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/manager/UTEntityFactory.java +++ b/Aria/src/main/java/com/arialyy/aria/core/manager/UTEntityFactory.java @@ -15,10 +15,13 @@ */ 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.UploadTaskWrapper; import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.util.Regular; +import java.util.List; import java.util.regex.Pattern; /** @@ -41,17 +44,26 @@ class UTEntityFactory implements ITEntityFactory return INSTANCE; } - @Override public UploadTaskEntity create(UploadEntity entity) { - UploadTaskEntity uTaskEntity = - DbEntity.findFirst(UploadTaskEntity.class, "key=?", entity.getFilePath()); - if (uTaskEntity == null) { - uTaskEntity = new UploadTaskEntity(); - uTaskEntity.entity = entity; - } - if (uTaskEntity.entity == null) { + private UploadTaskEntity create(UploadEntity entity) { + List wrapper = + DbEntity.findRelationData(UploadTaskWrapper.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; + } else if (uTaskEntity.entity == null || TextUtils.isEmpty( + uTaskEntity.entity.getFilePath())) { + uTaskEntity.entity = entity; + } + return uTaskEntity; + } else { + UploadTaskEntity uTaskEntity = new UploadTaskEntity(); uTaskEntity.entity = entity; + return uTaskEntity; } - return uTaskEntity; } @Override public UploadTaskEntity create(String key) { @@ -67,14 +79,12 @@ class UTEntityFactory implements ITEntityFactory 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; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadGroupTaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadGroupTaskQueue.java index ad4b7c7d..421df17a 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadGroupTaskQueue.java +++ b/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadGroupTaskQueue.java @@ -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, "任务已存在"); diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java index 4fba7b68..5a747bae 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java @@ -17,12 +17,9 @@ package com.arialyy.aria.core.upload; import android.support.annotation.NonNull; import android.text.TextUtils; -import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.manager.TEManager; import com.arialyy.aria.core.queue.UploadTaskQueue; -import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.util.ALog; -import com.arialyy.aria.util.CommonUtil; import java.io.File; /** @@ -30,13 +27,9 @@ import java.io.File; */ abstract class BaseNormalTarget extends AbsUploadTarget { - private static final String TAG = "BaseNormalTarget"; protected void initTarget(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()); @@ -74,7 +67,11 @@ abstract class BaseNormalTarget } @Override protected boolean checkEntity() { - return checkUrl() && checkFilePath(); + boolean b = checkUrl() && checkFilePath(); + if (b) { + mTaskEntity.save(mEntity); + } + return b; } /** diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java index 34922b45..8c48e213 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java @@ -30,7 +30,6 @@ import com.arialyy.aria.util.CommonUtil; */ public class FtpUploadTarget extends BaseNormalTarget implements IFtpTarget { - private final String TAG = "FtpUploadTarget"; private FtpDelegate mDelegate; FtpUploadTarget(String filePath, String targetName) { @@ -51,14 +50,15 @@ public class FtpUploadTarget extends BaseNormalTarget */ @Override public FtpUploadTarget setUploadUrl(@NonNull String uploadUrl) { - uploadUrl = CheckUtil.checkUrl(uploadUrl); + if (!CheckUtil.checkUrl(uploadUrl)) { + return this; + } if (!uploadUrl.endsWith("/")) { uploadUrl += "/"; } mTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(uploadUrl); if (mEntity.getUrl().equals(uploadUrl)) return this; mEntity.setUrl(uploadUrl); - mEntity.update(); return this; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadEntity.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadEntity.java index 7c273459..9db2c3fa 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadEntity.java @@ -19,15 +19,18 @@ 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.Foreign; +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 @Foreign(parent = UploadTaskEntity.class, column = "key") private String filePath; /** * 上传完成后服务器返回的数据 diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java index 3d9b6040..134d1b23 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java @@ -20,9 +20,7 @@ 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.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; @@ -92,7 +90,7 @@ public class UploadReceiver extends AbsReceiver { @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 keys = am.getReceiver().keySet(); diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java index a7b4a042..ba4c3457 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java @@ -29,7 +29,6 @@ import java.util.Map; */ public class UploadTarget extends BaseNormalTarget implements IHttpHeaderTarget { - private static final String TAG = "UploadTarget"; private HttpHeaderDelegate mDelegate; UploadTarget(String filePath, String targetName) { @@ -47,12 +46,13 @@ public class UploadTarget extends BaseNormalTarget } @Override public UploadTarget setUploadUrl(@NonNull String uploadUrl) { - uploadUrl = CheckUtil.checkUrl(uploadUrl); + if (!CheckUtil.checkUrl(uploadUrl)){ + return this; + } if (mEntity.getUrl().equals(uploadUrl)) { return this; } mEntity.setUrl(uploadUrl); - mEntity.update(); return this; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskWrapper.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskWrapper.java new file mode 100644 index 00000000..3eea9148 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskWrapper.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.arialyy.aria.core.upload; + +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 UploadTaskWrapper extends AbsWrapper { + + @One + public UploadEntity entity; + + @Many(parentColumn = "filePath", entityColumn = "key") + private List 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.entity = entity; + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/orm/AbsDelegate.java b/Aria/src/main/java/com/arialyy/aria/orm/AbsDelegate.java new file mode 100644 index 00000000..e3a1ae64 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/orm/AbsDelegate.java @@ -0,0 +1,162 @@ +/* + * 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 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 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} + * + * @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的参数字段"); + return false; + } + } + + /** + * 检查map参数是否合法,map只能是{@code Map} + * + * @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的参数字段"); + return false; + } + } + + /** + * 为了防止特殊字符串导致存储失败,需要使用URL编码保存的字符串 + * + * @param value 需要保存的内容 + * @return 转换后的内容 + */ + String convertValue(String value) { + if (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; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/UrlMapping.java b/Aria/src/main/java/com/arialyy/aria/orm/AbsWrapper.java similarity index 71% rename from Aria/src/main/java/com/arialyy/aria/core/UrlMapping.java rename to Aria/src/main/java/com/arialyy/aria/orm/AbsWrapper.java index 41098241..49f4eca1 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/UrlMapping.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/AbsWrapper.java @@ -13,22 +13,15 @@ * 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; +package com.arialyy.aria.orm; /** - * Created by lyy on 2017/10/17. - * Url 映射表 + * Created by laoyuyu on 2018/3/30. */ -public class UrlMapping extends DbEntity { - /** - * 各实体对应的key - */ - public String key; +public abstract class AbsWrapper { /** - * 链接 + * 处理转换 */ - public String url; + protected abstract void handleConvert(); } diff --git a/Aria/src/main/java/com/arialyy/aria/orm/ActionPolicy.java b/Aria/src/main/java/com/arialyy/aria/orm/ActionPolicy.java new file mode 100644 index 00000000..614a35dc --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/orm/ActionPolicy.java @@ -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 + * {@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; + } + +} diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java b/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java index 3075d1d4..84113515 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java @@ -17,7 +17,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; @@ -34,7 +33,7 @@ import java.util.Map; class DBConfig { static Map mapping = new HashMap<>(); static String DB_NAME; - static int VERSION = 25; + static int VERSION = 31; static { if (TextUtils.isEmpty(DB_NAME)) { @@ -46,13 +45,12 @@ 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("DownloadEntity", DownloadEntity.class); + mapping.put("UploadEntity", UploadEntity.class); mapping.put("ErrorEntity", ErrorEntity.class); - //mapping.put("UrlMapping", UrlMapping.class); } } diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DatabaseContext.java b/Aria/src/main/java/com/arialyy/aria/orm/DatabaseContext.java new file mode 100644 index 00000000..e5aa3292 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/orm/DatabaseContext.java @@ -0,0 +1,110 @@ +/* + * 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 android.os.Environment; +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) { + //判断是否存在sd卡 + boolean sdExist = android.os.Environment.MEDIA_MOUNTED.equals( + android.os.Environment.getExternalStorageState()); + if (!sdExist) { + return null; + } else { + //获取sd卡路径 + File file = getBaseContext().getExternalFilesDir(null); + String dbDir; + if (file != null) { + dbDir = file.getPath() + "/"; + } else { + dbDir = Environment.getExternalStorageDirectory().getPath() + + "/Android/data/" + + getBaseContext().getPackageName() + + "/files/"; + } + + 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); + } +} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java b/Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java index 8b6ced31..56e09f3e 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java @@ -28,7 +28,7 @@ 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; @@ -36,15 +36,14 @@ public class DbEntity { } - ///** - // * 关键字模糊检索全文 - // * - // * @param column 需要查找的列 - // * @param mathSql 关键字语法,exsimple “white OR green”、“blue AND red”、“white NOT green” - // */ - //public static List searchData(Class clazz, String column, String mathSql) { - // return DbUtil.getInstance().searchData(clazz, column, mathSql); - //} + /** + * 查询关联数据 + * + * @param expression 查询条件 + */ + public static List findRelationData(Class clazz, String... expression) { + return DelegateWrapper.getInstance().findRelationData(clazz, expression); + } /** * 检查某个字段的值是否存在 @@ -53,21 +52,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 void clean(Class 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 +75,7 @@ public class DbEntity { * @return 没有数据返回null */ public static List findAllData(Class clazz) { - DbUtil util = DbUtil.getInstance(); + DelegateWrapper util = DelegateWrapper.getInstance(); return util.findAllData(clazz); } @@ -97,7 +96,7 @@ public class DbEntity { * @return 没有数据返回null */ public static List findDatas(Class clazz, String... expression) { - DbUtil util = DbUtil.getInstance(); + DelegateWrapper util = DelegateWrapper.getInstance(); return util.findData(clazz, expression); } @@ -110,7 +109,7 @@ public class DbEntity { * @return 没有数据返回null */ public static T findFirst(Class clazz, String... expression) { - DbUtil util = DbUtil.getInstance(); + DelegateWrapper util = DelegateWrapper.getInstance(); List datas = util.findData(clazz, expression); return datas == null ? null : datas.size() > 0 ? datas.get(0) : null; } @@ -119,14 +118,14 @@ public class DbEntity { * 获取所有行的rowid */ public int[] getRowIds() { - return DbUtil.getInstance().getRowId(getClass()); + return DelegateWrapper.getInstance().getRowId(getClass()); } /** * 获取rowid */ public int getRowId(@NonNull Object[] wheres, @NonNull Object[] values) { - return DbUtil.getInstance().getRowId(getClass(), wheres, values); + return DelegateWrapper.getInstance().getRowId(getClass(), wheres, values); } /** @@ -143,7 +142,7 @@ public class DbEntity { * */ public static void deleteData(Class clazz, String... expression) { - DbUtil util = DbUtil.getInstance(); + DelegateWrapper util = DelegateWrapper.getInstance(); util.delData(clazz, expression); } @@ -151,7 +150,7 @@ public class DbEntity { * 修改数据 */ public void update() { - DbUtil.getInstance().modifyData(this); + DelegateWrapper.getInstance().modifyData(this); } /** @@ -171,7 +170,7 @@ public class DbEntity { * 查找数据在表中是否存在 */ private boolean thisIsExist() { - DbUtil util = DbUtil.getInstance(); + DelegateWrapper util = DelegateWrapper.getInstance(); return util.isExist(getClass(), rowID); } @@ -179,45 +178,38 @@ public class DbEntity { * 插入数据 */ public void insert() { - DbUtil.getInstance().insertData(this); + DelegateWrapper.getInstance().insertData(this); updateRowID(); } - private T findFirst(Class clazz, @NonNull String[] wheres, - @NonNull String[] values) { - DbUtil util = DbUtil.getInstance(); - List list = util.findData(clazz, wheres, values); - return list == null ? null : list.get(0); - } - private void updateRowID() { try { List fields = CommonUtil.getAllFields(getClass()); - List where = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + List params = new ArrayList<>(); List values = new ArrayList<>(); for (Field field : fields) { field.setAccessible(true); - if (SqlUtil.ignoreField(field)) { + if (SqlUtil.isIgnore(field)) { continue; } - where.add(field.getName()); + sb.append(field.getName()).append("=? AND "); 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)); - } + if (type == List.class) { + values.add(SqlUtil.list2Str(this, field)); } else if (type == Map.class) { values.add(SqlUtil.map2Str((Map) 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()])); + + String temp = sb.toString(); + String p = temp.substring(0, temp.length() - 5); + + params.add(p); + params.addAll(values); + DbEntity entity = findFirst(getClass(), params.toArray(new String[params.size()])); if (entity != null) { rowID = entity.rowID; } diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DbUtil.java b/Aria/src/main/java/com/arialyy/aria/orm/DbUtil.java deleted file mode 100644 index 7e1bf8d9..00000000 --- a/Aria/src/main/java/com/arialyy/aria/orm/DbUtil.java +++ /dev/null @@ -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 List searchData(Class 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 void clean(Class 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 void delData(Class clazz, String... expression) { - CheckUtil.checkSqlExpression(expression); - checkDb(); - SqlHelper.delData(mDb, clazz, expression); - } - - /** - * 修改某行数据 - */ - synchronized void modifyData(DbEntity dbEntity) { - checkDb(); - SqlHelper.modifyData(mDb, dbEntity); - } - - /** - * 遍历所有数据 - */ - synchronized List findAllData(Class clazz) { - checkDb(); - return SqlHelper.findAllData(mDb, clazz); - } - - /** - * 条件查寻数据 - */ - synchronized List findData(Class clazz, String... expression) { - checkDb(); - return SqlHelper.findData(mDb, clazz, expression); - } - - /** - * 通过rowId判断数据是否存在 - */ - synchronized boolean isExist(Class 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 List findData(Class 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; - } -} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DelegateCommon.java b/Aria/src/main/java/com/arialyy/aria/orm/DelegateCommon.java new file mode 100644 index 00000000..c23fabf6 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/orm/DelegateCommon.java @@ -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(); + } + + /** + * 清空表数据 + */ + void clean(SQLiteDatabase db, Class 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 fields = CommonUtil.getAllFields(clazz); + if (fields != null && fields.size() > 0) { + //外键Map,在Sqlite3中foreign修饰的字段必须放在最后 + final List 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); + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java b/Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java new file mode 100644 index 00000000..98a5866d --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java @@ -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 + */ + List findRelationData(SQLiteDatabase db, Class 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 pColumn = SqlUtil.getAllNotIgnoreField(parentClazz); + List cColumn = SqlUtil.getAllNotIgnoreField(childClazz); + List pColumnAlias = new ArrayList<>(); + List 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 data = + (List) 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 List newInstanceEntity( + Class clazz, Class

parent, + Class child, + Cursor cursor, + List pColumn, List cColumn, + List pColumnAlias, List cColumnAlias) { + try { + String parentPrimary = ""; //父表主键别名 + for (Field f : pColumn) { + if (SqlUtil.isPrimary(f)) { + parentPrimary = PARENT_COLUMN_ALIAS.concat(f.getName()); + break; + } + } + + List wrappers = new ArrayList<>(); + Map tempParent = new WeakHashMap<>(); // 所有父表元素,key为父表主键的值 + Map> 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()); + } + tempChild.get(old).add(cEntity); + } + + List wFields = SqlUtil.getAllNotIgnoreField(clazz); + if (wFields != null && !wFields.isEmpty()) { + Set 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; + } + + /** + * 条件查寻数据 + */ + List findData(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] = "'" + convertValue(expression[i + 1]) + "'"; + } + sql = String.format(sql, params); + print(FIND_DATA, sql); + Cursor cursor = db.rawQuery(sql, null); + List data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; + closeCursor(cursor); + close(db); + return data; + } + + /** + * 查找表的所有数据 + */ + List findAllData(SQLiteDatabase db, Class 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 data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; + closeCursor(cursor); + close(db); + return data; + } + + /** + * 根据数据游标创建一个具体的对象 + */ + private List newInstanceEntity(Class clazz, Cursor cursor) { + List fields = CommonUtil.getAllFields(clazz); + List 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判断数据是否存在 + */ + boolean itemExist(SQLiteDatabase db, Class clazz, + int 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; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DelegateManager.java b/Aria/src/main/java/com/arialyy/aria/orm/DelegateManager.java new file mode 100644 index 00000000..802a8bc6 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/orm/DelegateManager.java @@ -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 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 getDelegate(Class 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; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java b/Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java new file mode 100644 index 00000000..d697f5f0 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java @@ -0,0 +1,186 @@ +/* + * 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.sqlite.SQLiteDatabase; +import android.text.TextUtils; +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.lang.reflect.Type; +import java.util.List; +import java.util.Map; + +/** + * Created by laoyuyu on 2018/3/22. + * 增加数据、更新数据 + */ +class DelegateUpdate extends AbsDelegate { + private DelegateUpdate() { + } + + /** + * 删除某条数据 + */ + void delData(SQLiteDatabase db, Class clazz, String... expression) { + db = checkDb(db); + CheckUtil.checkSqlExpression(expression); + + String sql = "DELETE 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(DEL_DATA, sql); + db.execSQL(sql); + close(db); + } + + /** + * 修改某行数据 + */ + void modifyData(SQLiteDatabase db, DbEntity dbEntity) { + db = checkDb(db); + Class clazz = dbEntity.getClass(); + List fields = CommonUtil.getAllFields(clazz); + DbEntity cacheEntity = mDataCache.get(getCacheKey(dbEntity)); + if (fields != null && fields.size() > 0) { + StringBuilder sql = new StringBuilder(); + StringBuilder prams = new StringBuilder(); + sql.append("UPDATE ").append(CommonUtil.getClassName(dbEntity)).append(" SET "); + int i = 0; + try { + for (Field field : fields) { + field.setAccessible(true); + if (isIgnore(dbEntity, field)) { + continue; + } + if (cacheEntity != null + && field.get(dbEntity) == field.get(cacheEntity) + && !field.getName().equals("state")) { //在LruCache中 state字段总是不能重新赋值... + continue; + } + + String value; + prams.append(i > 0 ? ", " : ""); + prams.append(field.getName()).append("='"); + Type type = field.getType(); + if (type == Map.class && checkMap(field)) { + value = SqlUtil.map2Str((Map) field.get(dbEntity)); + } else if (type == List.class && checkList(field)) { + value = SqlUtil.list2Str(dbEntity, field); + } else { + Object obj = field.get(dbEntity); + value = obj == null ? "" : convertValue(obj.toString()); + } + + prams.append(TextUtils.isEmpty(value) ? "" : value); + prams.append("'"); + i++; + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + if (!TextUtils.isEmpty(prams.toString())) { + sql.append(prams.toString()); + sql.append(" where rowid=").append(dbEntity.rowID); + print(MODIFY_DATA, sql.toString()); + db.execSQL(sql.toString()); + } + } + mDataCache.put(getCacheKey(dbEntity), dbEntity); + close(db); + } + + /** + * 插入数据 + */ + void insertData(SQLiteDatabase db, DbEntity dbEntity) { + db = checkDb(db); + Class clazz = dbEntity.getClass(); + List fields = CommonUtil.getAllFields(clazz); + if (fields != null && fields.size() > 0) { + StringBuilder sb = new StringBuilder(); + sb.append("INSERT INTO ").append(CommonUtil.getClassName(dbEntity)).append("("); + int i = 0; + try { + for (Field field : fields) { + field.setAccessible(true); + if (isIgnore(dbEntity, field)) { + continue; + } + sb.append(i > 0 ? ", " : ""); + sb.append(field.getName()); + i++; + } + sb.append(") VALUES ("); + i = 0; + for (Field field : fields) { + field.setAccessible(true); + if (isIgnore(dbEntity, field)) { + continue; + } + sb.append(i > 0 ? ", " : ""); + sb.append("'"); + Type type = field.getType(); + if (type == Map.class && checkMap(field)) { + sb.append(SqlUtil.map2Str((Map) field.get(dbEntity))); + } else if (type == List.class && checkList(field)) { + sb.append(SqlUtil.list2Str(dbEntity, field)); + } else { + Object obj = field.get(dbEntity); + if (obj != null) { + sb.append(convertValue(field.get(dbEntity).toString())); + } + } + sb.append("'"); + i++; + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + sb.append(")"); + print(INSERT_DATA, sb.toString()); + db.execSQL(sb.toString()); + } + close(db); + } + + /** + * {@code true}自动增长的主键和需要忽略的字段 + */ + private boolean isIgnore(Object obj, Field field) throws IllegalAccessException { + if (SqlUtil.isIgnore(field)) { + return true; + } + if (SqlUtil.isPrimary(field)) { //忽略自动增长的主键 + Primary p = field.getAnnotation(Primary.class); + if (p.autoincrement()) { + return true; + } + } + if (SqlUtil.isForeign(field)) { //忽略外键为null的字段 + Object value = field.get(obj); + if (value == null || (value instanceof String && TextUtils.isEmpty(String.valueOf(value)))) { + return true; + } + } + return false; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java b/Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java new file mode 100644 index 00000000..ca33e472 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java @@ -0,0 +1,155 @@ +/* + * 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.database.sqlite.SQLiteDatabase; +import java.util.List; + +/** + * Created by lyy on 2015/2/11. + * 数据库操作工具 + */ +public class DelegateWrapper { + private static final String TAG = "DelegateWrapper"; + private volatile static DelegateWrapper INSTANCE = null; + + private SQLiteDatabase mDb; + private DelegateManager mDManager; + + private DelegateWrapper() { + + } + + private DelegateWrapper(Context context) { + SqlHelper helper = SqlHelper.init(context.getApplicationContext()); + mDb = helper.getWritableDatabase(); + mDManager = DelegateManager.getInstance(); + } + + public static void init(Context context) { + synchronized (DelegateWrapper.class) { + if (INSTANCE == null) { + INSTANCE = new DelegateWrapper(context); + } + } + } + + static DelegateWrapper getInstance() { + if (INSTANCE == null) { + throw new NullPointerException("请在Application中调用init进行数据库工具注册注册"); + } + return INSTANCE; + } + + /** + * 查询关联表数据 + * + * @param expression 查询条件 + */ + List findRelationData(Class clazz, String... expression) { + return mDManager.getDelegate(DelegateFind.class).findRelationData(mDb, clazz, expression); + } + + /** + * 检查某个字段的值是否存在 + * + * @param expression 字段和值"url=xxx" + * @return {@code true}该字段的对应的value已存在 + */ + boolean checkDataExist(Class clazz, String... expression) { + return mDManager.getDelegate(DelegateCommon.class) + .checkDataExist(mDb, clazz, expression); + } + + /** + * 清空表数据 + */ + void clean(Class clazz) { + mDManager.getDelegate(DelegateCommon.class).clean(mDb, clazz); + } + + /** + * 执行sql语句 + */ + void exeSql(String sql) { + mDb.execSQL(sql); + } + + /** + * 删除某条数据 + */ + void delData(Class clazz, String... expression) { + mDManager.getDelegate(DelegateUpdate.class).delData(mDb, clazz, expression); + } + + /** + * 修改某行数据 + */ + void modifyData(DbEntity dbEntity) { + mDManager.getDelegate(DelegateUpdate.class).modifyData(mDb, dbEntity); + } + + /** + * 遍历所有数据 + */ + List findAllData(Class clazz) { + return mDManager.getDelegate(DelegateFind.class).findAllData(mDb, clazz); + } + + /** + * 条件查寻数据 + */ + List findData(Class clazz, String... expression) { + return mDManager.getDelegate(DelegateFind.class).findData(mDb, clazz, expression); + } + + /** + * 通过rowId判断数据是否存在 + */ + boolean isExist(Class clazz, int rowId) { + return mDManager.getDelegate(DelegateFind.class).itemExist(mDb, clazz, rowId); + } + + /** + * 插入数据 + */ + void insertData(DbEntity dbEntity) { + mDManager.getDelegate(DelegateUpdate.class).insertData(mDb, dbEntity); + } + + /** + * 查找某张表是否存在 + */ + boolean tableExists(Class clazz) { + return mDManager.getDelegate(DelegateCommon.class).tableExists(mDb, clazz); + } + + /** + * 获取所在行Id + */ + int[] getRowId(Class clazz) { + return mDManager.getDelegate(DelegateFind.class).getRowId(mDb, clazz); + } + + /** + * 获取行Id + */ + int getRowId(Class clazz, Object[] wheres, Object[] values) { + return mDManager.getDelegate(DelegateFind.class).getRowId(mDb, clazz, wheres, values); + } +} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/orm/NormalList.java b/Aria/src/main/java/com/arialyy/aria/orm/NormalList.java deleted file mode 100644 index 2d2ba512..00000000 --- a/Aria/src/main/java/com/arialyy/aria/orm/NormalList.java +++ /dev/null @@ -1,32 +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 java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Created by AriaL on 2017/7/4. - * 基本类型的List,只能用于常见的数据类型,如果是一对多的复杂数据结构,需要使用{@link OneToMany} - */ -@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface NormalList { - /** - * 数据类型 - */ - Class clazz(); -} diff --git a/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java b/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java index 72be07c5..5231d09a 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java @@ -20,21 +20,11 @@ import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; -import android.support.annotation.NonNull; -import android.support.v4.util.LruCache; import android.text.TextUtils; -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.lang.reflect.Field; -import java.lang.reflect.Type; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Date; import java.util.List; -import java.util.Map; import java.util.Set; /** @@ -43,31 +33,34 @@ import java.util.Set; */ final class SqlHelper extends SQLiteOpenHelper { private static final String TAG = "SqlHelper"; - private static final int CREATE_TABLE = 0; - private static final int TABLE_EXISTS = 1; - private static final int INSERT_DATA = 2; - private static final int MODIFY_DATA = 3; - private static final int FIND_DATA = 4; - private static final int FIND_ALL_DATA = 5; - private static final int DEL_DATA = 6; + /** + * 是否将数据库保存在Sd卡,{@code true} 是 + */ + private static final boolean SAVE_IN_SDCARD = false; + + static volatile SqlHelper INSTANCE = null; - private static volatile SqlHelper INSTANCE = null; - private static LruCache mDataCache = new LruCache<>(1024); - //private static Map mDataCache = new ConcurrentHashMap<>(); + private DelegateCommon mDelegate; static SqlHelper init(Context context) { if (INSTANCE == null) { - synchronized (AriaManager.LOCK) { - INSTANCE = new SqlHelper(context.getApplicationContext()); + synchronized (SqlHelper.class) { + DelegateCommon delegate = DelegateManager.getInstance().getDelegate(DelegateCommon.class); + INSTANCE = new SqlHelper(context.getApplicationContext(), delegate); SQLiteDatabase db = INSTANCE.getWritableDatabase(); - db = checkDb(db); + db = delegate.checkDb(db); + // SQLite在3.6.19版本中开始支持外键约束, + // 而在Android中 2.1以前的版本使用的SQLite版本是3.5.9, 在2.2版本中使用的是3.6.22. + // 但是为了兼容以前的程序,默认并没有启用该功能,如果要启用该功能 + // 需要使用如下语句: + db.execSQL("PRAGMA foreign_keys=ON;"); Set tables = DBConfig.mapping.keySet(); for (String tableName : tables) { Class clazz = null; clazz = DBConfig.mapping.get(tableName); - if (!tableExists(db, clazz)) { - createTable(db, clazz, null); + if (!delegate.tableExists(db, clazz)) { + delegate.createTable(db, clazz); } } } @@ -75,8 +68,10 @@ final class SqlHelper extends SQLiteOpenHelper { return INSTANCE; } - private SqlHelper(Context context) { - super(context, DBConfig.DB_NAME, null, DBConfig.VERSION); + private SqlHelper(Context context, DelegateCommon delegate) { + super(SAVE_IN_SDCARD ? new DatabaseContext(context) : context, DBConfig.DB_NAME, null, + DBConfig.VERSION); + mDelegate = delegate; } @Override public void onCreate(SQLiteDatabase db) { @@ -85,7 +80,11 @@ final class SqlHelper extends SQLiteOpenHelper { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if (oldVersion < newVersion) { - handleDbUpdate(db); + if (oldVersion < 31) { + handle314AriaUpdate(db); + } else { + handleDbUpdate(db); + } } } @@ -110,635 +109,98 @@ final class SqlHelper extends SQLiteOpenHelper { Set tables = DBConfig.mapping.keySet(); for (String tableName : tables) { Class clazz = DBConfig.mapping.get(tableName); - if (tableExists(db, clazz)) { + if (mDelegate.tableExists(db, clazz)) { String countColumnSql = "SELECT rowid FROM " + tableName; Cursor cursor = db.rawQuery(countColumnSql, null); int dbColumnNum = cursor.getColumnCount(); - int newEntityColumnNum = getEntityAttr(clazz); + List fields = SqlUtil.getAllNotIgnoreField(clazz); + int newEntityColumnNum = (fields == null || fields.isEmpty()) ? 0 : fields.size(); if (dbColumnNum != newEntityColumnNum) { - back(db, clazz); - } - } - } - } - - /** - * 备份 - */ - private void back(SQLiteDatabase db, Class clazz) { - db = checkDb(db); - String oldTableName = CommonUtil.getClassName(clazz); - //备份数据 - List list = findAllData(db, clazz); - //修改原来表名字 - String alertSql = "alter table " + oldTableName + " rename to " + oldTableName + "_temp"; - db.beginTransaction(); - db.execSQL(alertSql); - //创建一个原来新表 - createTable(db, clazz, null); - if (list != null && list.size() > 0) { - for (DbEntity entity : list) { - insertData(db, entity); - } - } - //删除原来的表 - String deleteSQL = "drop table IF EXISTS " + oldTableName + "_temp"; - db.execSQL(deleteSQL); - db.setTransactionSuccessful(); - db.endTransaction(); - close(db); - } - - /** - * 获取实体的字段数 - */ - private int getEntityAttr(Class clazz) { - int count = 1; - List fields = CommonUtil.getAllFields(clazz); - if (fields != null && fields.size() > 0) { - for (Field field : fields) { - field.setAccessible(true); - if (SqlUtil.ignoreField(field)) { - continue; - } - count++; - } - } - return count; - } - - ///** - // * 关键字模糊检索全文 - // * - // * @param column 需要查找的列 - // * @param mathSql 关键字语法,exsimple “white OR green”、“blue AND red”、“white NOT green” - // */ - //public static List searchData(SQLiteDatabase db, Class clazz, - // String column, String mathSql) { - // String sql = "SELECT * FROM " - // + CommonUtil.getClassName(clazz) - // + " WHERE " - // + column - // + " MATCH '" - // + mathSql - // + "'"; - // - // Cursor cursor = db.rawQuery(sql, null); - // List data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null; - // closeCursor(cursor); - // return data; - //} - - /** - * 检查某个字段的值是否存在 - * - * @param expression 字段和值"url=xxx" - * @return {@code true}该字段的对应的value已存在 - */ - static synchronized 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; - } - - /** - * 条件查寻数据 - */ - static synchronized List findData(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] = "'" + checkValue(expression[i + 1]) + "'"; - } - sql = String.format(sql, params); - print(FIND_DATA, sql); - Cursor cursor = db.rawQuery(sql, null); - List data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null; - closeCursor(cursor); - close(db); - return data; - } - - /** - * 条件查寻数据 - */ - static synchronized List findData(SQLiteDatabase db, String tableName, - String... expression) { - Class clazz = null; - try { - clazz = (Class) Class.forName(tableName); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - return findData(db, clazz, expression); - } - - /** - * 条件查寻数据 - */ - @Deprecated static synchronized List findData(SQLiteDatabase db, - Class clazz, @NonNull String[] wheres, @NonNull String[] values) { - db = checkDb(db); - if (wheres.length <= 0 || values.length <= 0) { - ALog.e(TAG, "请输入查询条件"); - return null; - } else if (wheres.length != values.length) { - ALog.e(TAG, "groupName 和 vaule 长度不相等"); - return null; - } - 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(checkValue(values[i])).append("'"); - sb.append(i >= wheres.length - 1 ? "" : " AND "); - i++; - } - print(FIND_DATA, sb.toString()); - Cursor cursor = db.rawQuery(sb.toString(), null); - List data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null; - closeCursor(cursor); - close(db); - return data; - } - - private static String checkValue(String value) { - if (value.contains("'")) { - return URLEncoder.encode(value); - } - return value; - } - - /** - * 查找表的所有数据 - */ - static synchronized List findAllData(SQLiteDatabase db, Class 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 data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null; - closeCursor(cursor); - close(db); - return data; - } - - /** - * 删除某条数据 - */ - static synchronized void delData(SQLiteDatabase db, Class clazz, - String... expression) { - db = checkDb(db); - CheckUtil.checkSqlExpression(expression); - - //List fields = CommonUtil.getAllFields(clazz); - //for (Field field : fields) { - // if (SqlUtil.isOneToOne(field)) { - // OneToOne oto = field.getAnnotation(OneToOne.class); - // delData(db, oto.table(), oto.key() + "=?", ); - // } else if (SqlUtil.isOneToMany(field)) { - // OneToMany otm = field.getAnnotation(OneToMany.class); - // delData(db, otm.table(), otm.key() + "=?", otm.key()); - // } - //} - - String sql = "DELETE 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); - SqlHelper.print(DEL_DATA, sql); - db.execSQL(sql); - close(db); - } - - /** - * 修改某行数据 - */ - static synchronized void modifyData(SQLiteDatabase db, DbEntity dbEntity) { - db = checkDb(db); - Class clazz = dbEntity.getClass(); - List fields = CommonUtil.getAllFields(clazz); - DbEntity cacheEntity = mDataCache.get(getCacheKey(dbEntity)); - if (fields != null && fields.size() > 0) { - StringBuilder sql = new StringBuilder(); - StringBuilder prams = new StringBuilder(); - sql.append("UPDATE ").append(CommonUtil.getClassName(dbEntity)).append(" SET "); - int i = 0; - for (Field field : fields) { - field.setAccessible(true); - if (SqlUtil.ignoreField(field)) { - continue; - } - try { - if (cacheEntity != null - && field.get(dbEntity) == field.get(cacheEntity) - && !field.getName().equals("state")) { //在LruCache中 state字段总是不能重新赋值... - //if (dbEntity instanceof DownloadEntity && field.getName().equals("state")) { - // Log.i(TAG, "cacheState => " - // + ((DownloadEntity) cacheEntity).getState() - // + ", newState => " - // + ((DownloadEntity) dbEntity).getState()); - //} - continue; - } - - //sb.append(i > 0 ? ", " : ""); - //sb.append(field.getName()).append("='"); - String value; - prams.append(i > 0 ? ", " : ""); - prams.append(field.getName()).append("='"); - Type type = field.getType(); - if (type == Map.class) { - value = SqlUtil.map2Str((Map) field.get(dbEntity)); - } else if (type == List.class) { - if (SqlUtil.isOneToMany(field)) { - value = SqlUtil.getOneToManyElementParams(field); - } else { - value = SqlUtil.list2Str(dbEntity, field); + db = mDelegate.checkDb(db); + //备份数据 + List list = + DelegateManager.getInstance().getDelegate(DelegateFind.class).findAllData(db, clazz); + //修改表名为中介表名 + String alertSql = "ALTER TABLE " + tableName + " RENAME TO " + tableName + "_temp"; + //db.beginTransaction(); + db.execSQL(alertSql); + + //创建一个原本的表 + mDelegate.createTable(db, clazz); + //传入原来的数据 + if (list != null && list.size() > 0) { + DelegateUpdate update = DelegateManager.getInstance().getDelegate(DelegateUpdate.class); + for (DbEntity entity : list) { + update.insertData(db, entity); } - } else if (SqlUtil.isOneToOne(field)) { - value = SqlUtil.getOneToOneParams(field); - } else { - Object obj = field.get(dbEntity); - value = obj == null ? "" : checkValue(obj.toString()); } - - //sb.append(value == null ? "" : value); - //sb.append("'"); - prams.append(TextUtils.isEmpty(value) ? "" : value); - prams.append("'"); - } catch (IllegalAccessException e) { - e.printStackTrace(); + //删除中介表 + mDelegate.dropTable(db, tableName + "_temp"); } - i++; - } - if (!TextUtils.isEmpty(prams.toString())) { - sql.append(prams.toString()); - sql.append(" where rowid=").append(dbEntity.rowID); - print(MODIFY_DATA, sql.toString()); - db.execSQL(sql.toString()); } } - mDataCache.put(getCacheKey(dbEntity), dbEntity); - close(db); - } - - private static String getCacheKey(DbEntity dbEntity) { - return dbEntity.getClass().getName() + "_" + dbEntity.rowID; + //db.setTransactionSuccessful(); + //db.endTransaction(); + mDelegate.close(db); } /** - * 插入数据 + * 处理3.4版本之前数据库迁移,主要是修改子表外键字段对应的值 */ - static synchronized void insertData(SQLiteDatabase db, DbEntity dbEntity) { - db = checkDb(db); - Class clazz = dbEntity.getClass(); - List fields = CommonUtil.getAllFields(clazz); - if (fields != null && fields.size() > 0) { - StringBuilder sb = new StringBuilder(); - sb.append("INSERT INTO ").append(CommonUtil.getClassName(dbEntity)).append("("); - int i = 0; - for (Field field : fields) { - field.setAccessible(true); - if (SqlUtil.ignoreField(field)) { - continue; - } - sb.append(i > 0 ? ", " : ""); - sb.append(field.getName()); - i++; - } - sb.append(") VALUES ("); - i = 0; - try { - for (Field field : fields) { - field.setAccessible(true); - if (SqlUtil.ignoreField(field)) { - continue; - } - sb.append(i > 0 ? ", " : ""); - sb.append("'"); - Type type = field.getType(); - if (type == Map.class) { - sb.append(SqlUtil.map2Str((Map) field.get(dbEntity))); - } else if (type == List.class) { - if (SqlUtil.isOneToMany(field)) { - sb.append(SqlUtil.getOneToManyElementParams(field)); - } else { - sb.append(SqlUtil.list2Str(dbEntity, field)); - } - } else if (SqlUtil.isOneToOne(field)) { - sb.append(SqlUtil.getOneToOneParams(field)); - } else { - sb.append(checkValue(field.get(dbEntity).toString())); - } - sb.append("'"); - i++; - } - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - sb.append(")"); - print(INSERT_DATA, sb.toString()); - db.execSQL(sb.toString()); - } - close(db); - } - - /** - * 查找表是否存在 - * - * @param clazz 数据库实体 - * @return true,该数据库实体对应的表存在;false,不存在 - */ - static synchronized boolean tableExists(SQLiteDatabase db, Class clazz) { - return tableExists(db, CommonUtil.getClassName(clazz)); - } - - static synchronized 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 clazz 数据库实体 - * @param tableName 数据库实体的类名 - */ - static synchronized void createTable(SQLiteDatabase db, Class clazz, String tableName) { - db = checkDb(db); - createFTSTable(db); - List fields = CommonUtil.getAllFields(clazz); - if (fields != null && fields.size() > 0) { - //外键Map,在Sqlite3中foreign修饰的字段必须放在最后 - final List foreignArray = new ArrayList<>(); - StringBuilder sb = new StringBuilder(); - //sb.append("create VIRTUAL table ") - sb.append("create table ") - .append(TextUtils.isEmpty(tableName) ? CommonUtil.getClassName(clazz) : tableName) - //.append(" USING fts4("); - .append(" ("); - for (Field field : fields) { - field.setAccessible(true); - if (SqlUtil.ignoreField(field)) { - continue; - } - Class type = field.getType(); - sb.append(field.getName()); - if (type == String.class || SqlUtil.isOneToOne(field) || type.isEnum()) { - sb.append(" varchar"); - } else if (type == int.class || type == Integer.class) { - sb.append(" interger"); - } 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)) { - //sb.append(" PRIMARY KEY"); - - } - if (SqlUtil.isForeign(field)) { - //foreignArray.add(field); - } - - if (SqlUtil.isNoNull(field)) { - sb.append(" NOT NULL"); - } - sb.append(","); - } + private void handle314AriaUpdate(SQLiteDatabase db) { + Set tables = DBConfig.mapping.keySet(); + for (String tableName : tables) { + Class clazz = DBConfig.mapping.get(tableName); - for (Field field : foreignArray) { - Foreign foreign = field.getAnnotation(Foreign.class); - sb.append("FOREIGN KEY (") - .append(field.getName()) - .append(") REFERENCES ") - .append(CommonUtil.getClassName(foreign.table())) - .append("(") - .append(foreign.column()) - .append("),"); + String pColumn = SqlUtil.getPrimaryName(clazz); + if (!TextUtils.isEmpty(pColumn)) { + //删除所有主键为null的数据 + String nullSql = + "DELETE FROM " + tableName + " WHERE " + pColumn + " = '' OR " + pColumn + " IS NULL"; + ALog.d(TAG, nullSql); + db.execSQL(nullSql); + + //删除所有主键重复的数据 + String repeatSql = "DELETE FROM " + + tableName + + " WHERE " + + pColumn + + " in (SELECT " + + pColumn + + " FROM " + + tableName + + " GROUP BY " + pColumn + " having count(" + pColumn + ") > 1)"; + + ALog.d(TAG, repeatSql); + db.execSQL(repeatSql); } - String str = sb.toString(); - str = str.substring(0, str.length() - 1) + ");"; - print(CREATE_TABLE, str); - db.execSQL(str); - } - close(db); - } - - /** - * 创建分词表 - */ - private static void createFTSTable(SQLiteDatabase db) { - String tableName = "ariaFts"; - String sql = "CREATE VIRTUAL TABLE " + tableName + " USING fts4(tokenize= porter)"; - if (!tableExists(db, tableName)) { - db.execSQL(sql); - } - } + //备份数据 + List list = + DelegateManager.getInstance().getDelegate(DelegateFind.class).findAllData(db, clazz); - /** - * 打印数据库日志 - * - * @param type {@link DbUtil} - */ - static void print(int type, String sql) { - if (true) { - 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; - } - ALog.v(TAG, str + sql); - } + //修改表名为中介表名 + String alertSql = "ALTER TABLE " + tableName + " RENAME TO " + tableName + "_temp"; + db.execSQL(alertSql); - /** - * 根据数据游标创建一个具体的对象 - */ - private static synchronized List newInstanceEntity(SQLiteDatabase db, - Class clazz, Cursor cursor) { - List fields = CommonUtil.getAllFields(clazz); - List entitys = new ArrayList<>(); - if (fields != null && fields.size() > 0) { - try { - while (cursor.moveToNext()) { - T entity = clazz.newInstance(); - for (Field field : fields) { - field.setAccessible(true); - if (SqlUtil.ignoreField(field)) { - continue; - } - Class type = field.getType(); - int column = cursor.getColumnIndex(field.getName()); - if (column == -1) continue; - if (type == String.class) { - field.set(entity, URLDecoder.decode(cursor.getString(column))); - } 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) { - field.setBoolean(entity, !cursor.getString(column).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) { - field.set(entity, SqlUtil.str2Map(cursor.getString(column))); - } else if (type == List.class) { - String value = cursor.getString(column); - if (SqlUtil.isOneToMany(field)) { - //主键字段 - String primaryKey = SqlUtil.getPrimaryName(clazz); - if (TextUtils.isEmpty(primaryKey)) { - throw new IllegalArgumentException("List中的元素对象必须需要@Primary注解的字段"); - } - //list字段保存的数据 - int kc = cursor.getColumnIndex(primaryKey); - String primaryData = cursor.getString(kc); - if (TextUtils.isEmpty(primaryData)) continue; - List list = findForeignData(db, primaryData, value); - if (list == null) continue; - field.set(entity, findForeignData(db, primaryData, value)); - } else { - field.set(entity, SqlUtil.str2List(value, field)); - } - } else if (SqlUtil.isOneToOne(field)) { - String primaryKey = SqlUtil.getPrimaryName(clazz); - if (TextUtils.isEmpty(primaryKey)) { - throw new IllegalArgumentException("@OneToOne的注解对象必须需要@Primary注解的字段"); - } - int kc = cursor.getColumnIndex(primaryKey); - String params = cursor.getString(column); - String primaryData = cursor.getString(kc); - if (TextUtils.isEmpty(primaryData) || primaryData.equalsIgnoreCase("null")) continue; - List list = findForeignData(db, primaryData, params); - if (list != null && list.size() > 0) { - field.set(entity, list.get(0)); - } - } + //创建一个原本的表 + mDelegate.createTable(db, clazz); + //插入数据 + if (list != null && list.size() > 0) { + DelegateUpdate update = DelegateManager.getInstance().getDelegate(DelegateUpdate.class); + try { + for (DbEntity entity : list) { + update.insertData(db, entity); } - entity.rowID = cursor.getInt(cursor.getColumnIndex("rowid")); - mDataCache.put(getCacheKey(entity), entity); - entitys.add(entity); + } catch (Exception e) { + ALog.e(TAG, CommonUtil.getPrintException(e)); } - closeCursor(cursor); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - return entitys; - } - - /** - * 查找一对多、一对一的关联数据 - * - * @param primary 当前表的主键 - * @param childParams 当前表关联数据的类名 $$ 主键名 - */ - private static List findForeignData(SQLiteDatabase db, String primary, - String childParams) { - String[] params = childParams.split("\\$\\$"); - return findData(db, params[0], params[1] + "=?", primary); - } - - private static void closeCursor(Cursor cursor) { - if (cursor != null && !cursor.isClosed()) { - try { - cursor.close(); - } catch (android.database.SQLException e) { - e.printStackTrace(); } - } - } - private static void close(SQLiteDatabase db) { - //if (db != null && db.isOpen()) db.close(); - } + //删除中介表 + mDelegate.dropTable(db, tableName + "_temp"); - private static SQLiteDatabase checkDb(SQLiteDatabase db) { - if (db == null || !db.isOpen()) { - db = INSTANCE.getWritableDatabase(); + mDelegate.close(db); } - return db; } } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/orm/SqlUtil.java b/Aria/src/main/java/com/arialyy/aria/orm/SqlUtil.java index 877f10dd..525f90cd 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/SqlUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/SqlUtil.java @@ -16,6 +16,14 @@ package com.arialyy.aria.orm; import android.text.TextUtils; +import com.arialyy.aria.orm.annotation.Default; +import com.arialyy.aria.orm.annotation.Foreign; +import com.arialyy.aria.orm.annotation.Ignore; +import com.arialyy.aria.orm.annotation.Many; +import com.arialyy.aria.orm.annotation.NoNull; +import com.arialyy.aria.orm.annotation.One; +import com.arialyy.aria.orm.annotation.Primary; +import com.arialyy.aria.orm.annotation.Wrapper; import com.arialyy.aria.util.CommonUtil; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -32,31 +40,41 @@ import java.util.Set; final class SqlUtil { /** - * 获取一对一参数 + * 获取主键字段名 */ - static String getOneToOneParams(Field field) { - OneToOne oneToOne = field.getAnnotation(OneToOne.class); - if (oneToOne == null) { - throw new IllegalArgumentException("@OneToOne注解的对象必须要有@Primary注解的字段"); + static String getPrimaryName(Class clazz) { + List fields = CommonUtil.getAllFields(clazz); + String column; + if (fields != null && !fields.isEmpty()) { + + for (Field field : fields) { + field.setAccessible(true); + if (isPrimary(field)) { + column = field.getName(); + return column; + } + } } - return oneToOne.table().getName() + "$$" + oneToOne.key(); + return null; } /** - * 获取List一对多参数 - * - * @param field list反射字段 + * 获取类中所有不被忽略的字段 */ - static String getOneToManyElementParams(Field field) { - OneToMany oneToMany = field.getAnnotation(OneToMany.class); - if (oneToMany == null) { - throw new IllegalArgumentException("一对多元素必须被@OneToMany注解"); + static List getAllNotIgnoreField(Class clazz) { + List fields = CommonUtil.getAllFields(clazz); + List temp = new ArrayList<>(); + if (fields != null && fields.size() > 0) { + for (Field f : fields) { + f.setAccessible(true); + if (!isIgnore(f)) { + temp.add(f); + } + } + return temp; + } else { + return null; } - //关联的表名 - String tableName = oneToMany.table().getName(); - //关联的字段 - String key = oneToMany.key(); - return tableName + "$$" + key; } /** @@ -65,10 +83,6 @@ final class SqlUtil { * @param field list反射字段 */ static String list2Str(DbEntity dbEntity, Field field) throws IllegalAccessException { - NormalList normalList = field.getAnnotation(NormalList.class); - if (normalList == null) { - throw new IllegalArgumentException("List中元素必须被@NormalList注解"); - } List list = (List) field.get(dbEntity); if (list == null || list.isEmpty()) return ""; StringBuilder sb = new StringBuilder(); @@ -85,17 +99,17 @@ final class SqlUtil { * @return 如果str为null,则返回null */ static List str2List(String str, Field field) { - NormalList normalList = field.getAnnotation(NormalList.class); - if (normalList == null) { - throw new IllegalArgumentException("List中元素必须被@NormalList注解"); - } if (TextUtils.isEmpty(str)) return null; String[] datas = str.split("\\$\\$"); List list = new ArrayList(); - String type = normalList.clazz().getName(); - for (String data : datas) { - list.add(checkData(type, data)); + Class clazz = CommonUtil.getListParamType(field); + if (clazz != null) { + String type = clazz.getName(); + for (String data : datas) { + list.add(checkData(type, data)); + } } + return list; } @@ -152,9 +166,12 @@ final class SqlUtil { } /** + * shadow$_klass_、shadow$_monitor_、{@link Ignore}、rowID、{@link Field#isSynthetic()}、{@link + * Modifier#isFinal(int)}、{@link Modifier#isStatic(int)}将被忽略 + * * @return true 忽略该字段 */ - static boolean ignoreField(Field field) { + static boolean isIgnore(Field field) { // field.isSynthetic(), 使用as热启动App时,AS会自动给你的class添加change字段 Ignore ignore = field.getAnnotation(Ignore.class); int modifiers = field.getModifiers(); @@ -164,19 +181,29 @@ final class SqlUtil { .isStatic(modifiers) || Modifier.isFinal(modifiers); } + /** + * 判断是否是Wrapper注解 + * + * @return {@code true} 是 + */ + static boolean isWrapper(Class clazz) { + Wrapper w = (Wrapper) clazz.getAnnotation(Wrapper.class); + return w != null; + } + /** * 判断是否一对多注解 */ - static boolean isOneToMany(Field field) { - OneToMany oneToMany = field.getAnnotation(OneToMany.class); + static boolean isMany(Field field) { + Many oneToMany = field.getAnnotation(Many.class); return oneToMany != null; } /** * 判断是否是一对一注解 */ - static boolean isOneToOne(Field field) { - OneToOne oneToOne = field.getAnnotation(OneToOne.class); + static boolean isOne(Field field) { + One oneToOne = field.getAnnotation(One.class); return oneToOne != null; } @@ -210,6 +237,16 @@ final class SqlUtil { return nn != null; } + /** + * 判断是否是default + * + * @return {@code true}为default + */ + static boolean isDefault(Field field) { + Default nn = field.getAnnotation(Default.class); + return nn != null; + } + private static Object checkData(String type, String data) { if (type.equalsIgnoreCase("java.lang.String")) { return data; @@ -222,17 +259,4 @@ final class SqlUtil { } return null; } - - /** - * 查找class的主键字段 - * - * @return 返回主键字段名 - */ - static String getPrimaryName(Class clazz) { - List fields = CommonUtil.getAllFields(clazz); - for (Field field : fields) { - if (isPrimary(field)) return field.getName(); - } - return null; - } } diff --git a/Aria/src/main/java/com/arialyy/aria/orm/Foreign.java b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Default.java similarity index 79% rename from Aria/src/main/java/com/arialyy/aria/orm/Foreign.java rename to Aria/src/main/java/com/arialyy/aria/orm/annotation/Default.java index cc577d24..dcc81434 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/Foreign.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Default.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.orm; + +package com.arialyy.aria.orm.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -21,16 +22,9 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Created by AriaL on 2017/7/4. - * 外键约束 + * Created by lyy on 2015/11/2. + * 默认数据 */ -@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Foreign { - /** - * 关联的表 - */ - Class table(); - /** - * 关联的列 - */ - String column(); -} +@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Default { + String value() default ""; +} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/orm/annotation/Foreign.java b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Foreign.java new file mode 100644 index 00000000..6371a4d7 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Foreign.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.arialyy.aria.orm.annotation; + +import com.arialyy.aria.orm.ActionPolicy; +import com.arialyy.aria.orm.DbEntity; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by AriaL on 2017/7/4. + * 外键约束 + */ +@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Foreign { + + /** + * 关联的表 + */ + Class parent(); + + /** + * 父表对应的列名 + */ + String column(); + + /** + * ON UPDATE 约束 + */ + ActionPolicy onUpdate() default ActionPolicy.NO_ACTION; + + /** + * ON DELETE 约束 + */ + ActionPolicy onDelete() default ActionPolicy.NO_ACTION; +} diff --git a/Aria/src/main/java/com/arialyy/aria/orm/Ignore.java b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Ignore.java similarity index 95% rename from Aria/src/main/java/com/arialyy/aria/orm/Ignore.java rename to Aria/src/main/java/com/arialyy/aria/orm/annotation/Ignore.java index 33c4523f..d8a9fe0d 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/Ignore.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Ignore.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.arialyy.aria.orm; +package com.arialyy.aria.orm.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/Aria/src/main/java/com/arialyy/aria/orm/OneToMany.java b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Many.java similarity index 83% rename from Aria/src/main/java/com/arialyy/aria/orm/OneToMany.java rename to Aria/src/main/java/com/arialyy/aria/orm/annotation/Many.java index 8f529e1b..59d5367c 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/OneToMany.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Many.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.orm; +package com.arialyy.aria.orm.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -24,13 +24,14 @@ import java.lang.annotation.Target; * Created by AriaL on 2017/7/4. * 一对多 */ -@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface OneToMany { +@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Many { /** - * 关联的表 + * 父表对应的字段名 */ - Class table(); + String parentColumn(); + /** - * 关联的主键 + * 父表在子表对应的字段 */ - String key(); + String entityColumn(); } diff --git a/Aria/src/main/java/com/arialyy/aria/orm/NoNull.java b/Aria/src/main/java/com/arialyy/aria/orm/annotation/NoNull.java similarity index 95% rename from Aria/src/main/java/com/arialyy/aria/orm/NoNull.java rename to Aria/src/main/java/com/arialyy/aria/orm/annotation/NoNull.java index 212efc4b..d29c8ad9 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/NoNull.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/annotation/NoNull.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.arialyy.aria.orm; +package com.arialyy.aria.orm.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/Aria/src/main/java/com/arialyy/aria/orm/OneToOne.java b/Aria/src/main/java/com/arialyy/aria/orm/annotation/One.java similarity index 82% rename from Aria/src/main/java/com/arialyy/aria/orm/OneToOne.java rename to Aria/src/main/java/com/arialyy/aria/orm/annotation/One.java index 7641fd55..3f8df08e 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/OneToOne.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/annotation/One.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.orm; +package com.arialyy.aria.orm.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -22,17 +22,8 @@ import java.lang.annotation.Target; /** * Created by AriaL on 2017/7/4. - * 一对一 + * 一 */ -@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface OneToOne { +@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface One { - /** - * 关联的表 - */ - Class table(); - - /** - * 关联的主键 - */ - String key(); } diff --git a/Aria/src/main/java/com/arialyy/aria/orm/Primary.java b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Primary.java similarity index 87% rename from Aria/src/main/java/com/arialyy/aria/orm/Primary.java rename to Aria/src/main/java/com/arialyy/aria/orm/annotation/Primary.java index 365f1713..4ac2fb1c 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/Primary.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Primary.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.arialyy.aria.orm; +package com.arialyy.aria.orm.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -27,4 +27,9 @@ import java.lang.annotation.Target; */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Primary { int value() default -1; + + /** + * 字段需要int类型才可以自增 + */ + boolean autoincrement() default false; } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/orm/annotation/Table.java b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Table.java new file mode 100644 index 00000000..e2cbbb94 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Table.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.arialyy.aria.orm.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by lyy on 2015/11/2. + * 设置表名,如果不是使用该注解,默认为类名 + */ +@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Table { + String tableName(); +} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/orm/PrimaryAndForeign.java b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Wrapper.java similarity index 72% rename from Aria/src/main/java/com/arialyy/aria/orm/PrimaryAndForeign.java rename to Aria/src/main/java/com/arialyy/aria/orm/annotation/Wrapper.java index 2b50b18d..e0894440 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/PrimaryAndForeign.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Wrapper.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.orm; +package com.arialyy.aria.orm.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -21,16 +21,9 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Created by AriaL on 2017/7/4. - * 主键和外键约束 + * Created by laoyuyu on 2018/3/21. + * 关系包裹 */ -@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface PrimaryAndForeign { - /** - * 关联的表 - */ - Class table(); - /** - * 关联的列 - */ - String column(); +@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) +public @interface Wrapper { } diff --git a/Aria/src/main/java/com/arialyy/aria/util/ALog.java b/Aria/src/main/java/com/arialyy/aria/util/ALog.java index f24a3a30..c49a1ca9 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/ALog.java +++ b/Aria/src/main/java/com/arialyy/aria/util/ALog.java @@ -25,7 +25,7 @@ import android.util.Log; * Aria日志工具 */ public class ALog { - + public static final boolean DEBUG = true; public static final int LOG_LEVEL_VERBOSE = 2; public static final int LOG_LEVEL_DEBUG = 3; public static final int LOG_LEVEL_INFO = 4; diff --git a/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java b/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java index 65cd9b53..2e61f8c1 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java @@ -74,7 +74,8 @@ public class CheckUtil { * 检查下载实体 */ public static void checkDownloadEntity(DownloadEntity entity) { - entity.setUrl(checkUrl(entity.getUrl())); + checkUrlInvalidThrow(entity.getUrl()); + entity.setUrl(entity.getUrl()); checkPath(entity.getDownloadPath()); } @@ -88,9 +89,9 @@ public class CheckUtil { } /** - * 检测下载链接是否合法,如果地址中path是"//"而不是"/"将会改为"/"; + * 检测url是否合法,如果url不合法,将抛异常 */ - public static String checkUrl(String url) { + public static void checkUrlInvalidThrow(String url) { if (TextUtils.isEmpty(url)) { throw new IllegalArgumentException("url不能为null"); } else if (!url.startsWith("http") && !url.startsWith("ftp")) { @@ -100,7 +101,26 @@ public class CheckUtil { if (index == -1) { throw new IllegalArgumentException("url不合法"); } - return url; + } + + /** + * 检测url是否合法 + * + * @return {@code true} 合法,{@code false} 非法 + */ + public static boolean checkUrl(String url) { + 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 true; } /** diff --git a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java index f52ef139..eb9da319 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java @@ -30,13 +30,10 @@ import com.arialyy.aria.core.command.group.GroupCmdFactory; import com.arialyy.aria.core.command.normal.AbsNormalCmd; import com.arialyy.aria.core.command.normal.NormalCmdFactory; import com.arialyy.aria.core.download.DownloadEntity; -import com.arialyy.aria.core.download.DownloadGroupTaskEntity; -import com.arialyy.aria.core.download.DownloadTaskEntity; +import com.arialyy.aria.core.download.DownloadGroupEntity; import com.arialyy.aria.core.inf.AbsGroupTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.upload.UploadEntity; -import com.arialyy.aria.core.upload.UploadTaskEntity; -import com.arialyy.aria.orm.DbEntity; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; @@ -46,11 +43,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; -import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.lang.reflect.WildcardType; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URLEncoder; @@ -62,6 +56,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.regex.Matcher; @@ -73,6 +68,64 @@ import java.util.regex.Pattern; public class CommonUtil { private static final String TAG = "CommonUtil"; + /** + * 获取map泛型类型 + * + * @param map list类型字段 + * @return 泛型类型 + */ + public static Class[] getMapParamType(Field map) { + Class type = map.getType(); + if (!type.isAssignableFrom(Map.class)) { + ALog.d(TAG, "字段类型不是Map"); + return null; + } + + Type fc = map.getGenericType(); + + if (fc == null) { + ALog.d(TAG, "该字段没有泛型参数"); + return null; + } + + if (fc instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) fc; + Type[] types = pt.getActualTypeArguments(); + Class[] clazz = new Class[2]; + clazz[0] = (Class) types[0]; + clazz[1] = (Class) types[1]; + return clazz; + } + return null; + } + + /** + * 获取list泛型类型 + * + * @param list list类型字段 + * @return 泛型类型 + */ + public static Class getListParamType(Field list) { + Class type = list.getType(); + if (!type.isAssignableFrom(List.class)) { + ALog.d(TAG, "字段类型不是List"); + return null; + } + + Type fc = list.getGenericType(); // 关键的地方,如果是List类型,得到其Generic的类型 + + if (fc == null) { + ALog.d(TAG, "该字段没有泛型参数"); + return null; + } + + if (fc instanceof ParameterizedType) { //如果是泛型参数的类型 + ParameterizedType pt = (ParameterizedType) fc; + return (Class) pt.getActualTypeArguments()[0]; //得到泛型里的class类型对象。 + } + return null; + } + /** * 创建文件名,如果url链接有后缀名,则使用url中的后缀名 * @@ -230,55 +283,6 @@ public class CommonUtil { return null; } - /** - * 实例化泛型的实际类型参数 - * - * @throws Exception - */ - public static void typeCheck(Type type) throws Exception { - System.out.println("该类型是" + type); - // 参数化类型 - if (type instanceof ParameterizedType) { - Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments(); - for (int i = 0; i < typeArguments.length; i++) { - // 类型变量 - if (typeArguments[i] instanceof TypeVariable) { - System.out.println("第" + (i + 1) + "个泛型参数类型是类型变量" + typeArguments[i] + ",无法实例化。"); - } - // 通配符表达式 - else if (typeArguments[i] instanceof WildcardType) { - System.out.println("第" + (i + 1) + "个泛型参数类型是通配符表达式" + typeArguments[i] + ",无法实例化。"); - } - // 泛型的实际类型,即实际存在的类型 - else if (typeArguments[i] instanceof Class) { - System.out.println("第" + (i + 1) + "个泛型参数类型是:" + typeArguments[i] + ",可以直接实例化对象"); - } - } - // 参数化类型数组或类型变量数组 - } else if (type instanceof GenericArrayType) { - System.out.println("该泛型类型是参数化类型数组或类型变量数组,可以获取其原始类型。"); - Type componentType = ((GenericArrayType) type).getGenericComponentType(); - // 类型变量 - if (componentType instanceof TypeVariable) { - System.out.println("该类型变量数组的原始类型是类型变量" + componentType + ",无法实例化。"); - } - // 参数化类型,参数化类型数组或类型变量数组 - // 参数化类型数组或类型变量数组也可以是多维的数组,getGenericComponentType()方法仅仅是去掉最右边的[] - else { - // 递归调用方法自身 - typeCheck(componentType); - } - } else if (type instanceof TypeVariable) { - System.out.println("该类型是类型变量"); - } else if (type instanceof WildcardType) { - System.out.println("该类型是通配符表达式"); - } else if (type instanceof Class) { - System.out.println("该类型不是泛型类型"); - } else { - throw new Exception(); - } - } - /** * 根据下载任务组的url创建key * @@ -308,28 +312,27 @@ public class CommonUtil { * {@code false}如果任务已经完成,只删除任务数据库记录 */ public static void delDownloadGroupTaskConfig(boolean removeFile, - DownloadGroupTaskEntity tEntity) { - List tasks = - DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", tEntity.key); - if (tasks != null && !tasks.isEmpty()) { - for (DownloadTaskEntity taskEntity : tasks) { - delDownloadTaskConfig(removeFile, taskEntity); - } + DownloadGroupEntity groupEntity) { + if (groupEntity == null) { + ALog.e(TAG, "删除下载任务组记录失败,任务组实体为null"); + return; } - if (tEntity.getEntity() != null) { - File dir = new File(tEntity.getEntity().getDirPath()); - if (removeFile) { - if (dir.exists()) { - dir.delete(); - } - } else { - if (!tEntity.getEntity().isComplete()) { - dir.delete(); - } + for (DownloadEntity taskEntity : groupEntity.getSubTask()) { + delDownloadTaskConfig(removeFile, taskEntity); + } + + File dir = new File(groupEntity.getDirPath()); + if (removeFile) { + if (dir.exists()) { + dir.delete(); + } + } else { + if (!groupEntity.isComplete()) { + dir.delete(); } - tEntity.deleteData(); } + groupEntity.deleteData(); } /** @@ -338,8 +341,7 @@ public class CommonUtil { * @param removeFile {@code true} 不仅删除任务数据库记录,还会删除已经删除完成的文件 * {@code false}如果任务已经完成,只删除任务数据库记录 */ - public static void delUploadTaskConfig(boolean removeFile, UploadTaskEntity tEntity) { - UploadEntity uEntity = tEntity.getEntity(); + public static void delUploadTaskConfig(boolean removeFile, UploadEntity uEntity) { if (uEntity == null) { return; } @@ -353,8 +355,8 @@ public class CommonUtil { if (config.exists()) { config.delete(); } - //uEntity.deleteData(); - tEntity.deleteData(); + //下载任务实体和下载实体为一对一关系,下载实体删除,任务实体自动删除 + uEntity.deleteData(); } /** @@ -363,8 +365,7 @@ public class CommonUtil { * @param removeFile {@code true} 不仅删除任务数据库记录,还会删除已经下载完成的文件 * {@code false}如果任务已经完成,只删除任务数据库记录 */ - public static void delDownloadTaskConfig(boolean removeFile, DownloadTaskEntity tEntity) { - DownloadEntity dEntity = tEntity.getEntity(); + public static void delDownloadTaskConfig(boolean removeFile, DownloadEntity dEntity) { if (dEntity == null) return; File file = new File(dEntity.getDownloadPath()); if (removeFile) { @@ -383,9 +384,8 @@ public class CommonUtil { if (config.exists()) { config.delete(); } - //dEntity.deleteData(); - //tEntity.deleteData(); - tEntity.deleteData(); + //下载任务实体和下载实体为一对一关系,下载实体删除,任务实体自动删除 + dEntity.deleteData(); } /** diff --git a/Aria/src/main/java/com/arialyy/aria/util/ErrorHelp.java b/Aria/src/main/java/com/arialyy/aria/util/ErrorHelp.java index 4a56c186..20258930 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/ErrorHelp.java +++ b/Aria/src/main/java/com/arialyy/aria/util/ErrorHelp.java @@ -35,6 +35,8 @@ public class ErrorHelp { * @param msg 错误提示 * @param ex 异常 */ + // TODO: 2018/4/4 错误应该写在文件中 + @Deprecated public static void saveError(String taskType, AbsEntity entity, String msg, String ex) { ErrorEntity errorEntity = new ErrorEntity(); errorEntity.insertTime = System.currentTimeMillis(); diff --git a/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java b/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java index 4762fe1f..7140a086 100644 --- a/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java @@ -45,7 +45,7 @@ public class DownloadGroupActivity extends BaseActivity temps = Aria.download(this).getTotleTaskList(); + List temps = Aria.download(this).getTotalTaskList(); if (temps != null && !temps.isEmpty()) { mData.addAll(temps); } diff --git a/aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskEntity.java b/aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskEntity.java index 83ad03af..709558e4 100644 --- a/aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskEntity.java +++ b/aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskEntity.java @@ -16,7 +16,9 @@ package com.arialyy.aria.core.upload; import com.arialyy.aria.core.inf.AbsNormalTaskEntity; -import com.arialyy.aria.orm.OneToOne; +import com.arialyy.aria.orm.annotation.Foreign; +import com.arialyy.aria.orm.annotation.Ignore; +import com.arialyy.aria.orm.annotation.Primary; import java.util.HashMap; import java.util.Map; @@ -28,9 +30,16 @@ public class UploadTaskEntity extends AbsNormalTaskEntity { public String attachment; //文件上传需要的key public String contentType = "multipart/form-data"; //上传的文件类型 public String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)"; - @OneToOne(table = UploadEntity.class, key = "filePath") public UploadEntity entity; + + //@OneToOne(table = UploadEntity.class, key = "filePath") public UploadEntity entity; + + @Ignore public UploadEntity entity; + public String filePath = ""; + @Primary @Foreign(parent = UploadEntity.class, column = "filePath") + public String key; + /** * 文件上传表单 */ @@ -43,11 +52,17 @@ public class UploadTaskEntity extends AbsNormalTaskEntity { return entity; } + @Override public String getKey() { + return key; + } + public void save(UploadEntity entity) { - filePath = entity.getFilePath(); - key = entity.getKey(); - this.entity = entity; - entity.save(); + if (entity != null) { + filePath = entity.getFilePath(); + key = entity.getKey(); + this.entity = entity; + entity.save(); + } save(); } } From 1e5f01cbd8819152e86f60207236e944517ca562 Mon Sep 17 00:00:00 2001 From: laoyuyu <511455842@qq.com> Date: Thu, 12 Apr 2018 21:41:32 +0800 Subject: [PATCH 13/22] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E4=BC=98?= =?UTF-8?q?=E5=8C=96=EF=BC=8C=E4=BB=A3=E7=A0=81=E9=80=BB=E8=BE=91=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/arialyy/aria/core/AriaManager.java | 6 +- .../aria/core/command/normal/StartCmd.java | 1 + .../aria/core/download/BaseDListener.java | 2 +- .../aria/core/download/BaseGroupTarget.java | 52 +++--- .../aria/core/download/BaseNormalTarget.java | 3 +- .../aria/core/download/DownloadEntity.java | 20 +-- .../core/download/DownloadGroupEntity.java | 20 +-- .../core/download/DownloadGroupListener.java | 2 +- .../core/download/DownloadGroupTarget.java | 65 +++---- .../aria/core/download/DownloadGroupTask.java | 1 - .../download/DownloadGroupTaskEntity.java | 26 +-- .../aria/core/download/DownloadReceiver.java | 15 +- .../core/download/DownloadTaskEntity.java | 21 +-- .../core/download/FtpDirDownloadTarget.java | 5 +- .../download/downloader/AbsGroupUtil.java | 97 +++-------- .../downloader/DownloadGroupUtil.java | 4 +- .../downloader/FtpDirDownloadUtil.java | 6 +- .../download/downloader/FtpDirInfoThread.java | 22 ++- .../DGroupEntityWrapper.java} | 9 +- .../DGroupSubTaskEntityWrapper.java} | 20 +-- .../wrapper/DGroupTaskEntityWrapper.java | 60 +++++++ .../{ => wrapper}/DownloadTaskWrapper.java | 4 +- .../com/arialyy/aria/core/inf/AbsEntity.java | 6 +- .../arialyy/aria/core/inf/AbsGroupEntity.java | 4 +- .../aria/core/inf/AbsNormalEntity.java | 6 +- .../com/arialyy/aria/core/inf/AbsTarget.java | 2 +- .../aria/core/manager/DGTEFactory.java | 162 ++++++++++++++++++ .../aria/core/manager/DGTEntityFactory.java | 128 -------------- .../{DTEntityFactory.java => DTEFactory.java} | 32 ++-- ...IGTEntityFactory.java => IGTEFactory.java} | 20 ++- ...tityFactory.java => INormalTEFactory.java} | 2 +- .../arialyy/aria/core/manager/TEManager.java | 97 +++++++++-- .../{UTEntityFactory.java => UTEFactory.java} | 14 +- .../aria/core/upload/BaseNormalTarget.java | 3 +- .../aria/core/upload/BaseUListener.java | 2 +- .../java/com/arialyy/aria/orm/DbEntity.java | 67 +------- .../com/arialyy/aria/orm/DelegateFind.java | 2 +- .../com/arialyy/aria/orm/DelegateUpdate.java | 85 +++++---- .../com/arialyy/aria/orm/DelegateWrapper.java | 2 +- .../java/com/arialyy/aria/orm/SqlHelper.java | 2 +- .../com/arialyy/aria/orm/annotation/Many.java | 7 + .../main/java/com/arialyy/aria/util/ALog.java | 50 ++++++ .../com/arialyy/aria/util/CommonUtil.java | 4 +- app/src/main/AndroidManifest.xml | 4 +- .../simple/download/SingleTaskActivity.java | 1 - .../download/group/DownloadGroupActivity.java | 10 +- .../group/FTPDirDownloadActivity.java | 8 +- .../simple/download/group/GroupModule.java | 4 +- .../multi_download/DownloadAdapter.java | 4 +- .../com/arialyy/simple/test/TestActivity.java | 92 ++++++++++ .../simple/test/TestGroupActivity.java | 91 ++++++++++ app/src/main/res/layout/activity_test.xml | 40 +++++ .../aria/core/upload/UploadTaskEntity.java | 17 +- 53 files changed, 885 insertions(+), 544 deletions(-) rename Aria/src/main/java/com/arialyy/aria/core/download/{DownloadGroupWrapper.java => wrapper/DGroupEntityWrapper.java} (78%) rename Aria/src/main/java/com/arialyy/aria/core/download/{DownloadGroupTaskWrapper.java => wrapper/DGroupSubTaskEntityWrapper.java} (63%) create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGroupTaskEntityWrapper.java rename Aria/src/main/java/com/arialyy/aria/core/download/{ => wrapper}/DownloadTaskWrapper.java (89%) create mode 100644 Aria/src/main/java/com/arialyy/aria/core/manager/DGTEFactory.java delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/manager/DGTEntityFactory.java rename Aria/src/main/java/com/arialyy/aria/core/manager/{DTEntityFactory.java => DTEFactory.java} (78%) rename Aria/src/main/java/com/arialyy/aria/core/manager/{IGTEntityFactory.java => IGTEFactory.java} (55%) rename Aria/src/main/java/com/arialyy/aria/core/manager/{ITEntityFactory.java => INormalTEFactory.java} (90%) rename Aria/src/main/java/com/arialyy/aria/core/manager/{UTEntityFactory.java => UTEFactory.java} (88%) create mode 100644 app/src/main/java/com/arialyy/simple/test/TestActivity.java create mode 100644 app/src/main/java/com/arialyy/simple/test/TestGroupActivity.java create mode 100644 app/src/main/res/layout/activity_test.xml diff --git a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java index efaca07f..c76c4cc0 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java @@ -323,6 +323,7 @@ import org.xml.sax.SAXException; * 根据功能类型和控件类型获取对应的key */ private String getKey(boolean isDownload, Object obj) { + // TODO: 2018/4/12 不做限制了,让所有类都可以使用 String clsName = obj.getClass().getName(); String key = ""; if (!(obj instanceof Activity)) { @@ -421,8 +422,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); } } @@ -493,6 +494,7 @@ import org.xml.sax.SAXException; @Override public void onActivityDestroyed(Activity activity) { destroySchedulerListener(activity); + // TODO: 2018/4/11 维护一个activity堆栈,应用被kill,activity会回调onDestroy方法,需要考虑server后台情况 } } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java index 62824b10..45bbab04 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java @@ -53,6 +53,7 @@ class StartCmd extends AbsNormalCmd { return; } String mod; + // TODO: 2018/4/12 配置文件不存在,是否会出现wait获取不到 ? int maxTaskNum = mQueue.getMaxTaskNum(); AriaManager manager = AriaManager.getInstance(AriaManager.APP); if (isDownloadCmd) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java b/Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java index 04b6d44f..10ca12c0 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java @@ -154,7 +154,7 @@ class BaseDListener /** * 文件夹临时路径 */ - protected String mDirPathTemp; + String mDirPathTemp; + /** + * 是否需要修改路径 + */ + boolean needModifyPath = false; private SubTaskManager mSubTaskManager; @@ -110,21 +113,21 @@ abstract class BaseGroupTarget * * @param newDirPath 新的文件夹路径 */ - private void reChangeDirPath(String newDirPath) { - List 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 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); - 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 + "'"); + if (file.exists()) { + file.renameTo(new File(newPath)); + } + de.setDownloadPath(newPath); + dte.key = newPath; + de.save(); + dte.save(); } } } @@ -135,26 +138,25 @@ abstract class BaseGroupTarget * @return {@code true} 合法 */ boolean checkDirPath() { - final String dirPath = mDirPathTemp; - if (TextUtils.isEmpty(dirPath)) { + if (TextUtils.isEmpty(mDirPathTemp)) { ALog.e(TAG, "文件夹路径不能为null"); return false; - } else if (!dirPath.startsWith("/")) { - ALog.e(TAG, "文件夹路径【" + dirPath + "】错误"); + } else if (!mDirPathTemp.startsWith("/")) { + ALog.e(TAG, "文件夹路径【" + mDirPathTemp + "】错误"); return false; } - File file = new File(dirPath); + File file = new File(mDirPathTemp); if (file.isFile()) { - ALog.e(TAG, "路径【" + dirPath + "】是文件,请设置文件夹路径"); + ALog.e(TAG, "路径【" + mDirPathTemp + "】是文件,请设置文件夹路径"); return false; } - if (!mEntity.getDirPath().equals(dirPath)) { + if (TextUtils.isEmpty(mEntity.getDirPath()) || !mEntity.getDirPath().equals(mDirPathTemp)) { if (!file.exists()) { file.mkdirs(); } - mEntity.setDirPath(dirPath); - reChangeDirPath(dirPath); + needModifyPath = true; + mEntity.setDirPath(mDirPathTemp); } return true; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java index 141d5fb3..f5e8e6b0 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/BaseNormalTarget.java @@ -108,7 +108,8 @@ abstract class BaseNormalTarget @Override protected boolean checkEntity() { boolean b = getTargetType() < GROUP_HTTP && checkUrl() && checkFilePath(); if (b) { - mTaskEntity.save(mEntity); + mEntity.save(); + mTaskEntity.save(); } return b; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java index 89704153..b22ae995 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java @@ -21,6 +21,7 @@ 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.ActionPolicy; import com.arialyy.aria.orm.annotation.Foreign; import com.arialyy.aria.orm.annotation.Primary; import com.arialyy.aria.util.CommonUtil; @@ -30,28 +31,30 @@ import com.arialyy.aria.util.CommonUtil; * 下载实体 */ public class DownloadEntity extends AbsNormalEntity implements Parcelable { - @Primary private String downloadPath = ""; //保存路径 + @Primary private String downloadPath; //保存路径 /** * 所属任务组 */ - @Foreign(parent = DownloadGroupEntity.class, column = "groupName") private String groupName = ""; + @Foreign(parent = DownloadGroupEntity.class, column = "groupName", + onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE) + private String groupName; /** * 从服务器的返回信息中获取的文件md5信息,如果服务器没有返回,则不会设置该信息 * 如果你已经设置了该任务的MD5信息,Aria也不会从服务器返回的信息中获取该信息 */ - private String md5Code = ""; + private String md5Code; /** * 从服务器的返回信息中获取的文件描述信息 */ - private String disposition = ""; + private String disposition; /** * 从disposition获取到的文件名,如果可以获取到,则会赋值到这个字段 */ - private String serverFileName = ""; + private String serverFileName; @Override public String getKey() { return getUrl(); @@ -96,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; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java index d90b05eb..e061c009 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java @@ -27,25 +27,21 @@ import java.util.List; */ public class DownloadGroupEntity extends AbsGroupEntity { - //@OneToMany(table = DownloadEntity.class, key = "groupName") private List subtask = - // new ArrayList<>(); - - @Ignore - private List subtask; + @Ignore private List subEntities; /** * 任务组下载文件的文件夹地址 * * @see DownloadGroupTarget#setDirPath(String) */ - private String dirPath = ""; + private String dirPath; - public List getSubTask() { - return subtask; + public List getSubEntities() { + return subEntities; } - public void setSubTasks(List subTasks) { - this.subtask = subTasks; + public void setSubEntities(List subTasks) { + this.subEntities = subTasks; } public String getDirPath() { @@ -73,13 +69,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(); } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java index 321a8311..806d341f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java @@ -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); diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java index 1d2b0a8d..5a938021 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java @@ -17,7 +17,6 @@ package com.arialyy.aria.core.download; import android.text.TextUtils; import com.arialyy.aria.core.manager.TEManager; -import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CommonUtil; import java.io.File; @@ -46,21 +45,23 @@ public class DownloadGroupTarget extends BaseGroupTarget { if (groupEntity.getUrls() != null && !groupEntity.getUrls().isEmpty()) { this.mUrls.addAll(groupEntity.getUrls()); } - mGroupName = CommonUtil.getMd5Code(groupEntity.getUrls()); - mTaskEntity = TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, mUrls); - mEntity = mTaskEntity.getEntity(); - - if (mEntity != null) { - mDirPathTemp = mEntity.getDirPath(); - } + init(); } DownloadGroupTarget(List urls, String targetName) { this.mTargetName = targetName; this.mUrls = urls; - mGroupName = CommonUtil.getMd5Code(urls); + init(); + } + + private void init() { + mGroupName = CommonUtil.getMd5Code(mUrls); mTaskEntity = TEManager.getInstance().getGTEntity(DownloadGroupTaskEntity.class, mUrls); mEntity = mTaskEntity.getEntity(); + + if (mEntity != null) { + mDirPathTemp = mEntity.getDirPath(); + } } /** @@ -105,6 +106,11 @@ public class DownloadGroupTarget extends BaseGroupTarget { */ public DownloadGroupTarget setSubFileName(List 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(); @@ -112,27 +118,6 @@ public class DownloadGroupTarget extends BaseGroupTarget { return this; } - /** - * 创建子任务 - */ - private List createSubTask() { - List list = new ArrayList<>(); - for (int i = 0, len = mUrls.size(); i < len; i++) { - DownloadEntity entity = new DownloadEntity(); - entity.setUrl(mUrls.get(i)); - String fileName = - mSubNameTemp.isEmpty() ? CommonUtil.createFileName(entity.getUrl()) : mSubNameTemp.get(i); - entity.setDownloadPath(mEntity.getDirPath() + "/" + fileName); - entity.setGroupName(mGroupName); - entity.setGroupChild(true); - entity.setFileName(fileName); - // TODO: 2018/4/3 是否需要在这个插入? - //entity.insert(); - list.add(entity); - } - return list; - } - @Override protected int getTargetType() { return GROUP_HTTP; } @@ -151,10 +136,14 @@ public class DownloadGroupTarget extends BaseGroupTarget { return false; } - //文件夹路径通过后,并且该实体没有子任务,则创建子任务 - if (mEntity.getSubTask() == null || mEntity.getSubTask().isEmpty()) { - mEntity.setSubTasks(createSubTask()); - } else { + mEntity.save(); + mTaskEntity.save(); + + if (needModifyPath) { + reChangeDirPath(mDirPathTemp); + } + + if (!mSubNameTemp.isEmpty()) { updateSingleSubFileName(); } return true; @@ -166,7 +155,7 @@ public class DownloadGroupTarget extends BaseGroupTarget { * 更新所有改动的子任务文件名 */ private void updateSingleSubFileName() { - List entities = mEntity.getSubTask(); + List entities = mEntity.getSubEntities(); int i = 0; for (DownloadEntity entity : entities) { if (i < mSubNameTemp.size()) { @@ -235,12 +224,10 @@ public class DownloadGroupTarget extends BaseGroupTarget { oldFile.renameTo(new File(newPath)); } CommonUtil.renameDownloadConfig(oldFile.getName(), newName); - DbEntity.exeSql( - "UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'"); + // TODO: 2018/4/11 需要校验数据库级联操作是否生效 entity.setDownloadPath(newPath); entity.setFileName(newName); - // TODO: 2018/4/3 是否需要在这个更新? - //entity.update(); + entity.update(); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java index ee2b44b4..87fb4e2d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java @@ -116,7 +116,6 @@ public class DownloadGroupTask extends AbsGroupTask { public DownloadGroupTask build() { DownloadGroupTask task = new DownloadGroupTask(taskEntity, outHandler); task.setTargetName(targetName); - taskEntity.save(); return task; } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java index bd24c154..0fff9682 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java @@ -16,18 +16,25 @@ package com.arialyy.aria.core.download; import com.arialyy.aria.core.inf.AbsGroupTaskEntity; +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 { @Ignore private DownloadGroupEntity entity; - @Primary @Foreign(parent = DownloadGroupEntity.class, column = "groupName") + @Ignore private List subTaskEntities; + + @Primary + @Foreign(parent = DownloadGroupEntity.class, column = "groupName", + onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE) private String key; @Override public DownloadGroupEntity getEntity() { @@ -38,6 +45,14 @@ public class DownloadGroupTaskEntity extends AbsGroupTaskEntity getSubTaskEntities() { + return subTaskEntities; + } + + public void setSubTaskEntities(List subTaskEntities) { + this.subTaskEntities = subTaskEntities; + } + @Override public String getKey() { return key; } @@ -45,13 +60,4 @@ public class DownloadGroupTaskEntity extends AbsGroupTaskEntity getGroupTaskList() { - List wrappers = DbEntity.findRelationData(DownloadGroupWrapper.class); + List wrappers = DbEntity.findRelationData(DGroupEntityWrapper.class); if (wrappers == null || wrappers.isEmpty()) { return null; } List entities = new ArrayList<>(); - for (DownloadGroupWrapper wrapper : wrappers) { + for (DGroupEntityWrapper wrapper : wrappers) { entities.add(wrapper.groupEntity); } return entities; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java index a089da27..8bdff9a6 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java @@ -16,6 +16,7 @@ package com.arialyy.aria.core.download; import com.arialyy.aria.core.inf.AbsNormalTaskEntity; +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; @@ -27,7 +28,6 @@ import com.arialyy.aria.orm.annotation.Primary; */ public class DownloadTaskEntity extends AbsNormalTaskEntity { - //@OneToOne(table = DownloadEntity.class, key = "downloadPath") public DownloadEntity entity; @Ignore public DownloadEntity entity; /** @@ -38,7 +38,9 @@ public class DownloadTaskEntity extends AbsNormalTaskEntity { /** * 所属的任务组组名,如果不属于任务组,则为null */ - public String groupName = ""; + @Foreign(parent = DownloadGroupTaskEntity.class, column = "key", + onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE) + public String groupName; /** * 是否是chunk模式 @@ -53,7 +55,10 @@ public class DownloadTaskEntity extends AbsNormalTaskEntity { /** * Task实体对应的key */ - @Primary @Foreign(parent = DownloadEntity.class, column = "downloadPath") public String key = ""; + @Primary + @Foreign(parent = DownloadEntity.class, column = "downloadPath", + onUpdate = ActionPolicy.CASCADE, onDelete = ActionPolicy.CASCADE) + public String key; public DownloadTaskEntity() { } @@ -65,14 +70,4 @@ public class DownloadTaskEntity extends AbsNormalTaskEntity { @Override public String getKey() { return key; } - - public void save(DownloadEntity entity) { - this.entity = entity; - if (entity != null) { - url = entity.getUrl(); - key = entity.getDownloadPath(); - entity.save(); - } - save(); - } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java index 7b82e2fd..a81142f3 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/FtpDirDownloadTarget.java @@ -37,7 +37,7 @@ public class FtpDirDownloadTarget extends BaseGroupTarget private void init(String key) { mGroupName = key; - mTaskEntity = TEManager.getInstance().getTEntity(DownloadGroupTaskEntity.class, key); + mTaskEntity = TEManager.getInstance().getFDTEntity(DownloadGroupTaskEntity.class, key); mTaskEntity.requestType = AbsTaskEntity.D_FTP_DIR; mEntity = mTaskEntity.getEntity(); if (mEntity != null) { @@ -53,7 +53,8 @@ public class FtpDirDownloadTarget extends BaseGroupTarget @Override protected boolean checkEntity() { boolean b = getTargetType() == GROUP_FTP_DIR && checkDirPath() && checkUrl(); if (b) { - mTaskEntity.save(mEntity); + mEntity.save(); + mTaskEntity.save(); } return b; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java index 012e9fc3..06a82131 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java @@ -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,14 +70,15 @@ public abstract class AbsGroupUtil implements IUtil { Map mFailMap = new HashMap<>(); /** - * 下载器映射表,key为下载地址 + * 该任务组对应的所有任务 */ - private Map mDownloaderMap = new HashMap<>(); + private Map mTasksMap = new HashMap<>(); /** - * 该任务组对应的所有任务 + * 下载器映射表,key为下载地址 */ - private Map mTasksMap = new HashMap<>(); + private Map mDownloaderMap = new HashMap<>(); + /** * 是否需要读取文件长度,{@code true}需要 */ @@ -99,37 +97,31 @@ public abstract class AbsGroupUtil implements IUtil { 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 tasks = - DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mGTEntity.getKey()); - 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.getEntity().getSubTask().size(); + + mGroupSize = mGTEntity.getSubTaskEntities().size(); mTotalLen = groupEntity.getEntity().getFileSize(); isNeedLoadFileSize = mTotalLen <= 1; - for (DownloadEntity entity : mGTEntity.getEntity().getSubTask()) { - File file = new File(entity.getDownloadPath()); - if (entity.getState() == IEntity.STATE_COMPLETE && file.exists()) { + + for (DownloadTaskEntity te : mGTEntity.getSubTaskEntities()) { + File file = new File(te.getKey()); + if (te.getState() == IEntity.STATE_COMPLETE && file.exists()) { mCompleteNum++; - mCurrentLocation += entity.getFileSize(); + mCurrentLocation += te.getEntity().getFileSize(); } else { - mExeMap.put(entity.getUrl(), createChildDownloadTask(entity)); - mCurrentLocation += file.exists() ? entity.getCurrentProgress() : 0; + mExeMap.put(te.url, te); + mCurrentLocation += file.exists() ? te.getEntity().getCurrentProgress() : 0; mActualTaskNum++; } if (isNeedLoadFileSize) { - mTotalLen += entity.getFileSize(); + mTotalLen += te.getEntity().getFileSize(); } + mTasksMap.put(te.url, te); } updateFileSize(); mUpdateInterval = @@ -190,12 +182,9 @@ public abstract class AbsGroupUtil implements IUtil { * @param url 子任务下载地址 */ public void cancelSubTask(String url) { - List urls = mGTEntity.getEntity().getUrls(); - if (urls != null && !urls.isEmpty() && urls.contains(url)) { - urls.remove(url); - // TODO: 2018/4/4 有问题 - DownloadTaskEntity det = - DbEntity.findFirst(DownloadTaskEntity.class, "url=? and isGroupTask='true'", url); + Set urls = mTasksMap.keySet(); + if (!urls.isEmpty() && urls.contains(url)) { + DownloadTaskEntity det = mTasksMap.get(url); if (det != null) { mTotalLen -= det.getEntity().getFileSize(); mGroupSize--; @@ -275,7 +264,6 @@ public abstract class AbsGroupUtil implements IUtil { } } CommonUtil.delDownloadGroupTaskConfig(mGTEntity.removeFile, mGTEntity.getEntity()); - mGTEntity.deleteData(); } public void onCancel() { @@ -306,7 +294,11 @@ public abstract class AbsGroupUtil implements IUtil { isRunning = true; mFailNum = 0; mListener.onPre(); - onStart(); + if (mCompleteNum == mGroupSize) { + mListener.onComplete(); + } else { + onStart(); + } } protected void onStart() { @@ -377,43 +369,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.removeFile = mGTEntity.removeFile; - taskEntity.groupName = mGTEntity.getKey(); - 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; - } - /** * 子任务事件监听 */ @@ -554,7 +509,7 @@ public abstract class AbsGroupUtil implements IUtil { 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()); diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java index 7699077d..e5a47a82 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java @@ -109,7 +109,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil { createChildDownload(te); } mInitNum++; - if (mInitNum + mInitFailNum >= mGTEntity.getEntity().getSubTask().size() + if (mInitNum + mInitFailNum >= mGTEntity.getEntity().getSubEntities().size() || !isNeedLoadFileSize) { startRunningFlow(); updateFileSize(); @@ -132,7 +132,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil { if (mActualTaskNum < 0) mActualTaskNum = 0; } failNum++; - if (mInitNum + mInitFailNum >= mGTEntity.getEntity().getSubTask().size() + if (mInitNum + mInitFailNum >= mGTEntity.getEntity().getSubEntities().size() || !isNeedLoadFileSize) { startRunningFlow(); updateFileSize(); diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java index f2c9665d..1b1b4b3c 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java @@ -20,6 +20,7 @@ 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.core.manager.TEManager; import com.arialyy.aria.util.ErrorHelp; import java.util.Set; @@ -44,10 +45,7 @@ public class FtpDirDownloadUtil extends AbsGroupUtil { new FtpDirInfoThread(mGTEntity, new OnFileInfoCallback() { @Override public void onComplete(String url, CompleteInfo info) { if (info.code >= 200 && info.code < 300) { - for (DownloadEntity entity : mGTEntity.getEntity().getSubTask()) { - mExeMap.put(entity.getUrl(), createChildDownloadTask(entity)); - } - mActualTaskNum = mGTEntity.getEntity().getSubTask().size(); + mActualTaskNum = mGTEntity.getEntity().getSubEntities().size(); mGroupSize = mActualTaskNum; mTotalLen = mGTEntity.getEntity().getFileSize(); startDownload(); diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java index 8b4bf128..7efa26b0 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java @@ -22,6 +22,7 @@ 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.util.CommonUtil; import java.nio.charset.Charset; import java.util.ArrayList; @@ -52,10 +53,14 @@ class FtpDirInfoThread extends AbsFtpInfoThread()); } - if (mEntity.getSubTask() == null) { - mEntity.setSubTasks(new ArrayList()); + if (mEntity.getSubEntities() == null) { + mEntity.setSubEntities(new ArrayList()); } - mEntity.getSubTask().add(entity); + mEntity.getSubEntities().add(entity); + mTaskEntity.getSubTaskEntities().add(taskEntity); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupWrapper.java b/Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGroupEntityWrapper.java similarity index 78% rename from Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupWrapper.java rename to Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGroupEntityWrapper.java index e5a1e9d9..25c6a5ac 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupWrapper.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGroupEntityWrapper.java @@ -13,8 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.core.download; +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; @@ -23,9 +25,10 @@ import java.util.List; /** * Created by laoyuyu on 2018/3/30. + * 任务组实体和子任务实体的关系 */ @Wrapper -public class DownloadGroupWrapper extends AbsWrapper { +public class DGroupEntityWrapper extends AbsWrapper { @One public DownloadGroupEntity groupEntity; @@ -35,7 +38,7 @@ public class DownloadGroupWrapper extends AbsWrapper { @Override protected void handleConvert() { if (subEntity != null && !subEntity.isEmpty()) { - groupEntity.setSubTasks(subEntity); + groupEntity.setSubEntities(subEntity); } } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskWrapper.java b/Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGroupSubTaskEntityWrapper.java similarity index 63% rename from Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskWrapper.java rename to Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGroupSubTaskEntityWrapper.java index c0f3fbfd..057c42bd 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskWrapper.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGroupSubTaskEntityWrapper.java @@ -13,8 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.core.download; +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; @@ -22,23 +24,21 @@ import com.arialyy.aria.orm.annotation.Wrapper; import java.util.List; /** - * Created by laoyuyu on 2018/3/30. + * Created by laoyuyu on 2018/4/11. + * 任务组任务实体和任务组任务实体的子任务实体对应关系 */ @Wrapper -public class DownloadGroupTaskWrapper extends AbsWrapper { +public class DGroupSubTaskEntityWrapper extends AbsWrapper { @One - public DownloadGroupEntity entity; + public DownloadGroupTaskEntity dgTaskEntity; @Many(parentColumn = "key", entityColumn = "groupName") - private List taskEntitys; - - public DownloadGroupTaskEntity taskEntity; + public List subTaskEntity; @Override protected void handleConvert() { - taskEntity = (taskEntitys == null || taskEntitys.isEmpty()) ? null : taskEntitys.get(0); - if (taskEntity != null) { - taskEntity.setEntity(entity); + if (subTaskEntity != null && !subTaskEntity.isEmpty()) { + dgTaskEntity.setSubTaskEntities(subTaskEntity); } } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGroupTaskEntityWrapper.java b/Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGroupTaskEntityWrapper.java new file mode 100644 index 00000000..0575daee --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DGroupTaskEntityWrapper.java @@ -0,0 +1,60 @@ +/* + * 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.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 java.util.ArrayList; +import java.util.List; + +/** + * Created by laoyuyu on 2018/3/30. + * 任务组实体和任务组任务实体的关系 + */ +@Wrapper +public class DGroupTaskEntityWrapper extends AbsWrapper { + + @One + public DownloadGroupEntity entity; + + @Many(parentColumn = "groupName", entityColumn = "key") + private List taskEntitys; + + public DownloadGroupTaskEntity taskEntity; + + @Override protected void handleConvert() { + taskEntity = (taskEntitys == null || taskEntitys.isEmpty()) ? null : taskEntitys.get(0); + if (taskEntity != null) { + taskEntity.setEntity(entity); + List subWrappers = + DbEntity.findRelationData(DownloadTaskWrapper.class, "DownloadTaskEntity.groupName=?", + taskEntity.getKey()); + if (subWrappers != null && !subWrappers.isEmpty()) { + List temp = new ArrayList<>(); + for (DownloadTaskWrapper dw : subWrappers) { + temp.add(dw.taskEntity); + } + taskEntity.setSubTaskEntities(temp); + } + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskWrapper.java b/Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DownloadTaskWrapper.java similarity index 89% rename from Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskWrapper.java rename to Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DownloadTaskWrapper.java index a2fe9137..133a47ad 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskWrapper.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/wrapper/DownloadTaskWrapper.java @@ -13,8 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.core.download; +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; diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java index aa297862..c4a10c5c 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java @@ -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; /** diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java index d8250ab7..ad7f6abc 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java @@ -28,12 +28,12 @@ public abstract class AbsGroupEntity extends AbsEntity implements Parcelable { /** * 组名,组名为任务地址相加的url的Md5 */ - @Primary protected String groupName = ""; + @Primary protected String groupName; /** * 任务组别名 */ - private String alias = ""; + private String alias; private List urls = new ArrayList<>(); diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java index c6391ae2..86e6ed12 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java @@ -26,12 +26,12 @@ public abstract class AbsNormalEntity extends AbsEntity implements Parcelable { /** * 服务器地址 */ - private String url = ""; + private String url; /** * 文件名 */ - private String fileName = ""; + private String fileName; /** * 是否是任务组里面的下载实体 @@ -39,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; diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java index eac0d191..f67a7727 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java @@ -64,7 +64,7 @@ public abstract class AbsTarget { + 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 urls) { + DownloadGroupEntity entity = createDGroupEntity(groupName, urls); + List wrapper = + DbEntity.findRelationData(DGroupTaskEntityWrapper.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 wrapper = + DbEntity.findRelationData(DGroupTaskEntityWrapper.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.urlEntity = CommonUtil.getFtpUrlInfo(ftpUrl); + return fte; + } + + /** + * 创建任务组子任务的任务实体 + */ + private List createDGSubTaskEntity(DownloadGroupEntity dge) { + List list = new ArrayList<>(); + for (DownloadEntity entity : dge.getSubEntities()) { + DownloadTaskEntity taskEntity = new DownloadTaskEntity(); + taskEntity.entity = entity; + taskEntity.key = entity.getDownloadPath(); + taskEntity.groupName = dge.getKey(); + taskEntity.isGroupTask = true; + taskEntity.url = entity.getUrl(); + list.add(taskEntity); + } + return list; + } + + /** + * 查询任务组实体,如果数据库不存在该实体,则新创建一个新的任务组实体 + */ + private DownloadGroupEntity createDGroupEntity(String groupName, List urls) { + List wrapper = + DbEntity.findRelationData(DGroupEntityWrapper.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 createSubTask(String groupName, List urls) { + List 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; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/manager/DGTEntityFactory.java b/Aria/src/main/java/com/arialyy/aria/core/manager/DGTEntityFactory.java deleted file mode 100644 index af0ebce2..00000000 --- a/Aria/src/main/java/com/arialyy/aria/core/manager/DGTEntityFactory.java +++ /dev/null @@ -1,128 +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.core.download.DownloadGroupTaskWrapper; -import com.arialyy.aria.core.download.DownloadGroupWrapper; -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, - IGTEntityFactory { - 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; - } - - /** - * 通过下载实体创建任务实体 - */ - private DownloadGroupTaskEntity create(DownloadGroupEntity entity) { - List wrapper = - DbEntity.findRelationData(DownloadGroupTaskWrapper.class, "DownloadGroupTaskWrapper.key=?", - entity.getGroupName()); - DownloadGroupTaskEntity dgTaskEntity; - - if (wrapper != null && !wrapper.isEmpty()) { - dgTaskEntity = wrapper.get(0).taskEntity; - if (dgTaskEntity == null) { - dgTaskEntity = new DownloadGroupTaskEntity(); - dgTaskEntity.setEntity(entity); - } else if (dgTaskEntity.getEntity() == null || TextUtils.isEmpty( - dgTaskEntity.getEntity().getKey())) { - dgTaskEntity.setEntity(entity); - } - } else { - dgTaskEntity = new DownloadGroupTaskEntity(); - dgTaskEntity.setEntity(entity); - } - - return dgTaskEntity; - } - - /** - * 对于任务组,不能使用这个,该方法只用于FTP文件夹下载 - * - * @deprecated 任务组使用:{@link #create(String, List)} - */ - @Override @Deprecated public DownloadGroupTaskEntity create(String key) { - List wrapper = - DbEntity.findRelationData(DownloadGroupTaskWrapper.class, "DownloadGroupTaskWrapper.key=?", - key); - DownloadGroupTaskEntity dgTaskEntity; - if (wrapper != null && !wrapper.isEmpty()) { - dgTaskEntity = wrapper.get(0).taskEntity; - if (dgTaskEntity == null) { - dgTaskEntity = new DownloadGroupTaskEntity(); - dgTaskEntity.setEntity(getDownloadGroupEntity(key, null)); - } else if (dgTaskEntity.getEntity() == null || TextUtils.isEmpty( - dgTaskEntity.getEntity().getKey())) { - dgTaskEntity.setEntity(getDownloadGroupEntity(key, null)); - } - dgTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(key); - return dgTaskEntity; - } else { - dgTaskEntity = new DownloadGroupTaskEntity(); - dgTaskEntity.setEntity(getDownloadGroupEntity(key, null)); - dgTaskEntity.urlEntity = CommonUtil.getFtpUrlInfo(key); - return dgTaskEntity; - } - } - - @Override public DownloadGroupTaskEntity create(String groupName, List urls) { - return create(getDownloadGroupEntity(groupName, urls)); - } - - /** - * 查询任务组实体,如果数据库不存在该实体,则新创建一个新的任务组实体 - */ - private DownloadGroupEntity getDownloadGroupEntity(String groupName, List urls) { - - List wrapper = - DbEntity.findRelationData(DownloadGroupWrapper.class, "DownloadGroupEntity.groupName=?", - groupName); - DownloadGroupEntity groupEntity; - if (wrapper != null && !wrapper.isEmpty()) { - groupEntity = wrapper.get(0).groupEntity; - if (groupEntity == null) { - groupEntity = new DownloadGroupEntity(); - } - } else { - groupEntity = new DownloadGroupEntity(); - } - groupEntity.setGroupName(groupName); - groupEntity.setUrls(urls); - return groupEntity; - } -} diff --git a/Aria/src/main/java/com/arialyy/aria/core/manager/DTEntityFactory.java b/Aria/src/main/java/com/arialyy/aria/core/manager/DTEFactory.java similarity index 78% rename from Aria/src/main/java/com/arialyy/aria/core/manager/DTEntityFactory.java rename to Aria/src/main/java/com/arialyy/aria/core/manager/DTEFactory.java index 6ec6eb63..b958f11e 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/manager/DTEntityFactory.java +++ b/Aria/src/main/java/com/arialyy/aria/core/manager/DTEFactory.java @@ -18,7 +18,7 @@ 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.DownloadTaskWrapper; +import com.arialyy.aria.core.download.wrapper.DownloadTaskWrapper; import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.orm.DbEntity; import java.io.File; @@ -28,17 +28,17 @@ import java.util.List; * Created by Aria.Lao on 2017/11/1. * 任务实体工厂 */ -class DTEntityFactory implements ITEntityFactory { - private static final String TAG = "DTEntityFactory"; - private static volatile DTEntityFactory INSTANCE = null; +class DTEFactory implements INormalTEFactory { + 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; @@ -51,22 +51,21 @@ class DTEntityFactory implements ITEntityFactory wrapper = DbEntity.findRelationData(DownloadTaskWrapper.class, "DownloadTaskEntity.key=? and DownloadTaskEntity.isGroupTask='false' and DownloadTaskEntity.url=?", entity.getDownloadPath(), entity.getUrl()); - + DownloadTaskEntity taskEntity; if (wrapper != null && !wrapper.isEmpty()) { - DownloadTaskEntity taskEntity = wrapper.get(0).taskEntity; + taskEntity = wrapper.get(0).taskEntity; if (taskEntity == null) { taskEntity = new DownloadTaskEntity(); - taskEntity.entity = entity; } else if (taskEntity.entity == null || TextUtils.isEmpty(taskEntity.entity.getUrl())) { taskEntity.entity = entity; } - - return taskEntity; } else { - DownloadTaskEntity taskEntity = new DownloadTaskEntity(); - taskEntity.entity = entity; - return taskEntity; + taskEntity = new DownloadTaskEntity(); } + taskEntity.key = entity.getDownloadPath(); + taskEntity.url = entity.getUrl(); + taskEntity.entity = entity; + return taskEntity; } /** @@ -89,6 +88,7 @@ class DTEntityFactory implements ITEntityFactory> { +interface IGTEFactory> { /** - * 通过key创建任务 + * 获取任务组的任务实体, + * 1、创建实体和任务实体之间的关联 + * 2、如果在数据库中查找不到对应的数据,则新创建任务实体 + * + * @param groupName 任务组名 + * @param urls 子任务的下载地址 */ - TASK_ENTITY create(String groupName, List urls); + TASK_ENTITY getGTE(String groupName, List urls); + + /** + * 获取FTP文件夹的任务实体,该方法需要以下操作: + * 1、创建实体和任务实体之间的关联 + * 2、如果在数据库中查找不到对应的数据,则新创建任务实体 + * + * @param ftpUrl ftp文件夹下载路径 + */ + TASK_ENTITY getFTE(String ftpUrl); } diff --git a/Aria/src/main/java/com/arialyy/aria/core/manager/ITEntityFactory.java b/Aria/src/main/java/com/arialyy/aria/core/manager/INormalTEFactory.java similarity index 90% rename from Aria/src/main/java/com/arialyy/aria/core/manager/ITEntityFactory.java rename to Aria/src/main/java/com/arialyy/aria/core/manager/INormalTEFactory.java index d5d2b97d..b55ddcf7 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/manager/ITEntityFactory.java +++ b/Aria/src/main/java/com/arialyy/aria/core/manager/INormalTEFactory.java @@ -21,7 +21,7 @@ import com.arialyy.aria.core.inf.AbsTaskEntity; /** * Created by Aria.Lao on 2017/11/1. */ -interface ITEntityFactory> { +interface INormalTEFactory> { /** * 通过key创建任务,只适应于单任务 diff --git a/Aria/src/main/java/com/arialyy/aria/core/manager/TEManager.java b/Aria/src/main/java/com/arialyy/aria/core/manager/TEManager.java index 3ed9f3c1..daba832d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/manager/TEManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/manager/TEManager.java @@ -50,18 +50,17 @@ public class TEManager { } /** - * 通过key创建任务,只适应于单任务,不能用于HTTP任务组,可用于Ftp文件夹 - * 如果是任务组,请使用{@link #createGTEntity(Class, List)} + * 通过key创建任务,只适应于单任务 * * @return 如果任务实体创建失败,返回null */ - public TE createTEntity(Class clazz, String key) { + private TE createNormalTE(Class 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; @@ -76,23 +75,44 @@ public class TEManager { } /** - * 创建任务组实体 + * 通过key创建不需要缓存的任务实体,只适应于单任务 * * @return 如果任务实体创建失败,返回null */ - public TE createGTEntity(Class clazz, List urls) { + public TE createNormalNoCacheTE(Class 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 createGTEntity(Class clazz, List 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; @@ -101,26 +121,49 @@ public class TEManager { } } - private IGTEntityFactory chooseGroupFactory(Class clazz) { + /** + * 通过ftp文件夹路径,创建FTP文件夹实体 + * + * @return 如果任务实体创建失败,返回null + */ + private TE createFDTE(Class clazz, String key) { + final Lock lock = this.lock; + lock.lock(); + try { + AbsTaskEntity tEntity = cache.get(convertKey(key)); + if (tEntity == null || tEntity.getClass() != clazz) { + IGTEFactory factory = chooseGroupFactory(clazz); + if (factory == null) { + ALog.e(TAG, "任务实体创建失败"); + return null; + } + tEntity = factory.getFTE(key); + cache.put(convertKey(key), tEntity); + } + return (TE) tEntity; + } finally { + lock.unlock(); + } + } + + 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 */ @@ -130,7 +173,27 @@ public class TEManager { try { AbsTaskEntity tEntity = cache.get(convertKey(key)); if (tEntity == null) { - return createTEntity(clazz, key); + return createNormalTE(clazz, key); + } else { + return (TE) tEntity; + } + } finally { + lock.unlock(); + } + } + + /** + * 从缓存中获取FTP文件夹任务实体,如果任务实体不存在,则创建任务实体 + * + * @return 创建失败,返回null + */ + public TE getFDTEntity(Class 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; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/manager/UTEntityFactory.java b/Aria/src/main/java/com/arialyy/aria/core/manager/UTEFactory.java similarity index 88% rename from Aria/src/main/java/com/arialyy/aria/core/manager/UTEntityFactory.java rename to Aria/src/main/java/com/arialyy/aria/core/manager/UTEFactory.java index fa2e8a60..9f2e60cb 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/manager/UTEntityFactory.java +++ b/Aria/src/main/java/com/arialyy/aria/core/manager/UTEFactory.java @@ -28,17 +28,17 @@ import java.util.regex.Pattern; * Created by Aria.Lao on 2017/11/1. * 任务实体工厂 */ -class UTEntityFactory implements ITEntityFactory { - private static final String TAG = "DTEntityFactory"; - private static volatile UTEntityFactory INSTANCE = null; +class UTEFactory implements INormalTEFactory { + 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; diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java index 5a747bae..eca4d68f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseNormalTarget.java @@ -69,7 +69,8 @@ abstract class BaseNormalTarget @Override protected boolean checkEntity() { boolean b = checkUrl() && checkFilePath(); if (b) { - mTaskEntity.save(mEntity); + mEntity.save(); + mTaskEntity.save(); } return b; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java index 48aa5b73..eeb07b4f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java @@ -140,7 +140,7 @@ class BaseUListener List findRelationData(Class clazz, String... expression) { + public static List findRelationData(Class clazz, + String... expression) { return DelegateWrapper.getInstance().findRelationData(clazz, expression); } @@ -114,20 +109,6 @@ public abstract class DbEntity { return datas == null ? null : datas.size() > 0 ? datas.get(0) : null; } - /** - * 获取所有行的rowid - */ - public int[] getRowIds() { - return DelegateWrapper.getInstance().getRowId(getClass()); - } - - /** - * 获取rowid - */ - public int getRowId(@NonNull Object[] wheres, @NonNull Object[] values) { - return DelegateWrapper.getInstance().getRowId(getClass(), wheres, values); - } - /** * 删除当前数据 */ @@ -155,6 +136,7 @@ public abstract class DbEntity { /** * 保存自身,如果表中已经有数据,则更新数据,否则插入数据 + * 只有 target中checkEntity成功后才能保存,创建实体部分也不允许保存 */ public void save() { synchronized (LOCK) { @@ -171,50 +153,13 @@ public abstract class DbEntity { */ private boolean thisIsExist() { DelegateWrapper util = DelegateWrapper.getInstance(); - return util.isExist(getClass(), rowID); + return rowID != -1 && util.isExist(getClass(), rowID); } /** - * 插入数据 + * 插入数据,只有 target中checkEntity成功后才能插入,创建实体部分也不允许操作 */ public void insert() { DelegateWrapper.getInstance().insertData(this); - updateRowID(); - } - - private void updateRowID() { - try { - List fields = CommonUtil.getAllFields(getClass()); - StringBuilder sb = new StringBuilder(); - List params = new ArrayList<>(); - List values = new ArrayList<>(); - for (Field field : fields) { - field.setAccessible(true); - if (SqlUtil.isIgnore(field)) { - continue; - } - sb.append(field.getName()).append("=? AND "); - Type type = field.getType(); - if (type == List.class) { - values.add(SqlUtil.list2Str(this, field)); - } else if (type == Map.class) { - values.add(SqlUtil.map2Str((Map) field.get(this))); - } else { - values.add(field.get(this) + ""); - } - } - - String temp = sb.toString(); - String p = temp.substring(0, temp.length() - 5); - - params.add(p); - params.addAll(values); - DbEntity entity = findFirst(getClass(), params.toArray(new String[params.size()])); - if (entity != null) { - rowID = entity.rowID; - } - } catch (IllegalAccessException e) { - e.printStackTrace(); - } } } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java b/Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java index 98a5866d..89c9916f 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/DelegateFind.java @@ -500,7 +500,7 @@ class DelegateFind extends AbsDelegate { * 通过rowId判断数据是否存在 */ boolean itemExist(SQLiteDatabase db, Class clazz, - int rowId) { + long rowId) { db = checkDb(db); String sql = "SELECT rowid FROM " + CommonUtil.getClassName(clazz) + " WHERE rowid=" + rowId; print(ROW_ID, sql); diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java b/Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java index d697f5f0..41e94823 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/DelegateUpdate.java @@ -15,9 +15,11 @@ */ package com.arialyy.aria.orm; +import android.content.ContentValues; import android.database.sqlite.SQLiteDatabase; import android.text.TextUtils; import com.arialyy.aria.orm.annotation.Primary; +import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CommonUtil; import java.lang.reflect.Field; @@ -61,10 +63,7 @@ class DelegateUpdate extends AbsDelegate { List fields = CommonUtil.getAllFields(clazz); DbEntity cacheEntity = mDataCache.get(getCacheKey(dbEntity)); if (fields != null && fields.size() > 0) { - StringBuilder sql = new StringBuilder(); - StringBuilder prams = new StringBuilder(); - sql.append("UPDATE ").append(CommonUtil.getClassName(dbEntity)).append(" SET "); - int i = 0; + ContentValues values = new ContentValues(); try { for (Field field : fields) { field.setAccessible(true); @@ -76,10 +75,7 @@ class DelegateUpdate extends AbsDelegate { && !field.getName().equals("state")) { //在LruCache中 state字段总是不能重新赋值... continue; } - String value; - prams.append(i > 0 ? ", " : ""); - prams.append(field.getName()).append("='"); Type type = field.getType(); if (type == Map.class && checkMap(field)) { value = SqlUtil.map2Str((Map) field.get(dbEntity)); @@ -89,19 +85,17 @@ class DelegateUpdate extends AbsDelegate { Object obj = field.get(dbEntity); value = obj == null ? "" : convertValue(obj.toString()); } - - prams.append(TextUtils.isEmpty(value) ? "" : value); - prams.append("'"); - i++; + values.put(field.getName(), value); } } catch (IllegalAccessException e) { e.printStackTrace(); } - if (!TextUtils.isEmpty(prams.toString())) { - sql.append(prams.toString()); - sql.append(" where rowid=").append(dbEntity.rowID); - print(MODIFY_DATA, sql.toString()); - db.execSQL(sql.toString()); + //print(MODIFY_DATA, sql.toString()); + if (values.size() > 0) { + db.update(CommonUtil.getClassName(dbEntity), values, "rowid=?", + new String[] { String.valueOf(dbEntity.rowID) }); + } else { + ALog.d(TAG, "没有数据更新"); } } mDataCache.put(getCacheKey(dbEntity), dbEntity); @@ -116,48 +110,32 @@ class DelegateUpdate extends AbsDelegate { Class clazz = dbEntity.getClass(); List fields = CommonUtil.getAllFields(clazz); if (fields != null && fields.size() > 0) { - StringBuilder sb = new StringBuilder(); - sb.append("INSERT INTO ").append(CommonUtil.getClassName(dbEntity)).append("("); - int i = 0; + ContentValues values = new ContentValues(); try { for (Field field : fields) { field.setAccessible(true); if (isIgnore(dbEntity, field)) { continue; } - sb.append(i > 0 ? ", " : ""); - sb.append(field.getName()); - i++; - } - sb.append(") VALUES ("); - i = 0; - for (Field field : fields) { - field.setAccessible(true); - if (isIgnore(dbEntity, field)) { - continue; - } - sb.append(i > 0 ? ", " : ""); - sb.append("'"); + String value = null; Type type = field.getType(); if (type == Map.class && checkMap(field)) { - sb.append(SqlUtil.map2Str((Map) field.get(dbEntity))); + value = SqlUtil.map2Str((Map) field.get(dbEntity)); } else if (type == List.class && checkList(field)) { - sb.append(SqlUtil.list2Str(dbEntity, field)); + value = SqlUtil.list2Str(dbEntity, field); } else { Object obj = field.get(dbEntity); if (obj != null) { - sb.append(convertValue(field.get(dbEntity).toString())); + value = convertValue(field.get(dbEntity).toString()); } } - sb.append("'"); - i++; + values.put(field.getName(), value); } } catch (IllegalAccessException e) { e.printStackTrace(); } - sb.append(")"); - print(INSERT_DATA, sb.toString()); - db.execSQL(sb.toString()); + //print(INSERT_DATA, ); + dbEntity.rowID = db.insert(CommonUtil.getClassName(dbEntity), null, values); } close(db); } @@ -169,18 +147,33 @@ class DelegateUpdate extends AbsDelegate { if (SqlUtil.isIgnore(field)) { return true; } - if (SqlUtil.isPrimary(field)) { //忽略自动增长的主键 - Primary p = field.getAnnotation(Primary.class); - if (p.autoincrement()) { + Object value = field.get(obj); + if (value == null) { // 忽略为空的字段 + return true; + } + if (value instanceof String) { + if (TextUtils.isEmpty(String.valueOf(value))) { return true; } } - if (SqlUtil.isForeign(field)) { //忽略外键为null的字段 - Object value = field.get(obj); - if (value == null || (value instanceof String && TextUtils.isEmpty(String.valueOf(value)))) { + if (value instanceof List) { + if (((List) value).size() == 0) { return true; } } + if (value instanceof Map) { + if (((Map) value).size() == 0) { + return true; + } + } + + if (SqlUtil.isPrimary(field)) { //忽略自动增长的主键 + Primary p = field.getAnnotation(Primary.class); + if (p.autoincrement()) { + return true; + } + } + return false; } } diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java b/Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java index ca33e472..6a817885 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/DelegateWrapper.java @@ -121,7 +121,7 @@ public class DelegateWrapper { /** * 通过rowId判断数据是否存在 */ - boolean isExist(Class clazz, int rowId) { + boolean isExist(Class clazz, long rowId) { return mDManager.getDelegate(DelegateFind.class).itemExist(mDb, clazz, rowId); } diff --git a/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java b/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java index 5231d09a..f4560755 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java @@ -36,7 +36,7 @@ final class SqlHelper extends SQLiteOpenHelper { /** * 是否将数据库保存在Sd卡,{@code true} 是 */ - private static final boolean SAVE_IN_SDCARD = false; + private static final boolean SAVE_IN_SDCARD = true; static volatile SqlHelper INSTANCE = null; diff --git a/Aria/src/main/java/com/arialyy/aria/orm/annotation/Many.java b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Many.java index 59d5367c..03f6fd72 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/annotation/Many.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/annotation/Many.java @@ -34,4 +34,11 @@ import java.lang.annotation.Target; * 父表在子表对应的字段 */ String entityColumn(); + + ///** + // * 是否是一对一关系 + // * + // * @return {@code true} 是,{@code false} 不是 + // */ + //boolean isOne2One() default false; } diff --git a/Aria/src/main/java/com/arialyy/aria/util/ALog.java b/Aria/src/main/java/com/arialyy/aria/util/ALog.java index c49a1ca9..d7c7081f 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/ALog.java +++ b/Aria/src/main/java/com/arialyy/aria/util/ALog.java @@ -19,6 +19,12 @@ package com.arialyy.aria.util; import android.text.TextUtils; import android.util.Log; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; /** * Created by Aria.Lao on 2017/10/25. @@ -61,6 +67,50 @@ public class ALog { return println(Log.ERROR, tag, getExceptionString(e)); } + /** + * 打印MAp,debug级别日志 + */ + public static void m(String tag, Map map) { + if (LOG_LEVEL <= Log.DEBUG) { + Set set = map.entrySet(); + if (set.size() < 1) { + d(tag, "[]"); + return; + } + int i = 0; + String[] s = new String[set.size()]; + for (Object aSet : set) { + Map.Entry entry = (Map.Entry) aSet; + s[i] = entry.getKey() + " = " + entry.getValue() + ",\n"; + i++; + } + println(Log.DEBUG, tag, Arrays.toString(s)); + } + } + + /** + * 打印JSON,debug级别日志 + */ + public static void j(String tag, String jsonStr) { + if (LOG_LEVEL <= Log.DEBUG) { + String message; + try { + if (jsonStr.startsWith("{")) { + JSONObject jsonObject = new JSONObject(jsonStr); + message = jsonObject.toString(4); //这个是核心方法 + } else if (jsonStr.startsWith("[")) { + JSONArray jsonArray = new JSONArray(jsonStr); + message = jsonArray.toString(4); + } else { + message = jsonStr; + } + } catch (JSONException e) { + message = jsonStr; + } + println(Log.DEBUG, tag, message); + } + } + /** * 将异常信息转换为字符串 */ diff --git a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java index eb9da319..131a3a4f 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java @@ -318,7 +318,7 @@ public class CommonUtil { return; } - for (DownloadEntity taskEntity : groupEntity.getSubTask()) { + for (DownloadEntity taskEntity : groupEntity.getSubEntities()) { delDownloadTaskConfig(removeFile, taskEntity); } @@ -767,7 +767,7 @@ public class CommonUtil { return; } File file = new File(path); - if (!file.getParentFile().exists()) { + if (file.getParentFile() == null || !file.getParentFile().exists()) { ALog.d(TAG, "目标文件所在路径不存在,准备创建……"); if (!createDir(file.getParent())) { ALog.d(TAG, "创建目录文件所在的目录失败!文件路径【" + path + "】"); diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6730d35c..18cc4fd4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,8 +14,10 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme.NoActionBar"> + + diff --git a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java index cd0aade9..d98d94b7 100644 --- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java @@ -46,7 +46,6 @@ public class SingleTaskActivity extends BaseActivity { //"http://kotlinlang.org/docs/kotlin-docs.pdf"; //"https://atom-installer.github.com/v1.13.0/AtomSetup.exe?s=1484074138&ext=.exe"; //"http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk"; - //不支持断点的链接 "http://58.210.9.131/tpk/sipgt//TDLYZTGH.tpk"; //chunked 下载 //"https://static.donguo.me//video/ip/course/pfys_1.mp4"; @Bind(R.id.start) Button mStart; diff --git a/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java b/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java index 7140a086..b0527c6f 100644 --- a/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java @@ -48,7 +48,7 @@ public class DownloadGroupActivity extends BaseActivity getUrls() { + public List getUrls() { List urls = new ArrayList<>(); String[] str = getContext().getResources().getStringArray(R.array.group_urls_1); Collections.addAll(urls, str); @@ -44,7 +44,7 @@ public class GroupModule extends BaseModule { return urls; } - List getSubName(){ + List getSubName() { List names = new ArrayList<>(); String[] str = getContext().getResources().getStringArray(R.array.group_names); Collections.addAll(names, str); diff --git a/app/src/main/java/com/arialyy/simple/download/multi_download/DownloadAdapter.java b/app/src/main/java/com/arialyy/simple/download/multi_download/DownloadAdapter.java index 83b75caa..db4284ac 100644 --- a/app/src/main/java/com/arialyy/simple/download/multi_download/DownloadAdapter.java +++ b/app/src/main/java/com/arialyy/simple/download/multi_download/DownloadAdapter.java @@ -217,9 +217,9 @@ public class DownloadAdapter extends AbsRVAdapter 0) { - holder.childList.updateChildProgress(((DownloadGroupEntity) entity).getSubTask()); + holder.childList.updateChildProgress(((DownloadGroupEntity) entity).getSubEntities()); } else { - holder.childList.addData(((DownloadGroupEntity) entity).getSubTask()); + holder.childList.addData(((DownloadGroupEntity) entity).getSubEntities()); } } diff --git a/app/src/main/java/com/arialyy/simple/test/TestActivity.java b/app/src/main/java/com/arialyy/simple/test/TestActivity.java new file mode 100644 index 00000000..3f1f88d9 --- /dev/null +++ b/app/src/main/java/com/arialyy/simple/test/TestActivity.java @@ -0,0 +1,92 @@ +package com.arialyy.simple.test; + +import android.os.Bundle; +import android.os.Environment; +import android.util.Log; +import android.view.View; +import com.arialyy.annotations.Download; +import com.arialyy.aria.core.Aria; +import com.arialyy.aria.core.common.RequestEnum; +import com.arialyy.aria.core.download.DownloadTask; +import com.arialyy.aria.util.CommonUtil; +import com.arialyy.frame.util.show.L; +import com.arialyy.simple.R; +import com.arialyy.simple.base.BaseActivity; +import com.arialyy.simple.databinding.ActivityTestBinding; +import java.io.File; + +/** + * Created by Administrator on 2018/4/12. + */ + +public class TestActivity extends BaseActivity { + String TAG = "TestActivity"; + String URL = "http://58.210.9.131/tpk/sipgt//TDLYZTGH.tpk"; //chunked 下载 + + @Override protected int setLayoutId() { + return R.layout.activity_test; + } + + @Override protected void init(Bundle savedInstanceState) { + super.init(savedInstanceState); + mBar.setVisibility(View.GONE); + Aria.download(this).register(); + } + + @Download.onWait void onWait(DownloadTask task) { + Log.d(TAG, "wait ==> " + task.getDownloadEntity().getFileName()); + } + + @Download.onPre protected void onPre(DownloadTask task) { + Log.d(TAG, "onPre"); + } + + @Download.onTaskStart void taskStart(DownloadTask task) { + Log.d(TAG, "onStart"); + } + + @Download.onTaskRunning protected void running(DownloadTask task) { + Log.d(TAG, "running"); + } + + @Download.onTaskResume void taskResume(DownloadTask task) { + Log.d(TAG, "resume"); + } + + @Download.onTaskStop void taskStop(DownloadTask task) { + Log.d(TAG, "stop"); + } + + @Download.onTaskCancel void taskCancel(DownloadTask task) { + Log.d(TAG, "cancel"); + } + + @Download.onTaskFail void taskFail(DownloadTask task) { + Log.d(TAG, "fail"); + } + + @Download.onTaskComplete void taskComplete(DownloadTask task) { + L.d(TAG, "path ==> " + task.getDownloadEntity().getDownloadPath()); + L.d(TAG, "md5Code ==> " + CommonUtil.getFileMD5(new File(task.getDownloadPath()))); + } + + public void onClick(View view) { + switch (view.getId()) { + case R.id.start: + Aria.download(this) + .load(URL) + .addHeader("Accept-Encoding", "gzip, deflate") + .setRequestMode(RequestEnum.GET) + .setFilePath(Environment.getExternalStorageDirectory().getPath() + "/ggsg1.apk") + .resetState() + .start(); + break; + case R.id.stop: + Aria.download(this).load(URL).stop(); + break; + case R.id.cancel: + Aria.download(this).load(URL).cancel(); + break; + } + } +} diff --git a/app/src/main/java/com/arialyy/simple/test/TestGroupActivity.java b/app/src/main/java/com/arialyy/simple/test/TestGroupActivity.java new file mode 100644 index 00000000..d8455218 --- /dev/null +++ b/app/src/main/java/com/arialyy/simple/test/TestGroupActivity.java @@ -0,0 +1,91 @@ +package com.arialyy.simple.test; + +import android.os.Bundle; +import android.os.Environment; +import android.view.View; +import com.arialyy.annotations.DownloadGroup; +import com.arialyy.aria.core.Aria; +import com.arialyy.aria.core.download.DownloadGroupTask; +import com.arialyy.frame.util.show.L; +import com.arialyy.simple.R; +import com.arialyy.simple.base.BaseActivity; +import com.arialyy.simple.databinding.ActivityTestBinding; +import com.arialyy.simple.download.group.GroupModule; +import java.util.List; + +/** + * Created by Administrator on 2018/4/12. + */ + +public class TestGroupActivity extends BaseActivity { + List mUrls; + + @Override protected int setLayoutId() { + return R.layout.activity_test; + } + + @Override protected void init(Bundle savedInstanceState) { + super.init(savedInstanceState); + mBar.setVisibility(View.GONE); + Aria.download(this).register(); + mUrls = getModule(GroupModule.class).getUrls(); + } + + @DownloadGroup.onWait void taskWait(DownloadGroupTask task) { + L.d(TAG, task.getTaskName() + "wait"); + } + + @DownloadGroup.onPre() protected void onPre(DownloadGroupTask task) { + L.d(TAG, "group pre"); + } + + @DownloadGroup.onTaskPre() protected void onTaskPre(DownloadGroupTask task) { + L.d(TAG, "group task pre"); + } + + @DownloadGroup.onTaskStart() void taskStart(DownloadGroupTask task) { + L.d(TAG, "group task start"); + } + + @DownloadGroup.onTaskRunning() protected void running(DownloadGroupTask task) { + L.d(TAG, "group task running"); + } + + @DownloadGroup.onTaskResume() void taskResume(DownloadGroupTask task) { + L.d(TAG, "group task resume"); + } + + @DownloadGroup.onTaskStop() void taskStop(DownloadGroupTask task) { + L.d(TAG, "group task stop"); + } + + @DownloadGroup.onTaskCancel() void taskCancel(DownloadGroupTask task) { + L.d(TAG, "group task cancel"); + } + + @DownloadGroup.onTaskFail() void taskFail(DownloadGroupTask task) { + L.d(TAG, "group task fail"); + } + + @DownloadGroup.onTaskComplete() void taskComplete(DownloadGroupTask task) { + L.d(TAG, "group task complete"); + } + + public void onClick(View view) { + switch (view.getId()) { + case R.id.start: + Aria.download(this) + .loadGroup(mUrls) + .setDirPath(Environment.getExternalStorageDirectory().getPath() + "/download/test/") + .resetState() + .start(); + break; + case R.id.stop: + Aria.download(this).loadGroup(mUrls).stop(); + break; + case R.id.cancel: + Aria.download(this).loadGroup(mUrls).cancel(); + break; + } + } +} diff --git a/app/src/main/res/layout/activity_test.xml b/app/src/main/res/layout/activity_test.xml new file mode 100644 index 00000000..b5b4cf62 --- /dev/null +++ b/app/src/main/res/layout/activity_test.xml @@ -0,0 +1,40 @@ + + + + + + +