From cd964d600e3b46a05fcf7a2e83679d2de0d75f68 Mon Sep 17 00:00:00 2001 From: AriaLyy <511455842@qq.com> Date: Sat, 17 Jun 2017 14:31:26 +0800 Subject: [PATCH 01/34] =?UTF-8?q?=E4=BF=AE=E5=A4=8Das=E7=83=AD=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E5=B4=A9=E6=BA=83=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Aria/build.gradle | 2 +- Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java | 3 +-- Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java | 2 +- app/build.gradle | 2 +- build.gradle | 1 + gradle/wrapper/gradle-wrapper.properties | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Aria/build.gradle b/Aria/build.gradle index 7b8287a2..9f7b3b26 100644 --- a/Aria/build.gradle +++ b/Aria/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.library' android { compileSdkVersion 23 - buildToolsVersion '25.0.2' + buildToolsVersion '25.0.3' defaultConfig { minSdkVersion 9 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 4378c2d8..fc42e75c 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java @@ -161,8 +161,7 @@ public class DbEntity { List values = new ArrayList<>(); for (Field field : fields) { field.setAccessible(true); - Ignore ignore = field.getAnnotation(Ignore.class); - if (ignore != null && ignore.value()) { + if (SqlHelper.ignoreField(field)) { continue; } where.add(field.getName()); 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 784900b1..0d643822 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java @@ -511,7 +511,7 @@ final class SqlHelper extends SQLiteOpenHelper { * @return true 忽略该字段 */ static boolean ignoreField(Field field) { - // field.isSynthetic(), 使用as热启动App时,AS会自动给你的clss添加change字段 + // field.isSynthetic(), 使用as热启动App时,AS会自动给你的class添加change字段 Ignore ignore = field.getAnnotation(Ignore.class); int modifiers = field.getModifiers(); return (ignore != null && ignore.value()) diff --git a/app/build.gradle b/app/build.gradle index 247814e2..e4a53267 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.application' android { compileSdkVersion 23 - buildToolsVersion '25.0.2' + buildToolsVersion '25.0.3' defaultConfig { applicationId "com.arialyy.simple" diff --git a/build.gradle b/build.gradle index d4da586b..36979409 100644 --- a/build.gradle +++ b/build.gradle @@ -5,6 +5,7 @@ buildscript { mavenCentral() } dependencies { +// classpath 'com.android.tools.build:gradle:2.3.0' classpath 'com.android.tools.build:gradle:2.2.2' // classpath 'com.novoda:bintray-release:0.5.0' // classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3aaadf68..e159d533 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,5 +3,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -#distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-all.zip -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-all.zip +#distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip From 97e671d83eca63a07254918b93ebf680854f8f6b Mon Sep 17 00:00:00 2001 From: AriaLyy <511455842@qq.com> Date: Mon, 19 Jun 2017 09:39:52 +0800 Subject: [PATCH 02/34] test --- .../java/com/arialyy/simple/test/TestMutilTaskSysDownload.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/arialyy/simple/test/TestMutilTaskSysDownload.java b/app/src/main/java/com/arialyy/simple/test/TestMutilTaskSysDownload.java index 71b235e5..530442a0 100644 --- a/app/src/main/java/com/arialyy/simple/test/TestMutilTaskSysDownload.java +++ b/app/src/main/java/com/arialyy/simple/test/TestMutilTaskSysDownload.java @@ -56,7 +56,6 @@ public class TestMutilTaskSysDownload extends BaseActivity Date: Mon, 19 Jun 2017 18:02:52 +0800 Subject: [PATCH 03/34] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E4=B8=AD=EF=BC=8C=E7=BD=91=E7=BB=9C=E6=96=AD=E5=BC=80=E4=B8=8D?= =?UTF-8?q?=E4=BC=9A=E9=87=8D=E8=AF=95=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/arialyy/aria/core/download/DownloadUtil.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java index 2f08ba86..183954e8 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java @@ -192,7 +192,6 @@ class DownloadUtil implements IDownloadUtil, Runnable { private void failDownload(String msg) { Log.e(TAG, msg); CONSTANCE.isDownloading = false; - stopDownload(); mListener.onFail(); } @@ -210,7 +209,7 @@ class DownloadUtil implements IDownloadUtil, Runnable { + mDownloadEntity.getDownloadUrl() + "】\n【filePath:" + mDownloadFile.getPath() - + "】" + + "】\n" + CommonUtil.getPrintException(e)); } } From 4d93bff81638569d711c2862897c085b16563dd5 Mon Sep 17 00:00:00 2001 From: laoyuyu <511455842@QQ.com> Date: Tue, 20 Jun 2017 17:40:09 +0800 Subject: [PATCH 04/34] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f1e78ebd..8e71303a 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ 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:3.1.9' +compile 'com.arialyy.aria:aria-core:3.1.9' annotationProcessor 'com.arialyy.aria:aria-compiler:3.1.9' ``` From da5fbcb462c25a51ebd84cf1352d734a804bb1e9 Mon Sep 17 00:00:00 2001 From: AriaLyy <511455842@qq.com> Date: Wed, 21 Jun 2017 23:48:29 +0800 Subject: [PATCH 05/34] https://github.com/AriaLyy/Aria/issues/57 --- .../com/arialyy/aria/core/AriaManager.java | 20 +++++++++++ .../com/arialyy/aria/core/ConfigHelper.java | 19 ++++++++++- .../java/com/arialyy/aria/core/QueueMod.java | 29 ++++++++++++++++ .../com/arialyy/aria/core/command/AbsCmd.java | 7 ++++ .../arialyy/aria/core/command/StartCmd.java | 21 +++++++++++- .../aria/core/download/DownloadReceiver.java | 6 ++++ .../arialyy/aria/core/queue/AbsTaskQueue.java | 4 +++ .../arialyy/aria/core/queue/ITaskQueue.java | 8 +++++ .../java/com/arialyy/aria/orm/SqlHelper.java | 3 ++ app/build.gradle | 4 +-- app/src/main/assets/aria_config.xml | 3 ++ .../simple/download/SingleTaskActivity.java | 2 +- .../simple/test/TestMutilTaskSysDownload.java | 33 +++++++++++-------- .../com/arialyy/aria/core/Configuration.java | 19 ++++++++++- 14 files changed, 159 insertions(+), 19 deletions(-) create mode 100644 Aria/src/main/java/com/arialyy/aria/core/QueueMod.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 dacb0aea..5bcad9cb 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java @@ -86,6 +86,26 @@ import org.xml.sax.SAXException; return mReceivers; } + /** + * 设置上传任务的执行队列类型 + * + * @param mod {@link com.arialyy.aria.core.QueueMod} + */ + public AriaManager setUploadQueueMod(QueueMod mod) { + mUConfig.setQueueMod(mod.tag); + return this; + } + + /** + * 设置下载任务的执行队列类型 + * + * @param mod {@link com.arialyy.aria.core.QueueMod} + */ + public AriaManager setDownloadQueueMod(QueueMod mod) { + mDConfig.setQueueMod(mod.tag); + return this; + } + /** * 如果需要在代码中修改下载配置,请使用以下方法 *
diff --git a/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java b/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java
index e4c94262..260d1d29 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java
@@ -86,16 +86,33 @@ class ConfigHelper extends DefaultHandler {
         case "maxSpeed":
           loadMaxSpeed(value);
           break;
+        case "queueMod":
+          loadQueueMod(value);
+          break;
       }
     }
   }
 
+  private void loadQueueMod(String value) {
+    String mod = "now";
+    if (!TextUtils.isEmpty(value) && (value.equalsIgnoreCase("now") || value.equalsIgnoreCase(
+        "wait"))) {
+      mod = value;
+    }
+    if (isDownloadConfig) {
+      mDownloadConfig.queueMod = mod;
+    }
+    if (isUploadConfig) {
+      mUploadConfig.queueMod = mod;
+    }
+  }
+
   private void loadMaxSpeed(String value) {
     double maxSpeed = 0.0;
     if (!TextUtils.isEmpty(value)) {
       maxSpeed = Double.parseDouble(value);
     }
-    if (isDownloadConfig){
+    if (isDownloadConfig) {
       mDownloadConfig.msxSpeed = maxSpeed;
     }
   }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/QueueMod.java b/Aria/src/main/java/com/arialyy/aria/core/QueueMod.java
new file mode 100644
index 00000000..70d02300
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/QueueMod.java
@@ -0,0 +1,29 @@
+package com.arialyy.aria.core;
+
+/**
+ * Created by Aria.Lao on 2017/6/21.
+ * 执行队列类型
+ */
+public enum QueueMod {
+  /**
+   * 等待模式,如果执行队列已经满了,再次使用start命令执行任务时,该任务会被添加到缓存队列中
+   * 当执行队列的任务完成时,将自动执行缓存队列中的任务
+   */
+  WAIT("wait"),
+
+  /**
+   * 立刻执行模式
+   * 如果执行队列已经满了,再次使用start命令执行任务时,该任务会添加到执行队列队尾,而原来执行队列的队首任务会停止
+   */
+  NOW("now");
+
+  String tag;
+
+  public String getTag() {
+    return tag;
+  }
+
+  QueueMod(String tag) {
+    this.tag = tag;
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
index 1107dbfd..a90d006e 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
@@ -39,6 +39,11 @@ public abstract class AbsCmd implements ICmd {
    * 能否执行命令
    */
   boolean canExeCmd = true;
+  /**
+   * 是否是下载任务的命令
+   * {@code true} 下载任务的命令,{@code false} 上传任务的命令
+   */
+  boolean isDownloadCmd = true;
 
   /**
    * @param targetName 产生任务的对象名
@@ -51,8 +56,10 @@ public abstract class AbsCmd implements ICmd {
     TAG = CommonUtil.getClassName(this);
     if (entity instanceof DownloadTaskEntity) {
       mQueue = DownloadTaskQueue.getInstance();
+      isDownloadCmd = true;
     } else if (entity instanceof UploadTaskEntity) {
       mQueue = UploadTaskQueue.getInstance();
+      isDownloadCmd = false;
     }
   }
 }
\ No newline at end of file
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java
index 82821ea8..284a5df8 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java
@@ -17,6 +17,9 @@
 package com.arialyy.aria.core.command;
 
 import android.text.TextUtils;
+import android.util.Log;
+import com.arialyy.aria.core.AriaManager;
+import com.arialyy.aria.core.QueueMod;
 import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
@@ -40,7 +43,23 @@ class StartCmd extends AbsCmd {
       if (!TextUtils.isEmpty(mTargetName)) {
         task.setTargetName(mTargetName);
       }
-      mQueue.startTask(task);
+      String mod;
+      int maxTaskNum;
+      AriaManager manager = AriaManager.getInstance(AriaManager.APP);
+      if (isDownloadCmd) {
+        mod = manager.getDownloadConfig().getQueueMod();
+        maxTaskNum = manager.getDownloadConfig().getMaxTaskNum();
+      } else {
+        mod = manager.getUploadConfig().getQueueMod();
+        maxTaskNum = manager.getUploadConfig().getMaxTaskNum();
+      }
+      if (mod.equals(QueueMod.NOW.getTag())) {
+        mQueue.startTask(task);
+      }else if (mod.equals(QueueMod.WAIT.getTag())){
+        if (mQueue.getExeTaskNum() < maxTaskNum){
+          mQueue.startTask(task);
+        }
+      }
     }
   }
 }
\ No newline at end of file
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 8f29f02f..9c12f140 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
@@ -18,6 +18,7 @@ package com.arialyy.aria.core.download;
 import android.support.annotation.NonNull;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.inf.ICmd;
+import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.IReceiver;
 import com.arialyy.aria.core.command.CmdFactory;
 import com.arialyy.aria.core.command.AbsCmd;
@@ -26,6 +27,7 @@ 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;
+import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -67,6 +69,10 @@ public class DownloadReceiver implements IReceiver {
     if (entity == null) {
       entity = new DownloadEntity();
     }
+    File file = new File(entity.getDownloadPath());
+    if (!file.exists()) {
+      entity.setState(IEntity.STATE_WAIT);
+    }
     entity.setDownloadUrl(downloadUrl);
     return new DownloadTarget(entity, targetName);
   }
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 625d28dd..eb133913 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
@@ -36,6 +36,10 @@ abstract class AbsTaskQueue mCachePool = new CachePool<>();
   ExecutePool mExecutePool;
 
+  @Override public boolean taskIsRunning(String key) {
+    return mExecutePool.getTask(key) != null;
+  }
+
   /**
    * 停止所有任务
    */
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
index 9c9bd7c0..538fc919 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
@@ -32,6 +32,14 @@ import com.arialyy.aria.core.upload.UploadTaskEntity;
  */
 public interface ITaskQueue {
 
+  /**
+   * 通过key判断任务是否正在执行
+   *
+   * @param key 下载链接,或上传文件的路径
+   * @return {@code true} 任务正在运行
+   */
+  boolean taskIsRunning(String key);
+
   /**
    * 停止所有任务
    */
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 0d643822..4920bef0 100644
--- a/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
+++ b/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
@@ -187,6 +187,7 @@ final class SqlHelper extends SQLiteOpenHelper {
     print(FIND_DATA, sql);
     Cursor cursor = db.rawQuery(sql, null);
     List data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
+    cursor.close();
     close(db);
     return data;
   }
@@ -215,6 +216,7 @@ final class SqlHelper extends SQLiteOpenHelper {
     print(FIND_DATA, sb.toString());
     Cursor cursor = db.rawQuery(sb.toString(), null);
     List data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
+    cursor.close();
     close(db);
     return data;
   }
@@ -229,6 +231,7 @@ final class SqlHelper extends SQLiteOpenHelper {
     print(FIND_ALL_DATA, sb.toString());
     Cursor cursor = db.rawQuery(sb.toString(), null);
     List data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
+    cursor.close();
     close(db);
     return data;
   }
diff --git a/app/build.gradle b/app/build.gradle
index e4a53267..58c03308 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -42,7 +42,7 @@ dependencies {
   compile 'com.squareup.okhttp3:okhttp:3.2.0'
   compile 'com.arialyy.frame:MVVM2:2.2.0'
   compile project(':Aria')
-//  compile 'com.arialyy.aria:aria-core:3.1.8'
-//  annotationProcessor 'com.arialyy.aria:aria-compiler:3.1.8'
+//  compile 'com.arialyy.aria:aria-core:3.1.9'
+//  annotationProcessor 'com.arialyy.aria:aria-compiler:3.1.9'
 
 }
diff --git a/app/src/main/assets/aria_config.xml b/app/src/main/assets/aria_config.xml
index f9ed36f3..9972caa4 100644
--- a/app/src/main/assets/aria_config.xml
+++ b/app/src/main/assets/aria_config.xml
@@ -34,6 +34,9 @@
     
     
 
+    
+    
+
   
 
   
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 6e3b468e..e96fd2c2 100644
--- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
+++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
@@ -153,7 +153,7 @@ public class SingleTaskActivity extends BaseActivity {
     switch (item.getItemId()) {
       case R.id.help:
         msg = "一些小知识点:\n"
-            + "1、你可以通过task.getKey().equals(DOWNLOAD_URL)判断是否是当前页面的下载,以防止progress乱跳\n"
+            + "1、你可以在注解中增加链接,用于指定被注解的方法只能被特定的下载任务回调,以防止progress乱跳\n"
             + "2、当遇到网络慢的情况时,你可以先使用onPre()更新UI界面,待连接成功时,再在onTaskPre()获取完整的task数据,然后给UI界面设置正确的数据\n"
             + "3、你可以在界面初始化时通过Aria.download(this).load(DOWNLOAD_URL).getPercent()等方法快速获取相关任务的一些数据";
         showMsgDialog("tip", msg);
diff --git a/app/src/main/java/com/arialyy/simple/test/TestMutilTaskSysDownload.java b/app/src/main/java/com/arialyy/simple/test/TestMutilTaskSysDownload.java
index 530442a0..45e659aa 100644
--- a/app/src/main/java/com/arialyy/simple/test/TestMutilTaskSysDownload.java
+++ b/app/src/main/java/com/arialyy/simple/test/TestMutilTaskSysDownload.java
@@ -3,6 +3,7 @@ package com.arialyy.simple.test;
 import android.os.Environment;
 import android.view.View;
 import com.arialyy.aria.core.Aria;
+import com.arialyy.aria.core.QueueMod;
 import com.arialyy.simple.R;
 import com.arialyy.simple.base.BaseActivity;
 import com.arialyy.simple.databinding.TestActivityMultiBinding;
@@ -54,20 +55,26 @@ public class TestMutilTaskSysDownload extends BaseActivity
Date: Thu, 22 Jun 2017 21:52:07 +0800
Subject: [PATCH 06/34] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/arialyy/aria/core/command/AbsCmd.java |  4 +--
 .../com/arialyy/aria/core/command/AddCmd.java |  6 ++--
 .../arialyy/aria/core/command/CancelCmd.java  |  6 ++--
 .../aria/core/command/HighestPriorityCmd.java |  4 +--
 .../aria/core/command/ResumeAllCmd.java       |  2 +-
 .../arialyy/aria/core/command/StartCmd.java   |  7 ++---
 .../arialyy/aria/core/command/StopCmd.java    |  6 ++--
 .../aria/core/download/DownloadUtil.java      |  2 +-
 .../aria/core/download/SingleThreadTask.java  | 26 +++++++++++-----
 .../arialyy/aria/core/inf/AbsTaskEntity.java  |  2 +-
 .../com/arialyy/aria/core/inf/IEntity.java    |  2 +-
 .../java/com/arialyy/aria/core/inf/ITask.java |  4 +--
 .../arialyy/aria/core/queue/AbsTaskQueue.java |  8 ++---
 .../aria/core/queue/DownloadTaskQueue.java    |  9 ++++--
 .../arialyy/aria/core/queue/ITaskQueue.java   | 30 +++++++++----------
 .../aria/core/queue/pool/CachePool.java       |  2 +-
 .../aria/core/queue/pool/ExecutePool.java     | 12 ++++----
 .../arialyy/aria/core/queue/pool/IPool.java   |  8 ++---
 .../aria/core/scheduler/AbsSchedulers.java    |  2 +-
 .../arialyy/simple/base/BaseApplication.java  |  9 ++++++
 .../simple/download/SingleTaskActivity.java   |  3 +-
 21 files changed, 88 insertions(+), 66 deletions(-)

diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
index a90d006e..8dc620c8 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
@@ -32,7 +32,7 @@ import com.arialyy.aria.util.CommonUtil;
  */
 public abstract class AbsCmd implements ICmd {
   ITaskQueue mQueue;
-  T mEntity;
+  T mTaskEntity;
   String TAG;
   String mTargetName;
   /**
@@ -52,7 +52,7 @@ public abstract class AbsCmd implements ICmd {
     canExeCmd = CheckUtil.checkCmdEntity(entity,
         !(this instanceof CancelCmd) || !(this instanceof StopCmd));
     mTargetName = targetName;
-    mEntity = entity;
+    mTaskEntity = entity;
     TAG = CommonUtil.getClassName(this);
     if (entity instanceof DownloadTaskEntity) {
       mQueue = DownloadTaskQueue.getInstance();
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java
index fe6d481b..4177dc1d 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java
@@ -33,10 +33,10 @@ class AddCmd extends AbsCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    ITask task = mQueue.getTask(mEntity.getEntity());
+    ITask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
-      mEntity.getEntity().setState(IEntity.STATE_WAIT);
-      mQueue.createTask(mTargetName, mEntity);
+      mTaskEntity.getEntity().setState(IEntity.STATE_WAIT);
+      mQueue.createTask(mTargetName, mTaskEntity);
     } else {
       Log.w(TAG, "添加命令执行失败,【该任务已经存在】");
     }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/CancelCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/CancelCmd.java
index ad2aecd8..fd51ad14 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/CancelCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/CancelCmd.java
@@ -31,15 +31,15 @@ class CancelCmd extends AbsCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    ITask task = mQueue.getTask(mEntity.getEntity());
+    ITask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
-      task = mQueue.createTask(mTargetName, mEntity);
+      task = mQueue.createTask(mTargetName, mTaskEntity);
     }
     if (task != null) {
       if (!TextUtils.isEmpty(mTargetName)) {
         task.setTargetName(mTargetName);
       }
-      mQueue.cancelTask(task);
+      mQueue.removeTask(task);
     }
   }
 }
\ No newline at end of file
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/HighestPriorityCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/HighestPriorityCmd.java
index 74999611..57dc35bb 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/HighestPriorityCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/HighestPriorityCmd.java
@@ -39,9 +39,9 @@ final class HighestPriorityCmd extends AbsCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    ITask task = mQueue.getTask(mEntity.getEntity());
+    ITask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
-      task = mQueue.createTask(mTargetName, mEntity);
+      task = mQueue.createTask(mTargetName, mTaskEntity);
     }
     if (task != null) {
       if (!TextUtils.isEmpty(mTargetName)) {
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/ResumeAllCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/ResumeAllCmd.java
index c7110077..cb87dee7 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/ResumeAllCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/ResumeAllCmd.java
@@ -27,7 +27,7 @@ final class ResumeAllCmd extends AbsCmd {
     List allEntity =
         DbEntity.findDatas(DownloadEntity.class, "state=?", IEntity.STATE_STOP + "");
     for (DownloadEntity entity : allEntity) {
-      int exeNum = mQueue.getExeTaskNum();
+      int exeNum = mQueue.getExePoolSize();
       if (exeNum == 0 || exeNum < mQueue.getMaxTaskNum()) {
         ITask task = createTask(entity);
         mQueue.startTask(task);
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java
index 284a5df8..a9a3d180 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java
@@ -17,7 +17,6 @@
 package com.arialyy.aria.core.command;
 
 import android.text.TextUtils;
-import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.QueueMod;
 import com.arialyy.aria.core.inf.ITask;
@@ -35,9 +34,9 @@ class StartCmd extends AbsCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    ITask task = mQueue.getTask(mEntity.getEntity());
+    ITask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
-      task = mQueue.createTask(mTargetName, mEntity);
+      task = mQueue.createTask(mTargetName, mTaskEntity);
     }
     if (task != null) {
       if (!TextUtils.isEmpty(mTargetName)) {
@@ -56,7 +55,7 @@ class StartCmd extends AbsCmd {
       if (mod.equals(QueueMod.NOW.getTag())) {
         mQueue.startTask(task);
       }else if (mod.equals(QueueMod.WAIT.getTag())){
-        if (mQueue.getExeTaskNum() < maxTaskNum){
+        if (mQueue.getExePoolSize() < maxTaskNum){
           mQueue.startTask(task);
         }
       }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/StopCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/StopCmd.java
index 1e1fb295..8712d6cc 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/StopCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/StopCmd.java
@@ -34,10 +34,10 @@ class StopCmd extends AbsCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    ITask task = mQueue.getTask(mEntity.getEntity());
+    ITask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
-      if (mEntity.getEntity().getState() == IEntity.STATE_RUNNING) {
-        task = mQueue.createTask(mTargetName, mEntity);
+      if (mTaskEntity.getEntity().getState() == IEntity.STATE_RUNNING) {
+        task = mQueue.createTask(mTargetName, mTaskEntity);
         mQueue.stopTask(task);
       } else {
         Log.w(TAG, "停止命令执行失败,【调度器中没有该任务】");
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
index 183954e8..d82975b1 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
@@ -21,7 +21,6 @@ import android.util.Log;
 import android.util.SparseArray;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.util.BufferedRandomAccessFile;
-import com.arialyy.aria.util.CheckUtil;
 import com.arialyy.aria.util.CommonUtil;
 import java.io.File;
 import java.io.IOException;
@@ -371,6 +370,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
         new BufferedRandomAccessFile(new File(mDownloadFile.getPath()), "rwd", 8192);
     //设置文件长度
     file.setLength(fileLength);
+    file.close();
     mListener.onPostPre(fileLength);
     //分配每条线程的下载区间
     pro = CommonUtil.loadConfig(mConfigFile);
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java
index b6233744..5d3cd840 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java
@@ -76,8 +76,9 @@ final class SingleThreadTask implements Runnable {
   }
 
   @Override public void run() {
-    HttpURLConnection conn;
-    InputStream is;
+    HttpURLConnection conn = null;
+    InputStream is = null;
+    BufferedRandomAccessFile file = null;
     try {
       URL url = new URL(mConfigEntity.DOWNLOAD_URL);
       conn = ConnectionHelp.handleConnection(url);
@@ -102,8 +103,7 @@ final class SingleThreadTask implements Runnable {
       conn.setReadTimeout(CONSTANCE.READ_TIME_OUT);  //设置读取流的等待时间,必须设置该参数
       is = conn.getInputStream();
       //创建可设置位置的文件
-      BufferedRandomAccessFile file =
-          new BufferedRandomAccessFile(mConfigEntity.TEMP_FILE, "rwd", mBufSize);
+      file = new BufferedRandomAccessFile(mConfigEntity.TEMP_FILE, "rwd", mBufSize);
       //设置每条线程写入文件的位置
       file.seek(mConfigEntity.START_LOCATION);
       byte[] buffer = new byte[mBufSize];
@@ -121,10 +121,6 @@ final class SingleThreadTask implements Runnable {
         file.write(buffer, 0, len);
         progress(len);
       }
-      file.close();
-      //close 为阻塞的,需要使用线程池来处理
-      is.close();
-      conn.disconnect();
       if (CONSTANCE.isCancel) {
         return;
       }
@@ -161,6 +157,20 @@ final class SingleThreadTask implements Runnable {
       failDownload(mChildCurrentLocation, "下载失败【" + mConfigEntity.DOWNLOAD_URL + "】", e);
     } catch (Exception e) {
       failDownload(mChildCurrentLocation, "获取流失败", e);
+    } finally {
+      try {
+        if (file != null) {
+          file.close();
+        }
+        if (is != null) {
+          is.close();
+        }
+        if (conn != null) {
+          conn.disconnect();
+        }
+      } catch (IOException e) {
+        e.printStackTrace();
+      }
     }
   }
 
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 eefa1f3a..4f82ad27 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
@@ -35,7 +35,7 @@ public abstract class AbsTaskEntity {
   public RequestEnum requestEnum = RequestEnum.GET;
 
   /**
-   * 重定向后,新url的key
+   * 重定向后,从链接中获取新url所需要的key
    */
   public String redirectUrlKey = "location";
 
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 6b60f1bb..fe529b49 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
@@ -39,7 +39,7 @@ public interface IEntity {
    */
   @Ignore public static final int STATE_STOP = 2;
   /**
-   * 未开始状态
+   * 等待状态
    */
   @Ignore public static final int STATE_WAIT = 3;
   /**
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java b/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
index c8b4efa2..27b4af9b 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
@@ -44,14 +44,14 @@ public interface ITask {
   public String getKey();
 
   /**
-   * 是否真正执行
+   * 任务是否正在执行
    *
    * @return true,正在执行;
    */
   public boolean isRunning();
 
   /**
-   * 获取工具实体
+   * 获取信息实体
    */
   public ENTITY getEntity();
 
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 eb133913..67f55038 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
@@ -78,16 +78,16 @@ abstract class AbsTaskQueue tasks = mExecutePool.getAllTask();
     Set keys = tasks.keySet();
-    for (String key : keys){
+    for (String key : keys) {
       DownloadTask task = tasks.get(key);
       task.setMaxSpeed(maxSpeed);
     }
@@ -116,7 +119,7 @@ public class DownloadTaskQueue
         }
       }
     }
-    mExecutePool.setDownloadNum(downloadNum);
+    mExecutePool.setMaxNum(downloadNum);
     if (diff >= 1) {
       for (int i = 0; i < diff; i++) {
         DownloadTask nextTask = getNextTask();
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
index 538fc919..f6fd93d5 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
@@ -67,11 +67,18 @@ public interface ITaskQueue implements IPool {
   }
 
   /**
-   * 获取所有正在执行的任务
+   * 获取被缓存的任务
    */
   public Map getAllTask() {
     return mCacheMap;
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/ExecutePool.java b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/ExecutePool.java
index 4f9691af..6892d208 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/ExecutePool.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/ExecutePool.java
@@ -83,19 +83,19 @@ public class ExecutePool implements IPool {
   }
 
   /**
-   * 设置执行任务数
+   * 设置执行队列最大任务数
    *
-   * @param downloadNum 下载数
+   * @param maxNum 下载数
    */
-  public void setDownloadNum(int downloadNum) {
+  public void setMaxNum(int maxNum) {
     try {
-      ArrayBlockingQueue temp = new ArrayBlockingQueue<>(downloadNum);
+      ArrayBlockingQueue temp = new ArrayBlockingQueue<>(maxNum);
       TASK task;
       while ((task = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS)) != null) {
         temp.offer(task);
       }
       mExecuteQueue = temp;
-      mSize = downloadNum;
+      mSize = maxNum;
     } catch (InterruptedException e) {
       e.printStackTrace();
     }
@@ -104,7 +104,7 @@ public class ExecutePool implements IPool {
   /**
    * 添加新任务
    *
-   * @param newTask 新下载任务
+   * @param newTask 新任务
    */
   private boolean putNewTask(TASK newTask) {
     String url = newTask.getKey();
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/IPool.java b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/IPool.java
index 53378e9c..970c22b9 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/IPool.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/IPool.java
@@ -52,17 +52,17 @@ public interface IPool {
   public boolean removeTask(T task);
 
   /**
-   * 通过下载链接移除下载任务
+   * 通过key除下载任务
    *
-   * @param downloadUrl 下载链接
+   * @param key 下载链接
    * @return true:移除成功
    */
-  public boolean removeTask(String downloadUrl);
+  public boolean removeTask(String key);
 
   /**
    * 池子大小
    *
-   * @return 返回缓存池或者当前任务池大小
+   * @return 返回缓存池或者执行池大小
    */
   public int size();
 }
\ No newline at end of file
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 f53bf4e7..4aa14f66 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
@@ -140,7 +140,7 @@ public abstract class AbsSchedulers= Build.VERSION_CODES.GINGERBREAD) {
+      StrictMode.setThreadPolicy(
+          new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
+      StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());
+    }
   }
 }
\ No newline at end of file
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 e96fd2c2..96e8e48c 100644
--- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
+++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
@@ -62,7 +62,8 @@ 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://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";

From 9d284cc86f6c36ff4a248867ae49f034d2b93e8a Mon Sep 17 00:00:00 2001
From: AriaLyy <511455842@qq.com>
Date: Fri, 23 Jun 2017 03:43:23 +0800
Subject: [PATCH 07/34] ..

---
 .../aria/core/download/DownloadUtil.java       | 18 +++++++++++-------
 .../aria/core/download/SingleThreadTask.java   | 18 ++++++++----------
 2 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
index d82975b1..d91271e4 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
@@ -338,7 +338,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
    * 处理不支持断点的下载
    */
   private void handleNoSupportBreakpointDownload(HttpURLConnection conn) {
-    ConfigEntity entity = new ConfigEntity();
+    ChildThreadConfigEntity entity = new ChildThreadConfigEntity();
     long len = conn.getContentLength();
     entity.FILE_SIZE = len;
     entity.DOWNLOAD_URL = mDownloadEntity.isRedirect() ? mDownloadEntity.getRedirectUrl()
@@ -348,7 +348,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
     entity.START_LOCATION = 0;
     entity.END_LOCATION = entity.FILE_SIZE;
     entity.CONFIG_FILE_PATH = mConfigFile.getPath();
-    entity.isSupportBreakpoint = isSupportBreakpoint;
+    entity.IS_SUPPORT_BREAK_POINT = isSupportBreakpoint;
     entity.DOWNLOAD_TASK_ENTITY = mDownloadTaskEntity;
     THREAD_NUM = 1;
     CONSTANCE.THREAD_NUM = THREAD_NUM;
@@ -439,7 +439,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
    * 创建单线程任务
    */
   private void addSingleTask(int i, long startL, long endL, long fileLength) {
-    ConfigEntity entity = new ConfigEntity();
+    ChildThreadConfigEntity entity = new ChildThreadConfigEntity();
     entity.FILE_SIZE = fileLength;
     entity.DOWNLOAD_URL = mDownloadEntity.isRedirect() ? mDownloadEntity.getRedirectUrl()
         : mDownloadEntity.getDownloadUrl();
@@ -448,7 +448,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
     entity.START_LOCATION = startL;
     entity.END_LOCATION = endL;
     entity.CONFIG_FILE_PATH = mConfigFile.getPath();
-    entity.isSupportBreakpoint = isSupportBreakpoint;
+    entity.IS_SUPPORT_BREAK_POINT = isSupportBreakpoint;
     entity.DOWNLOAD_TASK_ENTITY = mDownloadTaskEntity;
     CONSTANCE.THREAD_NUM = THREAD_NUM;
     SingleThreadTask task = new SingleThreadTask(CONSTANCE, mListener, entity);
@@ -477,16 +477,20 @@ class DownloadUtil implements IDownloadUtil, Runnable {
   /**
    * 子线程下载信息类
    */
-  final static class ConfigEntity {
-    //文件大小
+  final static class ChildThreadConfigEntity {
+    //线程Id
     int THREAD_ID;
+    //下载文件大小
     long FILE_SIZE;
+    //子线程启动下载位置
     long START_LOCATION;
+    //子线程结束下载位置
     long END_LOCATION;
+    //下载路径
     File TEMP_FILE;
     String DOWNLOAD_URL;
     String CONFIG_FILE_PATH;
     DownloadTaskEntity DOWNLOAD_TASK_ENTITY;
-    boolean isSupportBreakpoint = true;
+    boolean IS_SUPPORT_BREAK_POINT = true;
   }
 }
\ No newline at end of file
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java
index 5d3cd840..b46b8750 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java
@@ -28,9 +28,7 @@ import java.math.BigDecimal;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.HashSet;
 import java.util.Properties;
-import java.util.Set;
 
 /**
  * Created by lyy on 2017/1/18.
@@ -38,7 +36,7 @@ import java.util.Set;
  */
 final class SingleThreadTask implements Runnable {
   private static final String TAG = "SingleThreadTask";
-  private DownloadUtil.ConfigEntity mConfigEntity;
+  private DownloadUtil.ChildThreadConfigEntity mConfigEntity;
   private String mConfigFPath;
   private long mChildCurrentLocation = 0;
   private int mBufSize;
@@ -47,14 +45,14 @@ final class SingleThreadTask implements Runnable {
   private long mSleepTime = 0;
 
   SingleThreadTask(DownloadStateConstance constance, IDownloadListener listener,
-      DownloadUtil.ConfigEntity downloadInfo) {
+      DownloadUtil.ChildThreadConfigEntity downloadInfo) {
     AriaManager manager = AriaManager.getInstance(AriaManager.APP);
     CONSTANCE = constance;
     CONSTANCE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut();
     CONSTANCE.READ_TIME_OUT = manager.getDownloadConfig().getIOTimeOut();
     mListener = listener;
     this.mConfigEntity = downloadInfo;
-    if (mConfigEntity.isSupportBreakpoint) {
+    if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
       mConfigFPath = downloadInfo.CONFIG_FILE_PATH;
     }
     mBufSize = manager.getDownloadConfig().getBuffSize();
@@ -82,7 +80,7 @@ final class SingleThreadTask implements Runnable {
     try {
       URL url = new URL(mConfigEntity.DOWNLOAD_URL);
       conn = ConnectionHelp.handleConnection(url);
-      if (mConfigEntity.isSupportBreakpoint) {
+      if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
         Log.d(TAG, "任务【"
             + mConfigEntity.TEMP_FILE.getName()
             + "】线程__"
@@ -129,7 +127,7 @@ final class SingleThreadTask implements Runnable {
         return;
       }
       //支持断点的处理
-      if (mConfigEntity.isSupportBreakpoint) {
+      if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
         Log.i(TAG, "任务【"
             + mConfigEntity.TEMP_FILE.getName()
             + "】线程__"
@@ -180,7 +178,7 @@ final class SingleThreadTask implements Runnable {
   protected void stop() {
     synchronized (AriaManager.LOCK) {
       try {
-        if (mConfigEntity.isSupportBreakpoint) {
+        if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
           CONSTANCE.STOP_NUM++;
           Log.d(TAG, "任务【"
               + mConfigEntity.TEMP_FILE.getName()
@@ -221,7 +219,7 @@ final class SingleThreadTask implements Runnable {
    */
   protected void cancel() {
     synchronized (AriaManager.LOCK) {
-      if (mConfigEntity.isSupportBreakpoint) {
+      if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
         CONSTANCE.CANCEL_NUM++;
         Log.d(TAG, "任务【"
             + mConfigEntity.TEMP_FILE.getName()
@@ -260,7 +258,7 @@ final class SingleThreadTask implements Runnable {
         if (ex != null) {
           Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex));
         }
-        if (mConfigEntity.isSupportBreakpoint) {
+        if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
           writeConfig(false, currentLocation);
           if (CONSTANCE.isFail()) {
             Log.e(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】下载失败");

From c82a6ac694576d96a9be5918f36edc673b1d8617 Mon Sep 17 00:00:00 2001
From: AriaLyy <511455842@qq.com>
Date: Fri, 23 Jun 2017 14:54:41 +0800
Subject: [PATCH 08/34] fix bug https://github.com/AriaLyy/Aria/issues/53

---
 .../com/arialyy/aria/core/download/DownloadReceiver.java    | 2 +-
 .../com/arialyy/simple/download/SingleTaskActivity.java     | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

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 9c12f140..6aa171ca 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
@@ -60,7 +60,7 @@ public class DownloadReceiver implements IReceiver {
   }
 
   /**
-   * 读取下载链接
+   * 加载下载地址
    */
   public DownloadTarget load(@NonNull String downloadUrl) {
     CheckUtil.checkDownloadUrl(downloadUrl);
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 96e8e48c..76585966 100644
--- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
+++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
@@ -63,9 +63,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://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://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";
   //不支持断点的链接

From 5a0b91afa64caf769fbef482adbcdf572d9a09a5 Mon Sep 17 00:00:00 2001
From: AriaLyy <511455842@qq.com>
Date: Sun, 25 Jun 2017 21:14:21 +0800
Subject: [PATCH 09/34] merge

---
 Aria/build.gradle            | 6 +++---
 AriaAnnotations/build.gradle | 2 +-
 AriaCompiler/build.gradle    | 2 +-
 build.gradle                 | 6 +++---
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/Aria/build.gradle b/Aria/build.gradle
index 9f7b3b26..41a68320 100644
--- a/Aria/build.gradle
+++ b/Aria/build.gradle
@@ -22,8 +22,8 @@ dependencies {
   compile fileTree(include: ['*.jar'], dir: 'libs')
   testCompile 'junit:junit:4.12'
   compile 'com.android.support:appcompat-v7:23.1.1'
-  compile project(':AriaCompiler')
-//    compile project(':AriaAnnotations')
+//  compile project(':AriaCompiler')
+    compile project(':AriaAnnotations')
 }
-//apply from: 'bintray-release.gradle'
+apply from: 'bintray-release.gradle'
 //apply from: 'jcenter.gradle'
diff --git a/AriaAnnotations/build.gradle b/AriaAnnotations/build.gradle
index 0b581ad5..a9f2139b 100644
--- a/AriaAnnotations/build.gradle
+++ b/AriaAnnotations/build.gradle
@@ -11,4 +11,4 @@ dependencies {
   compile fileTree(dir: 'libs', include: ['*.jar'])
 }
 
-//apply from: 'bintray-release.gradle'
\ No newline at end of file
+apply from: 'bintray-release.gradle'
\ No newline at end of file
diff --git a/AriaCompiler/build.gradle b/AriaCompiler/build.gradle
index 38de01a1..a76e8659 100644
--- a/AriaCompiler/build.gradle
+++ b/AriaCompiler/build.gradle
@@ -14,4 +14,4 @@ dependencies {
   compile project(':AriaAnnotations')
 }
 
-//apply from: 'bintray-release.gradle'
\ No newline at end of file
+apply from: 'bintray-release.gradle'
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 36979409..1c332c62 100644
--- a/build.gradle
+++ b/build.gradle
@@ -7,7 +7,7 @@ buildscript {
   dependencies {
 //    classpath 'com.android.tools.build:gradle:2.3.0'
     classpath 'com.android.tools.build:gradle:2.2.2'
-//    classpath 'com.novoda:bintray-release:0.5.0'
+    classpath 'com.novoda:bintray-release:0.5.0'
     //        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7'
     //        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
     // NOTE: Do not place your application dependencies here; they belong
@@ -37,8 +37,8 @@ task clean(type: Delete) {
 ext {
   userOrg = 'arialyy'
   groupId = 'com.arialyy.aria'
-//  publishVersion = '0.0.6'
-  publishVersion = '3.1.9'
+//  publishVersion = '0.0.8'
+  publishVersion = '3.2.0'
   repoName='maven'
   desc = 'android 下载框架'
   website = 'https://github.com/AriaLyy/Aria'

From 3c876d8d523fe744a0457792a1cc8c26d5d456bd Mon Sep 17 00:00:00 2001
From: AriaLyy <511455842@qq.com>
Date: Mon, 26 Jun 2017 20:34:33 +0800
Subject: [PATCH 10/34] https://github.com/AriaLyy/Aria/issues/60

---
 .../java/com/arialyy/aria/core/QueueMod.java  |  6 ++-
 .../com/arialyy/aria/core/command/AddCmd.java |  3 +-
 .../arialyy/aria/core/command/CancelCmd.java  |  3 +-
 .../aria/core/command/HighestPriorityCmd.java |  3 +-
 .../aria/core/command/ResumeAllCmd.java       |  7 ++--
 .../arialyy/aria/core/command/StartCmd.java   | 40 ++++++++++++-------
 .../arialyy/aria/core/command/StopCmd.java    |  3 +-
 .../aria/core/download/DownloadUtil.java      | 27 ++++++++++++-
 .../com/arialyy/aria/core/inf/AbsTarget.java  | 12 +++---
 .../com/arialyy/aria/core/inf/AbsTask.java    |  9 +++++
 .../arialyy/aria/core/queue/AbsTaskQueue.java |  5 ++-
 .../arialyy/aria/core/queue/ITaskQueue.java   |  3 +-
 .../aria/core/scheduler/AbsSchedulers.java    |  6 ++-
 app/build.gradle                              |  1 +
 .../simple/download/SingleTaskActivity.java   | 11 ++++-
 .../multi_download/MultiDownloadActivity.java |  5 +--
 16 files changed, 103 insertions(+), 41 deletions(-)

diff --git a/Aria/src/main/java/com/arialyy/aria/core/QueueMod.java b/Aria/src/main/java/com/arialyy/aria/core/QueueMod.java
index 70d02300..db9e7b6c 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/QueueMod.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/QueueMod.java
@@ -6,8 +6,10 @@ package com.arialyy.aria.core;
  */
 public enum QueueMod {
   /**
-   * 等待模式,如果执行队列已经满了,再次使用start命令执行任务时,该任务会被添加到缓存队列中
-   * 当执行队列的任务完成时,将自动执行缓存队列中的任务
+   * 等待模式,
+   * 如果执行队列已经满了,再对其它任务(TASK_A)使用start命令执行任务时
+   * 1、TASK_A添加到缓存队列中,当执行队列中的任务完成时,系统会将自动执行缓存队列中的TASK_A
+   * 2、如果再次对TASK_A使用start命令,TASK_A将会立刻执行
    */
   WAIT("wait"),
 
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java
index 4177dc1d..44cf797f 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java
@@ -17,6 +17,7 @@
 package com.arialyy.aria.core.command;
 
 import android.util.Log;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
@@ -33,7 +34,7 @@ class AddCmd extends AbsCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    ITask task = mQueue.getTask(mTaskEntity.getEntity());
+    AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
       mTaskEntity.getEntity().setState(IEntity.STATE_WAIT);
       mQueue.createTask(mTargetName, mTaskEntity);
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/CancelCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/CancelCmd.java
index fd51ad14..74079a93 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/CancelCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/CancelCmd.java
@@ -17,6 +17,7 @@
 package com.arialyy.aria.core.command;
 
 import android.text.TextUtils;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
@@ -31,7 +32,7 @@ class CancelCmd extends AbsCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    ITask task = mQueue.getTask(mTaskEntity.getEntity());
+    AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
       task = mQueue.createTask(mTargetName, mTaskEntity);
     }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/HighestPriorityCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/HighestPriorityCmd.java
index 57dc35bb..a846a41e 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/HighestPriorityCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/HighestPriorityCmd.java
@@ -16,6 +16,7 @@
 package com.arialyy.aria.core.command;
 
 import android.text.TextUtils;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
@@ -39,7 +40,7 @@ final class HighestPriorityCmd extends AbsCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    ITask task = mQueue.getTask(mTaskEntity.getEntity());
+    AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
       task = mQueue.createTask(mTargetName, mTaskEntity);
     }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/ResumeAllCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/ResumeAllCmd.java
index cb87dee7..693b9c80 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/ResumeAllCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/ResumeAllCmd.java
@@ -3,6 +3,7 @@ package com.arialyy.aria.core.command;
 import android.util.Log;
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.ITask;
@@ -29,7 +30,7 @@ final class ResumeAllCmd extends AbsCmd {
     for (DownloadEntity entity : allEntity) {
       int exeNum = mQueue.getExePoolSize();
       if (exeNum == 0 || exeNum < mQueue.getMaxTaskNum()) {
-        ITask task = createTask(entity);
+        AbsTask task = createTask(entity);
         mQueue.startTask(task);
       } else {
         entity.setState(IEntity.STATE_WAIT);
@@ -38,8 +39,8 @@ final class ResumeAllCmd extends AbsCmd {
     }
   }
 
-  private ITask createTask(DownloadEntity entity) {
-    ITask task = mQueue.getTask(entity);
+  private AbsTask createTask(DownloadEntity entity) {
+    AbsTask task = mQueue.getTask(entity);
     if (task == null) {
       DownloadTaskEntity taskEntity = new DownloadTaskEntity(entity);
       task = mQueue.createTask(mTargetName, taskEntity);
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java
index a9a3d180..30906615 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java
@@ -19,12 +19,15 @@ package com.arialyy.aria.core.command;
 import android.text.TextUtils;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.QueueMod;
+import com.arialyy.aria.core.inf.AbsTask;
+import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
  * Created by lyy on 2016/8/22.
  * 开始命令
+ * 队列模型{@link QueueMod#NOW}、{@link QueueMod#WAIT}
  */
 class StartCmd extends AbsCmd {
 
@@ -34,31 +37,38 @@ class StartCmd extends AbsCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    ITask task = mQueue.getTask(mTaskEntity.getEntity());
+    String mod;
+    int maxTaskNum;
+    AriaManager manager = AriaManager.getInstance(AriaManager.APP);
+    if (isDownloadCmd) {
+      mod = manager.getDownloadConfig().getQueueMod();
+      maxTaskNum = manager.getDownloadConfig().getMaxTaskNum();
+    } else {
+      mod = manager.getUploadConfig().getQueueMod();
+      maxTaskNum = manager.getUploadConfig().getMaxTaskNum();
+    }
+
+    AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
       task = mQueue.createTask(mTargetName, mTaskEntity);
-    }
-    if (task != null) {
       if (!TextUtils.isEmpty(mTargetName)) {
         task.setTargetName(mTargetName);
       }
-      String mod;
-      int maxTaskNum;
-      AriaManager manager = AriaManager.getInstance(AriaManager.APP);
-      if (isDownloadCmd) {
-        mod = manager.getDownloadConfig().getQueueMod();
-        maxTaskNum = manager.getDownloadConfig().getMaxTaskNum();
-      } else {
-        mod = manager.getUploadConfig().getQueueMod();
-        maxTaskNum = manager.getUploadConfig().getMaxTaskNum();
-      }
+      // 任务不存在时,根据配置不同,对任务执行操作
       if (mod.equals(QueueMod.NOW.getTag())) {
         mQueue.startTask(task);
-      }else if (mod.equals(QueueMod.WAIT.getTag())){
-        if (mQueue.getExePoolSize() < maxTaskNum){
+      } else if (mod.equals(QueueMod.WAIT.getTag())) {
+        if (mQueue.getExePoolSize() < maxTaskNum) {
           mQueue.startTask(task);
         }
       }
+    } else {
+      // 任务不存在时,根据配置不同,对任务执行操作
+      if (!task.isRunning()
+          && mod.equals(QueueMod.WAIT.getTag())
+          && task.getState() == IEntity.STATE_WAIT) {
+        mQueue.startTask(task);
+      }
     }
   }
 }
\ No newline at end of file
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/StopCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/StopCmd.java
index 8712d6cc..dc04609b 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/StopCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/StopCmd.java
@@ -18,6 +18,7 @@ package com.arialyy.aria.core.command;
 
 import android.text.TextUtils;
 import android.util.Log;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
@@ -34,7 +35,7 @@ class StopCmd extends AbsCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    ITask task = mQueue.getTask(mTaskEntity.getEntity());
+    AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
       if (mTaskEntity.getEntity().getState() == IEntity.STATE_RUNNING) {
         task = mQueue.createTask(mTargetName, mTaskEntity);
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
index d91271e4..3dbf6aca 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
@@ -20,6 +20,8 @@ import android.content.Context;
 import android.util.Log;
 import android.util.SparseArray;
 import com.arialyy.aria.core.AriaManager;
+import com.arialyy.aria.orm.DbEntity;
+import com.arialyy.aria.orm.DbUtil;
 import com.arialyy.aria.util.BufferedRandomAccessFile;
 import com.arialyy.aria.util.CommonUtil;
 import java.io.File;
@@ -78,12 +80,28 @@ class DownloadUtil implements IDownloadUtil, Runnable {
         + AriaManager.DOWNLOAD_TEMP_DIR
         + mDownloadFile.getName()
         + ".properties");
+    checkTask();
+  }
+
+  /**
+   * 检查任务是否是新任务,新任务条件:
+   * 1、文件不存在
+   * 2、下载记录文件不存在
+   * 3、下载记录文件缺失或不匹配
+   * 4、数据库记录不存在
+   */
+  private void checkTask() {
     try {
       if (!mConfigFile.exists()) { //记录文件被删除,则重新下载
         isNewTask = true;
         CommonUtil.createFile(mConfigFile.getPath());
+      } else if (!mDownloadFile.exists()) {
+        isNewTask = true;
+      } else if (DbEntity.findData(DownloadEntity.class, "downloadUrl=?",
+          mDownloadEntity.getDownloadUrl()) == null) {
+        isNewTask = true;
       } else {
-        isNewTask = !mDownloadFile.exists();
+        isNewTask = false;
       }
     } catch (Exception e) {
       e.printStackTrace();
@@ -195,9 +213,10 @@ class DownloadUtil implements IDownloadUtil, Runnable {
   }
 
   @Override public void run() {
+    HttpURLConnection conn = null;
     try {
       URL url = new URL(mDownloadEntity.getDownloadUrl());
-      HttpURLConnection conn = ConnectionHelp.handleConnection(url);
+      conn = ConnectionHelp.handleConnection(url);
       conn = ConnectionHelp.setConnectParam(mDownloadTaskEntity, conn);
       conn.setRequestProperty("Range", "bytes=" + 0 + "-");
       conn.setConnectTimeout(mConnectTimeOut);
@@ -210,6 +229,10 @@ class DownloadUtil implements IDownloadUtil, Runnable {
           + mDownloadFile.getPath()
           + "】\n"
           + CommonUtil.getPrintException(e));
+    } finally {
+      if (conn != null) {
+        conn.disconnect();
+      }
     }
   }
 
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 4a286ba5..c3dcbb48 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
@@ -206,11 +206,13 @@ public abstract class AbsTarget cmds = new ArrayList<>();
-    cmds.add(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_CREATE));
-    cmds.add(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_START));
-    AriaManager.getInstance(AriaManager.APP).setCmds(cmds).exe();
-    cmds.clear();
+    //List cmds = new ArrayList<>();
+    //cmds.add(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_CREATE));
+    //cmds.add(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_START));
+    //cmds.clear();
+    AriaManager.getInstance(AriaManager.APP)
+        .setCmd(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_START))
+        .exe();
   }
 
   /**
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
index 64e6f543..5521a882 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
@@ -37,6 +37,15 @@ public abstract class AbsTask
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 67f55038..64a8ca14 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
@@ -20,6 +20,7 @@ import android.util.Log;
 import com.arialyy.aria.core.Aria;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.inf.AbsEntity;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.queue.pool.CachePool;
@@ -30,7 +31,7 @@ import java.util.Set;
  * Created by lyy on 2017/2/23.
  * 任务队列
  */
-abstract class AbsTaskQueue
+abstract class AbsTaskQueue
     implements ITaskQueue {
   private final String TAG = "AbsTaskQueue";
   CachePool mCachePool = new CachePool<>();
@@ -118,7 +119,7 @@ abstract class AbsTaskQueue {
+public interface ITaskQueue {
 
   /**
    * 通过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 4aa14f66..1bafa3e7 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
@@ -21,6 +21,7 @@ import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.download.DownloadTask;
 import com.arialyy.aria.core.inf.AbsEntity;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.ITask;
@@ -34,7 +35,7 @@ import java.util.concurrent.ConcurrentHashMap;
 /**
  * Created by lyy on 2017/6/4.
  */
-public abstract class AbsSchedulers, QUEUE extends ITaskQueue>
+public abstract class AbsSchedulers, QUEUE extends ITaskQueue>
     implements ISchedulers {
   private static final String TAG = "AbsSchedulers";
 
@@ -131,7 +132,7 @@ public abstract class AbsSchedulers {
       //"http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk";
       //"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://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";
   //不支持断点的链接
@@ -209,6 +209,10 @@ public class SingleTaskActivity extends BaseActivity {
   @Download.onTaskCancel(DOWNLOAD_URL) void taskCancel(DownloadTask task) {
     mUpdateHandler.sendEmptyMessage(DOWNLOAD_CANCEL);
     L.d(TAG, "task__cancel");
+    //Aria.download(this)
+    //    .load(DOWNLOAD_URL)
+    //    .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk")
+    //    .add();
   }
 
   @Download.onTaskFail(DOWNLOAD_URL) void taskFail(DownloadTask task) {
@@ -257,6 +261,11 @@ public class SingleTaskActivity extends BaseActivity {
         } else if (text.equals("恢复")) {
           Aria.download(this).load(DOWNLOAD_URL).resume();
         }
+        //DownloadTarget target = Aria.download(this)
+        //    .load(DOWNLOAD_URL)
+        //    .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk");
+        //target.add();
+        //target.cancel();
         break;
       case R.id.stop:
         Aria.download(this).load(DOWNLOAD_URL).pause();
diff --git a/app/src/main/java/com/arialyy/simple/download/multi_download/MultiDownloadActivity.java b/app/src/main/java/com/arialyy/simple/download/multi_download/MultiDownloadActivity.java
index 502a5ce3..915472fa 100644
--- a/app/src/main/java/com/arialyy/simple/download/multi_download/MultiDownloadActivity.java
+++ b/app/src/main/java/com/arialyy/simple/download/multi_download/MultiDownloadActivity.java
@@ -106,10 +106,7 @@ public class MultiDownloadActivity extends BaseActivity
Date: Tue, 27 Jun 2017 18:44:32 +0800
Subject: [PATCH 11/34] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=88=A0=E9=99=A4?=
 =?UTF-8?q?=E6=89=80=E6=9C=89=E4=BB=BB=E5=8A=A1=E7=9A=84=E5=91=BD=E4=BB=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../aria/core/command/CancelAllCmd.java       | 69 +++++++++++++++++++
 .../arialyy/aria/core/command/CmdFactory.java |  7 +-
 .../aria/core/download/DownloadReceiver.java  | 37 +++++-----
 .../aria/core/download/DownloadTaskGroup.java |  8 +++
 .../aria/core/download/DownloadUtil.java      |  5 +-
 .../arialyy/aria/core/inf/AbsReceiver.java    | 27 ++++++++
 .../arialyy/aria/core/inf/AbsTaskEntity.java  |  5 ++
 .../com/arialyy/aria/core/inf/IReceiver.java  |  2 +-
 .../arialyy/aria/core/queue/AbsTaskQueue.java | 12 ++++
 .../arialyy/aria/core/queue/ITaskQueue.java   |  5 ++
 .../aria/core/upload/UploadReceiver.java      | 31 +++++----
 .../com/arialyy/aria/util/CommonUtil.java     | 47 ++++++++++++-
 12 files changed, 220 insertions(+), 35 deletions(-)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/command/CancelAllCmd.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskGroup.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java

diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/CancelAllCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/CancelAllCmd.java
new file mode 100644
index 00000000..057c8a2b
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/CancelAllCmd.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.core.command;
+
+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.AbsTaskEntity;
+import com.arialyy.aria.core.upload.UploadEntity;
+import com.arialyy.aria.orm.DbEntity;
+import com.arialyy.aria.util.CommonUtil;
+import java.io.File;
+import java.util.List;
+
+/**
+ * Created by AriaL on 2017/6/27.
+ * 删除所有任务,并且删除所有回掉
+ */
+final class CancelAllCmd extends AbsCmd {
+  /**
+   * @param targetName 产生任务的对象名
+   */
+  CancelAllCmd(String targetName, T entity) {
+    super(targetName, entity);
+  }
+
+  @Override public void executeCmd() {
+    mQueue.removeAllTask();
+    if (mTaskEntity instanceof DownloadTaskEntity) {
+      handleDownloadRemove();
+    } else {
+      handleUploadRemove();
+    }
+  }
+
+  /**
+   * 处理上传的删除
+   */
+  private void handleUploadRemove() {
+    List allEntity = DbEntity.findAllData(UploadEntity.class);
+    for (UploadEntity entity : allEntity) {
+      CommonUtil.delUploadTaskConfig(mTaskEntity.removeFile, entity);
+    }
+  }
+
+  /**
+   * 处理下载的删除
+   */
+  private void handleDownloadRemove() {
+    List allEntity = DbEntity.findAllData(DownloadEntity.class);
+    for (DownloadEntity entity : allEntity) {
+      CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, entity);
+    }
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/CmdFactory.java b/Aria/src/main/java/com/arialyy/aria/core/command/CmdFactory.java
index ae725b51..e2fdf3e0 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/CmdFactory.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/CmdFactory.java
@@ -56,7 +56,10 @@ public class CmdFactory {
    * 恢复所有停止的任务
    */
   public static final int TASK_RESUME_ALL = 0x130;
-
+  /**
+   * 删除所有任务,
+   */
+  public static final int TASK_CANCEL_ALL = 0x131;
   private static volatile CmdFactory INSTANCE = null;
 
   private CmdFactory() {
@@ -95,6 +98,8 @@ public class CmdFactory {
         return new StopAllCmd<>(target, entity);
       case TASK_RESUME_ALL:
         return new ResumeAllCmd<>(target, entity);
+      case TASK_CANCEL_ALL:
+        return new CancelAllCmd<>(target, entity);
       default:
         return null;
     }
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 6aa171ca..32a255d3 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
@@ -17,7 +17,7 @@ package com.arialyy.aria.core.download;
 
 import android.support.annotation.NonNull;
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.inf.ICmd;
+import com.arialyy.aria.core.inf.AbsReceiver;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.IReceiver;
 import com.arialyy.aria.core.command.CmdFactory;
@@ -36,10 +36,8 @@ import java.util.Set;
  * Created by lyy on 2016/12/5.
  * 下载功能接收器
  */
-public class DownloadReceiver implements IReceiver {
+public class DownloadReceiver extends AbsReceiver {
   private static final String TAG = "DownloadReceiver";
-  public String targetName;
-  public Object obj;
   public ISchedulerListener listener;
 
   /**
@@ -143,9 +141,10 @@ public class DownloadReceiver implements IReceiver {
    * 停止所有正在下载的任务,并清空等待队列。
    */
   @Override public void stopAllTask() {
-    final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
-    ariaManager.setCmd(CmdFactory.getInstance()
-        .createCmd(targetName, new DownloadTaskEntity(), CmdFactory.TASK_STOP_ALL)).exe();
+    AriaManager.getInstance(AriaManager.APP)
+        .setCmd(CmdFactory.getInstance()
+            .createCmd(targetName, new DownloadTaskEntity(), CmdFactory.TASK_STOP_ALL))
+        .exe();
   }
 
   /**
@@ -154,23 +153,25 @@ public class DownloadReceiver implements IReceiver {
    * 2.如果队列执行队列已经满了,则将所有任务添加到等待队列中
    */
   public void resumeAllTask() {
-    final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
-    ariaManager.setCmd(CmdFactory.getInstance()
-        .createCmd(targetName, new DownloadTaskEntity(), CmdFactory.TASK_RESUME_ALL)).exe();
+    AriaManager.getInstance(AriaManager.APP)
+        .setCmd(CmdFactory.getInstance()
+            .createCmd(targetName, new DownloadTaskEntity(), CmdFactory.TASK_RESUME_ALL))
+        .exe();
   }
 
   /**
    * 删除所有任务
+   *
+   * @param removeFile {@code true} 删除已经下载完成的任务,不仅删除下载记录,还会删除已经下载完成的文件,{@code false}
+   * 如果文件已经下载完成,只删除下载记录
    */
-  @Override public void removeAllTask() {
+  @Override public void removeAllTask(boolean removeFile) {
     final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
-    List allEntity = DbEntity.findAllData(DownloadEntity.class);
-    List cancelCmds = new ArrayList<>();
-    for (DownloadEntity entity : allEntity) {
-      cancelCmds.add(
-          CommonUtil.createCmd(targetName, new DownloadTaskEntity(entity), CmdFactory.TASK_CANCEL));
-    }
-    ariaManager.setCmds(cancelCmds).exe();
+    AriaManager.getInstance(AriaManager.APP)
+        .setCmd(
+            CommonUtil.createCmd(targetName, new DownloadTaskEntity(), CmdFactory.TASK_CANCEL_ALL))
+        .exe();
+
     Set keys = ariaManager.getReceiver().keySet();
     for (String key : keys) {
       IReceiver receiver = ariaManager.getReceiver().get(key);
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskGroup.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskGroup.java
new file mode 100644
index 00000000..edb322a4
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskGroup.java
@@ -0,0 +1,8 @@
+package com.arialyy.aria.core.download;
+
+/**
+ * Created by AriaL on 2017/6/27.
+ */
+
+public class DownloadTaskGroup {
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
index 3dbf6aca..526f08ba 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
@@ -101,7 +101,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
           mDownloadEntity.getDownloadUrl()) == null) {
         isNewTask = true;
       } else {
-        isNewTask = false;
+        isNewTask = !mDownloadFile.exists();
       }
     } catch (Exception e) {
       e.printStackTrace();
@@ -342,7 +342,8 @@ class DownloadUtil implements IDownloadUtil, Runnable {
         recordL[rl] = i;
         rl++;
       } else {
-        handleNewTask(fileLength);
+        //handleNewTask(fileLength);
+        isNewTask = true;
       }
       if (isNewTask) {
         recordL[rl] = i;
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java
new file mode 100644
index 00000000..4e67339e
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.arialyy.aria.core.inf;
+
+/**
+ * Created by AriaL on 2017/6/27.
+ */
+
+public abstract class AbsReceiver implements IReceiver{
+  public String targetName;
+  public Object obj;
+
+}
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 4f82ad27..fe63cd37 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
@@ -39,5 +39,10 @@ public abstract class AbsTaskEntity {
    */
   public String redirectUrlKey = "location";
 
+  /**
+   * 用于判断删除任务时是否需要删除文件{@code true}删除
+   */
+  public boolean removeFile = false;
+
   public abstract AbsEntity getEntity();
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java
index 0c8d701c..19b1b11f 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java
@@ -44,7 +44,7 @@ public interface IReceiver {
   /**
    * 删除所有任务
    */
-  public void removeAllTask();
+  public void removeAllTask(boolean removeFile);
 
   /**
    * 任务是否存在
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 64a8ca14..0bd83e6e 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
@@ -41,6 +41,18 @@ abstract class AbsTaskQueue exeKeys = mExecutePool.getAllTask().keySet();
+    for (String key : exeKeys) {
+      TASK task = mExecutePool.getAllTask().get(key);
+      if (task != null) task.cancel();
+    }
+    Set cacheKeys = mCachePool.getAllTask().keySet();
+    for (String key : cacheKeys) {
+      mExecutePool.removeTask(key);
+    }
+  }
+
   /**
    * 停止所有任务
    */
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
index c562ffc0..b628a1d3 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
@@ -46,6 +46,11 @@ public interface ITaskQueue {
+public class UploadReceiver extends AbsReceiver {
   private static final String TAG = "DownloadReceiver";
-  public String targetName;
-  public Object obj;
   public ISchedulerListener listener;
 
   /**
@@ -94,15 +94,20 @@ public class UploadReceiver implements IReceiver {
     AriaManager.getInstance(AriaManager.APP).setCmds(stopCmds).exe();
   }
 
-  @Override public void removeAllTask() {
+  /**
+   * 删除所有任务
+   *
+   * @param removeFile {@code true} 删除已经上传完成的任务,不仅删除上传记录,还会删除已经上传完成的文件,{@code false}
+   * 如果文件已经上传完成,只删除上传记录
+   */
+  @Override public void removeAllTask(boolean removeFile) {
     final AriaManager am = AriaManager.getInstance(AriaManager.APP);
-    List allEntity = DbEntity.findAllData(UploadEntity.class);
-    List cancelCmds = new ArrayList<>();
-    for (UploadEntity entity : allEntity) {
-      cancelCmds.add(
-          CommonUtil.createCmd(targetName, new UploadTaskEntity(entity), CmdFactory.TASK_CANCEL));
-    }
-    am.setCmds(cancelCmds).exe();
+
+    AriaManager.getInstance(AriaManager.APP)
+        .setCmd(
+            CommonUtil.createCmd(targetName, new DownloadTaskEntity(), CmdFactory.TASK_CANCEL_ALL))
+        .exe();
+
     Set keys = am.getReceiver().keySet();
     for (String key : keys) {
       IReceiver receiver = am.getReceiver().get(key);
@@ -118,8 +123,10 @@ public class UploadReceiver implements IReceiver {
 
   /**
    * 添加调度器回调
+   *
+   * @see #register()
    */
-  public UploadReceiver addSchedulerListener(ISchedulerListener listener) {
+  @Deprecated public UploadReceiver addSchedulerListener(ISchedulerListener listener) {
     this.listener = listener;
     UploadSchedulers.getInstance().addSchedulerListener(targetName, listener);
     return this;
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 28d447ad..2b42354a 100644
--- a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
@@ -22,9 +22,12 @@ import android.content.SharedPreferences;
 import android.net.Uri;
 import android.text.TextUtils;
 import android.util.Log;
+import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.command.CmdFactory;
 import com.arialyy.aria.core.command.AbsCmd;
+import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
+import com.arialyy.aria.core.upload.UploadEntity;
 import java.io.File;
 import java.io.FileFilter;
 import java.io.FileInputStream;
@@ -49,10 +52,52 @@ import java.util.regex.Pattern;
 public class CommonUtil {
   private static final String TAG = "CommonUtil";
 
+  /**
+   * 删除上传任务的配置,包括
+   *
+   * @param removeFile {@code true} 删除已经上传完成的任务,不仅删除上传记录,还会删除已经上传完成的文件,{@code false}
+   * 如果文件已经上传完成,只删除上传记录
+   */
+  public static void delUploadTaskConfig(boolean removeFile, UploadEntity entity) {
+    if (removeFile) {
+      File file = new File(entity.getFilePath());
+      if (file.exists()) {
+        file.delete();
+      }
+    }
+    File config = new File(
+        AriaManager.APP.getFilesDir().getPath() + "/temp/" + entity.getFileName() + ".properties");
+    if (config.exists()) {
+      config.delete();
+    }
+    entity.deleteData();
+  }
+
+  /**
+   * 删除下载任务的配置,包括
+   *
+   * @param removeFile{@code true} 删除已经下载完成的任务,不仅删除下载记录,还会删除已经下载完成的文件,{@code false}
+   * 如果文件已经下载完成,只删除下载记录
+   */
+  public static void delDownloadTaskConfig(boolean removeFile, DownloadEntity entity) {
+    if (removeFile) {
+      File file = new File(entity.getDownloadPath());
+      if (file.exists()) {
+        file.delete();
+      }
+    }
+    File config = new File(
+        AriaManager.APP.getFilesDir().getPath() + "/temp/" + entity.getFileName() + ".properties");
+    if (config.exists()) {
+      config.delete();
+    }
+    entity.deleteData();
+  }
+
   /**
    * 获取CPU核心数
    */
-  public static int getNumCores() {
+  public static int getCoresNum() {
     //Private Class to display only CPU devices in the directory listing
     class CpuFilter implements FileFilter {
       @Override public boolean accept(File pathname) {

From 380b05de4326d429a36168d0f2ffda58dc18a929 Mon Sep 17 00:00:00 2001
From: AriaLyy <511455842@qq.com>
Date: Thu, 29 Jun 2017 18:07:21 +0800
Subject: [PATCH 12/34] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E7=BB=84=E5=BC=80?=
 =?UTF-8?q?=E5=A7=8B=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    |   3 +-
 .../com/arialyy/aria/core/command/AbsCmd.java |  46 +-----
 .../aria/core/command/AbsCmdFactory.java      |  30 ++++
 .../aria/core/{inf => command}/ICmd.java      |   4 +-
 .../aria/core/command/group/AbsGroupCmd.java  |  47 ++++++
 .../core/command/group/GroupCancelCmd.java    |  35 +++++
 .../core/command/group/GroupCmdFactory.java   |  71 +++++++++
 .../core/command/group/GroupStartCmd.java     |  35 +++++
 .../aria/core/command/group/GroupStopCmd.java |  35 +++++
 .../core/command/normal/AbsNormalCmd.java     |  56 +++++++
 .../core/command/{ => normal}/AddCmd.java     |   5 +-
 .../command/{ => normal}/CancelAllCmd.java    |   6 +-
 .../core/command/{ => normal}/CancelCmd.java  |   5 +-
 .../{ => normal}/HighestPriorityCmd.java      |   5 +-
 .../NormalCmdFactory.java}                    |  15 +-
 .../command/{ => normal}/ResumeAllCmd.java    |   5 +-
 .../core/command/{ => normal}/StartCmd.java   |   5 +-
 .../core/command/{ => normal}/StopAllCmd.java |   4 +-
 .../core/command/{ => normal}/StopCmd.java    |   5 +-
 .../aria/core/download/DownloadEntity.java    |   4 +-
 .../core/download/DownloadGroupTarget.java    |  38 +++++
 .../aria/core/download/DownloadReceiver.java  |  15 +-
 .../aria/core/download/DownloadTarget.java    |  76 ++--------
 .../arialyy/aria/core/inf/AbsGroupEntity.java | 140 ++++++++++++++++++
 .../arialyy/aria/core/inf/AbsGroupTarget.java |  79 ++++++++++
 .../{AbsEntity.java => AbsNormalEntity.java}  |   6 +-
 .../{AbsTarget.java => AbsNormalTarget.java}  | 139 +++++++++--------
 .../arialyy/aria/core/inf/AbsReceiver.java    |   2 +-
 .../com/arialyy/aria/core/inf/AbsTask.java    |   2 +-
 .../arialyy/aria/core/inf/AbsTaskEntity.java  |   2 +-
 .../com/arialyy/aria/core/inf/ITarget.java    |  86 +++++++++++
 .../java/com/arialyy/aria/core/inf/ITask.java |   6 +-
 .../arialyy/aria/core/queue/AbsTaskQueue.java |   6 +-
 .../core/queue/DownloadGroupTaskQueue.java    |  24 +++
 .../aria/core/scheduler/AbsSchedulers.java    |   5 +-
 .../aria/core/upload/UploadEntity.java        |   4 +-
 .../aria/core/upload/UploadReceiver.java      |  12 +-
 .../aria/core/upload/UploadTarget.java        |  62 ++------
 .../com/arialyy/aria/util/CommonUtil.java     |   8 +-
 39 files changed, 850 insertions(+), 283 deletions(-)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/command/AbsCmdFactory.java
 rename Aria/src/main/java/com/arialyy/aria/core/{inf => command}/ICmd.java (90%)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCancelCmd.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCmdFactory.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStopCmd.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/command/normal/AbsNormalCmd.java
 rename Aria/src/main/java/com/arialyy/aria/core/command/{ => normal}/AddCmd.java (90%)
 rename Aria/src/main/java/com/arialyy/aria/core/command/{ => normal}/CancelAllCmd.java (91%)
 rename Aria/src/main/java/com/arialyy/aria/core/command/{ => normal}/CancelCmd.java (89%)
 rename Aria/src/main/java/com/arialyy/aria/core/command/{ => normal}/HighestPriorityCmd.java (95%)
 rename Aria/src/main/java/com/arialyy/aria/core/command/{CmdFactory.java => normal/NormalCmdFactory.java} (85%)
 rename Aria/src/main/java/com/arialyy/aria/core/command/{ => normal}/ResumeAllCmd.java (91%)
 rename Aria/src/main/java/com/arialyy/aria/core/command/{ => normal}/StartCmd.java (94%)
 rename Aria/src/main/java/com/arialyy/aria/core/command/{ => normal}/StopAllCmd.java (75%)
 rename Aria/src/main/java/com/arialyy/aria/core/command/{ => normal}/StopCmd.java (91%)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java
 rename Aria/src/main/java/com/arialyy/aria/core/inf/{AbsEntity.java => AbsNormalEntity.java} (95%)
 rename Aria/src/main/java/com/arialyy/aria/core/inf/{AbsTarget.java => AbsNormalTarget.java} (61%)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/queue/DownloadGroupTaskQueue.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 5bcad9cb..41bb1525 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
@@ -29,14 +29,13 @@ import android.text.TextUtils;
 import android.util.Log;
 import android.widget.PopupWindow;
 import com.arialyy.aria.core.download.DownloadReceiver;
-import com.arialyy.aria.core.inf.ICmd;
+import com.arialyy.aria.core.command.ICmd;
 import com.arialyy.aria.core.inf.IReceiver;
 import com.arialyy.aria.core.upload.UploadReceiver;
 import com.arialyy.aria.orm.DbUtil;
 import com.arialyy.aria.util.CommonUtil;
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
index 8dc620c8..d337a453 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
@@ -16,50 +16,20 @@
 
 package com.arialyy.aria.core.command;
 
-import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
-import com.arialyy.aria.core.queue.DownloadTaskQueue;
 import com.arialyy.aria.core.queue.ITaskQueue;
-import com.arialyy.aria.core.inf.ICmd;
-import com.arialyy.aria.core.queue.UploadTaskQueue;
-import com.arialyy.aria.core.upload.UploadTaskEntity;
-import com.arialyy.aria.util.CheckUtil;
-import com.arialyy.aria.util.CommonUtil;
 
 /**
- * Created by lyy on 2016/8/22.
- * 下载命令
+ * Created by AriaL on 2017/6/29.
  */
-public abstract class AbsCmd implements ICmd {
-  ITaskQueue mQueue;
-  T mTaskEntity;
-  String TAG;
-  String mTargetName;
-  /**
-   * 能否执行命令
-   */
-  boolean canExeCmd = true;
+public abstract class AbsCmd implements ICmd{
+  protected ITaskQueue mQueue;
+  protected T mTaskEntity;
+  protected String TAG;
+  protected String mTargetName;
   /**
    * 是否是下载任务的命令
    * {@code true} 下载任务的命令,{@code false} 上传任务的命令
    */
-  boolean isDownloadCmd = true;
-
-  /**
-   * @param targetName 产生任务的对象名
-   */
-  AbsCmd(String targetName, T entity) {
-    canExeCmd = CheckUtil.checkCmdEntity(entity,
-        !(this instanceof CancelCmd) || !(this instanceof StopCmd));
-    mTargetName = targetName;
-    mTaskEntity = entity;
-    TAG = CommonUtil.getClassName(this);
-    if (entity instanceof DownloadTaskEntity) {
-      mQueue = DownloadTaskQueue.getInstance();
-      isDownloadCmd = true;
-    } else if (entity instanceof UploadTaskEntity) {
-      mQueue = UploadTaskQueue.getInstance();
-      isDownloadCmd = false;
-    }
-  }
-}
\ No newline at end of file
+  protected boolean isDownloadCmd = true;
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmdFactory.java b/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmdFactory.java
new file mode 100644
index 00000000..9f447b49
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmdFactory.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.core.command;
+
+import com.arialyy.aria.core.inf.AbsTaskEntity;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ */
+public abstract class AbsCmdFactory {
+
+  /**
+   * @param target 创建任务的对象
+   * @param entity 下载实体
+   */
+  public abstract  CMD createCmd(String target, T entity, int type);
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/ICmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/ICmd.java
similarity index 90%
rename from Aria/src/main/java/com/arialyy/aria/core/inf/ICmd.java
rename to Aria/src/main/java/com/arialyy/aria/core/command/ICmd.java
index 482cfb0c..dc938037 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/ICmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/ICmd.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.arialyy.aria.core.inf;
+package com.arialyy.aria.core.command;
 
 /**
  * Created by lyy on 2017/2/9.
@@ -23,5 +23,5 @@ public interface ICmd {
   /**
    * 执行命令
    */
-  public abstract void executeCmd();
+  void executeCmd();
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java
new file mode 100644
index 00000000..f8b2e0ed
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.arialyy.aria.core.command.group;
+
+import com.arialyy.aria.core.command.AbsCmd;
+import com.arialyy.aria.core.download.DownloadTaskEntity;
+import com.arialyy.aria.core.inf.AbsTaskEntity;
+import com.arialyy.aria.core.queue.DownloadTaskQueue;
+import com.arialyy.aria.core.queue.UploadTaskQueue;
+import com.arialyy.aria.core.upload.UploadTaskEntity;
+import com.arialyy.aria.util.CommonUtil;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ * 任务组命令
+ */
+public abstract class AbsGroupCmd extends AbsCmd {
+
+  /**
+   * @param targetName 创建任务的对象名
+   */
+  AbsGroupCmd(String targetName, T entity) {
+    mTargetName = targetName;
+    mTaskEntity = entity;
+    TAG = CommonUtil.getClassName(this);
+    if (entity instanceof DownloadTaskEntity) {
+      mQueue = DownloadTaskQueue.getInstance();
+      isDownloadCmd = true;
+    } else if (entity instanceof UploadTaskEntity) {
+      mQueue = UploadTaskQueue.getInstance();
+      isDownloadCmd = false;
+    }
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCancelCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCancelCmd.java
new file mode 100644
index 00000000..5b6e5cf9
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCancelCmd.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.command.group;
+
+import com.arialyy.aria.core.inf.AbsTaskEntity;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ * 删除任务组
+ */
+class GroupCancelCmd extends AbsGroupCmd {
+  /**
+   * @param targetName 创建任务的对象名
+   */
+  GroupCancelCmd(String targetName, T entity) {
+    super(targetName, entity);
+  }
+
+  @Override public void executeCmd() {
+
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCmdFactory.java b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCmdFactory.java
new file mode 100644
index 00000000..786dd6b8
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCmdFactory.java
@@ -0,0 +1,71 @@
+/*
+ * 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.command.group;
+
+import com.arialyy.aria.core.AriaManager;
+import com.arialyy.aria.core.command.AbsCmdFactory;
+import com.arialyy.aria.core.inf.AbsTaskEntity;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ */
+public class GroupCmdFactory extends AbsCmdFactory {
+  /**
+   * 启动任务
+   */
+  public static final int TASK_START = 0xa1;
+  /**
+   * 停止任务
+   */
+  public static final int TASK_STOP = 0xa2;
+  /**
+   * 取消任务
+   */
+  public static final int TASK_CANCEL = 0xa3;
+
+  private static volatile GroupCmdFactory INSTANCE = null;
+
+  private GroupCmdFactory() {
+
+  }
+
+  public static GroupCmdFactory getInstance() {
+    if (INSTANCE == null) {
+      synchronized (AriaManager.LOCK) {
+        INSTANCE = new GroupCmdFactory();
+      }
+    }
+    return INSTANCE;
+  }
+
+  /**
+   * @param target 创建任务的对象
+   * @param entity 下载实体
+   * @param type 命令类型{@link #TASK_START}、{@link #TASK_CANCEL}、{@link #TASK_STOP}
+   */
+  public  AbsGroupCmd createCmd(String target, T entity, int type) {
+    switch (type) {
+      case TASK_START:
+        return new GroupStartCmd<>(target, entity);
+      case TASK_STOP:
+        return new GroupStopCmd<>(target, entity);
+      case TASK_CANCEL:
+        return new GroupCancelCmd<>(target, entity);
+      default:
+        return null;
+    }
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java
new file mode 100644
index 00000000..7fdb8465
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.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.command.group;
+
+import com.arialyy.aria.core.inf.AbsTaskEntity;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ * 任务组开始命令,该命令负责开始下载或恢复下载的操作
+ */
+class GroupStartCmd extends AbsGroupCmd {
+  /**
+   * @param targetName 创建任务的对象名
+   */
+  GroupStartCmd(String targetName, T entity) {
+    super(targetName, entity);
+  }
+
+  @Override public void executeCmd() {
+
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStopCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStopCmd.java
new file mode 100644
index 00000000..85c400bd
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStopCmd.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.command.group;
+
+import com.arialyy.aria.core.inf.AbsTaskEntity;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ * 停止任务组的命令
+ */
+class GroupStopCmd extends AbsGroupCmd{
+  /**
+   * @param targetName 创建任务的对象名
+   */
+  GroupStopCmd(String targetName, T entity) {
+    super(targetName, entity);
+  }
+
+  @Override public void executeCmd() {
+
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/AbsNormalCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/AbsNormalCmd.java
new file mode 100644
index 00000000..e690524d
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/AbsNormalCmd.java
@@ -0,0 +1,56 @@
+/*
+ * 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.command.normal;
+
+import com.arialyy.aria.core.command.AbsCmd;
+import com.arialyy.aria.core.download.DownloadTaskEntity;
+import com.arialyy.aria.core.inf.AbsTaskEntity;
+import com.arialyy.aria.core.queue.DownloadTaskQueue;
+import com.arialyy.aria.core.queue.UploadTaskQueue;
+import com.arialyy.aria.core.upload.UploadTaskEntity;
+import com.arialyy.aria.util.CheckUtil;
+import com.arialyy.aria.util.CommonUtil;
+
+/**
+ * Created by lyy on 2016/8/22.
+ * 下载命令
+ */
+public abstract class AbsNormalCmd extends AbsCmd {
+
+  /**
+   * 能否执行命令
+   */
+  boolean canExeCmd = true;
+
+  /**
+   * @param targetName 产生任务的对象名
+   */
+  AbsNormalCmd(String targetName, T entity) {
+    canExeCmd = CheckUtil.checkCmdEntity(entity,
+        !(this instanceof CancelCmd) || !(this instanceof StopCmd));
+    mTargetName = targetName;
+    mTaskEntity = entity;
+    TAG = CommonUtil.getClassName(this);
+    if (entity instanceof DownloadTaskEntity) {
+      mQueue = DownloadTaskQueue.getInstance();
+      isDownloadCmd = true;
+    } else if (entity instanceof UploadTaskEntity) {
+      mQueue = UploadTaskQueue.getInstance();
+      isDownloadCmd = false;
+    }
+  }
+}
\ No newline at end of file
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
similarity index 90%
rename from Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java
rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
index 44cf797f..e848813b 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
@@ -14,19 +14,18 @@
  * limitations under the License.
  */
 
-package com.arialyy.aria.core.command;
+package com.arialyy.aria.core.command.normal;
 
 import android.util.Log;
 import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.IEntity;
-import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
  * Created by lyy on 2016/8/22.
  * 添加任务的命令
  */
-class AddCmd extends AbsCmd {
+class AddCmd extends AbsNormalCmd {
 
   AddCmd(String targetName, T entity) {
     super(targetName, entity);
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/CancelAllCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java
similarity index 91%
rename from Aria/src/main/java/com/arialyy/aria/core/command/CancelAllCmd.java
rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java
index 057c8a2b..f68b3bcc 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/CancelAllCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java
@@ -14,23 +14,21 @@
  * limitations under the License.
  */
 
-package com.arialyy.aria.core.command;
+package com.arialyy.aria.core.command.normal;
 
-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.AbsTaskEntity;
 import com.arialyy.aria.core.upload.UploadEntity;
 import com.arialyy.aria.orm.DbEntity;
 import com.arialyy.aria.util.CommonUtil;
-import java.io.File;
 import java.util.List;
 
 /**
  * Created by AriaL on 2017/6/27.
  * 删除所有任务,并且删除所有回掉
  */
-final class CancelAllCmd extends AbsCmd {
+final class CancelAllCmd extends AbsNormalCmd {
   /**
    * @param targetName 产生任务的对象名
    */
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/CancelCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
similarity index 89%
rename from Aria/src/main/java/com/arialyy/aria/core/command/CancelCmd.java
rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
index 74079a93..d12f0cad 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/CancelCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
@@ -14,18 +14,17 @@
  * limitations under the License.
  */
 
-package com.arialyy.aria.core.command;
+package com.arialyy.aria.core.command.normal;
 
 import android.text.TextUtils;
 import com.arialyy.aria.core.inf.AbsTask;
-import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
  * Created by lyy on 2016/9/20.
  * 取消命令
  */
-class CancelCmd extends AbsCmd {
+class CancelCmd extends AbsNormalCmd {
   CancelCmd(String targetName, T entity) {
     super(targetName, entity);
   }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/HighestPriorityCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java
similarity index 95%
rename from Aria/src/main/java/com/arialyy/aria/core/command/HighestPriorityCmd.java
rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java
index a846a41e..a52555a8 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/HighestPriorityCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java
@@ -13,11 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.arialyy.aria.core.command;
+package com.arialyy.aria.core.command.normal;
 
 import android.text.TextUtils;
 import com.arialyy.aria.core.inf.AbsTask;
-import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
@@ -30,7 +29,7 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
  * 5、如果下载队列中已经满了,则会停止队尾的任务,当高优先级任务完成后,该队尾任务将自动执行
  * 6、把任务设置为最高优先级任务后,将自动执行任务,不需要重新调用start()启动任务
  */
-final class HighestPriorityCmd extends AbsCmd {
+final class HighestPriorityCmd extends AbsNormalCmd {
   /**
    * @param targetName 产生任务的对象名
    */
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/CmdFactory.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/NormalCmdFactory.java
similarity index 85%
rename from Aria/src/main/java/com/arialyy/aria/core/command/CmdFactory.java
rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/NormalCmdFactory.java
index e2fdf3e0..85aa33fc 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/CmdFactory.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/NormalCmdFactory.java
@@ -14,16 +14,17 @@
  * limitations under the License.
  */
 
-package com.arialyy.aria.core.command;
+package com.arialyy.aria.core.command.normal;
 
 import com.arialyy.aria.core.AriaManager;
+import com.arialyy.aria.core.command.AbsCmdFactory;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
  * Created by Lyy on 2016/9/23.
  * 命令工厂
  */
-public class CmdFactory {
+public class NormalCmdFactory extends AbsCmdFactory {
   /**
    * 创建任务
    */
@@ -60,16 +61,16 @@ public class CmdFactory {
    * 删除所有任务,
    */
   public static final int TASK_CANCEL_ALL = 0x131;
-  private static volatile CmdFactory INSTANCE = null;
+  private static volatile NormalCmdFactory INSTANCE = null;
 
-  private CmdFactory() {
+  private NormalCmdFactory() {
 
   }
 
-  public static CmdFactory getInstance() {
+  public static NormalCmdFactory getInstance() {
     if (INSTANCE == null) {
       synchronized (AriaManager.LOCK) {
-        INSTANCE = new CmdFactory();
+        INSTANCE = new NormalCmdFactory();
       }
     }
     return INSTANCE;
@@ -81,7 +82,7 @@ public class CmdFactory {
    * @param type 命令类型{@link #TASK_CREATE}、{@link #TASK_START}、{@link #TASK_CANCEL}、{@link
    * #TASK_STOP}、{@link #TASK_HIGHEST_PRIORITY}、{@link #TASK_STOP_ALL}、{@link #TASK_RESUME_ALL}
    */
-  public  AbsCmd createCmd(String target, T entity, int type) {
+  public  AbsNormalCmd createCmd(String target, T entity, int type) {
     switch (type) {
       case TASK_CREATE:
         return new AddCmd<>(target, entity);
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/ResumeAllCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
similarity index 91%
rename from Aria/src/main/java/com/arialyy/aria/core/command/ResumeAllCmd.java
rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
index 693b9c80..58b26bdc 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/ResumeAllCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
@@ -1,4 +1,4 @@
-package com.arialyy.aria.core.command;
+package com.arialyy.aria.core.command.normal;
 
 import android.util.Log;
 import com.arialyy.aria.core.download.DownloadEntity;
@@ -6,7 +6,6 @@ import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IEntity;
-import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.orm.DbEntity;
 import java.util.List;
 
@@ -16,7 +15,7 @@ import java.util.List;
  * 1.如果执行队列没有满,则开始下载任务,直到执行队列满
  * 2.如果队列执行队列已经满了,则将所有任务添加到等待队列中
  */
-final class ResumeAllCmd extends AbsCmd {
+final class ResumeAllCmd extends AbsNormalCmd {
   /**
    * @param targetName 产生任务的对象名
    */
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java
similarity index 94%
rename from Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java
rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java
index 30906615..2b042a27 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package com.arialyy.aria.core.command;
+package com.arialyy.aria.core.command.normal;
 
 import android.text.TextUtils;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.QueueMod;
 import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.IEntity;
-import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
@@ -29,7 +28,7 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
  * 开始命令
  * 队列模型{@link QueueMod#NOW}、{@link QueueMod#WAIT}
  */
-class StartCmd extends AbsCmd {
+class StartCmd extends AbsNormalCmd {
 
   StartCmd(String targetName, T entity) {
     super(targetName, entity);
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/StopAllCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopAllCmd.java
similarity index 75%
rename from Aria/src/main/java/com/arialyy/aria/core/command/StopAllCmd.java
rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/StopAllCmd.java
index 2c16378e..431adfdd 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/StopAllCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopAllCmd.java
@@ -1,4 +1,4 @@
-package com.arialyy.aria.core.command;
+package com.arialyy.aria.core.command.normal;
 
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
@@ -6,7 +6,7 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
  * Created by AriaL on 2017/6/13.
  * 停止所有任务的命令,并清空所有等待队列
  */
-final class StopAllCmd extends AbsCmd {
+final class StopAllCmd extends AbsNormalCmd {
   /**
    * @param targetName 产生任务的对象名
    */
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/StopCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
similarity index 91%
rename from Aria/src/main/java/com/arialyy/aria/core/command/StopCmd.java
rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
index dc04609b..9d0b0811 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/StopCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
@@ -14,20 +14,19 @@
  * limitations under the License.
  */
 
-package com.arialyy.aria.core.command;
+package com.arialyy.aria.core.command.normal;
 
 import android.text.TextUtils;
 import android.util.Log;
 import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.IEntity;
-import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
  * Created by lyy on 2016/9/20.
  * 停止命令
  */
-class StopCmd extends AbsCmd {
+class StopCmd extends AbsNormalCmd {
 
   StopCmd(String targetName, T entity) {
     super(targetName, entity);
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 5c0e18bf..e1102037 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
@@ -18,7 +18,7 @@ package com.arialyy.aria.core.download;
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import com.arialyy.aria.core.inf.AbsEntity;
+import com.arialyy.aria.core.inf.AbsNormalEntity;
 import com.arialyy.aria.orm.Ignore;
 
 /**
@@ -27,7 +27,7 @@ import com.arialyy.aria.orm.Ignore;
  * !!! 注意:CREATOR要进行@Ignore注解
  * !!!并且需要Parcelable时需要手动填写rowID;
  */
-public class DownloadEntity extends AbsEntity implements Parcelable {
+public class DownloadEntity extends AbsNormalEntity implements Parcelable {
   private String downloadUrl = ""; //下载路径
   private String downloadPath = ""; //保存路径
   private boolean isDownloadComplete = false;   //是否下载完成
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
new file mode 100644
index 00000000..e556c424
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.arialyy.aria.core.download;
+
+import com.arialyy.aria.core.inf.AbsGroupTarget;
+import com.arialyy.aria.core.inf.ITarget;
+import java.util.List;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ */
+public class DownloadGroupTarget extends AbsGroupTarget {
+
+  /**
+   * 设置保存路径组
+   */
+  public DownloadGroupTarget setDownloadPaths(List paths) {
+
+    return this;
+  }
+
+  @Override public int getPercent() {
+    return 0;
+  }
+}
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 32a255d3..045902dd 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
@@ -20,15 +20,12 @@ import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.inf.AbsReceiver;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.IReceiver;
-import com.arialyy.aria.core.command.CmdFactory;
-import com.arialyy.aria.core.command.AbsCmd;
+import com.arialyy.aria.core.command.normal.NormalCmdFactory;
 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;
 import java.io.File;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
@@ -142,8 +139,8 @@ public class DownloadReceiver extends AbsReceiver {
    */
   @Override public void stopAllTask() {
     AriaManager.getInstance(AriaManager.APP)
-        .setCmd(CmdFactory.getInstance()
-            .createCmd(targetName, new DownloadTaskEntity(), CmdFactory.TASK_STOP_ALL))
+        .setCmd(NormalCmdFactory.getInstance()
+            .createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL))
         .exe();
   }
 
@@ -154,8 +151,8 @@ public class DownloadReceiver extends AbsReceiver {
    */
   public void resumeAllTask() {
     AriaManager.getInstance(AriaManager.APP)
-        .setCmd(CmdFactory.getInstance()
-            .createCmd(targetName, new DownloadTaskEntity(), CmdFactory.TASK_RESUME_ALL))
+        .setCmd(NormalCmdFactory.getInstance()
+            .createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_RESUME_ALL))
         .exe();
   }
 
@@ -169,7 +166,7 @@ public class DownloadReceiver extends AbsReceiver {
     final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
     AriaManager.getInstance(AriaManager.APP)
         .setCmd(
-            CommonUtil.createCmd(targetName, new DownloadTaskEntity(), CmdFactory.TASK_CANCEL_ALL))
+            CommonUtil.createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_CANCEL_ALL))
         .exe();
 
     Set keys = ariaManager.getReceiver().keySet();
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 05e6c2d9..914c1ff7 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
@@ -17,31 +17,21 @@ package com.arialyy.aria.core.download;
 
 import android.support.annotation.NonNull;
 import android.text.TextUtils;
-import android.util.Log;
-import com.arialyy.aria.core.RequestEnum;
-import com.arialyy.aria.core.inf.AbsTarget;
+import com.arialyy.aria.core.inf.AbsNormalTarget;
 import com.arialyy.aria.core.queue.DownloadTaskQueue;
 import java.io.File;
-import java.util.Map;
 
 /**
  * Created by lyy on 2016/12/5.
  * https://github.com/AriaLyy/Aria
  */
-public class DownloadTarget extends AbsTarget {
+public class DownloadTarget extends
+    AbsNormalTarget {
 
   DownloadTarget(DownloadEntity entity, String targetName) {
-    this.entity = entity;
-    this.targetName = targetName;
-    taskEntity = new DownloadTaskEntity(entity);
-  }
-
-  @Override public void pause() {
-    super.pause();
-  }
-
-  @Override public void resume() {
-    super.resume();
+    this.mEntity = entity;
+    this.mTargetName = targetName;
+    mTaskEntity = new DownloadTaskEntity(entity);
   }
 
   /**
@@ -65,54 +55,14 @@ public class DownloadTarget extends AbsTarget headers) {
-    super._addHeaders(headers);
-    return this;
-  }
 
   /**
    * 下载任务是否存在
    */
   @Override public boolean taskExists() {
-    return DownloadTaskQueue.getInstance().getTask(entity.getDownloadUrl()) != null;
+    return DownloadTaskQueue.getInstance().getTask(mEntity.getDownloadUrl()) != null;
   }
 
-  /**
-   * 设置请求类型
-   *
-   * @param requestEnum {@link RequestEnum}
-   */
-  public DownloadTarget setRequestMode(RequestEnum requestEnum) {
-    super._setRequestMode(requestEnum);
-    return this;
-  }
 
   /**
    * 设置文件存储路径
@@ -122,8 +72,8 @@ public class DownloadTarget extends AbsTarget extends DbEntity implements IEntity, Parcelable {
+  /**
+   * 速度
+   */
+  @Ignore private long speed = 0;
+  /**
+   * 单位转换后的速度
+   */
+  @Ignore private String convertSpeed = "0b/s";
+
+  /**
+   * 扩展字段
+   */
+  private String str = "";
+  /**
+   * 文件大小
+   */
+  private long fileSize = 1;
+  private int state = STATE_WAIT;
+  /**
+   * 当前下载进度
+   */
+  private long currentProgress = 0;
+  /**
+   * 完成时间
+   */
+  private long completeTime;
+  /**
+   * 文件名
+   */
+  private String grooupName = "";
+
+  public long getSpeed() {
+    return speed;
+  }
+
+  public void setSpeed(long speed) {
+    this.speed = speed;
+  }
+
+  public String getConvertSpeed() {
+    return convertSpeed;
+  }
+
+  public void setConvertSpeed(String convertSpeed) {
+    this.convertSpeed = convertSpeed;
+  }
+
+  public String getStr() {
+    return str;
+  }
+
+  public void setStr(String str) {
+    this.str = str;
+  }
+
+  public long getFileSize() {
+    return fileSize;
+  }
+
+  public void setFileSize(long fileSize) {
+    this.fileSize = fileSize;
+  }
+
+  public int getState() {
+    return state;
+  }
+
+  public void setState(int state) {
+    this.state = state;
+  }
+
+  public long getCurrentProgress() {
+    return currentProgress;
+  }
+
+  public void setCurrentProgress(long currentProgress) {
+    this.currentProgress = currentProgress;
+  }
+
+  public long getCompleteTime() {
+    return completeTime;
+  }
+
+  public void setCompleteTime(long completeTime) {
+    this.completeTime = completeTime;
+  }
+
+  public AbsGroupEntity() {
+  }
+
+  @Override public int describeContents() {
+    return 0;
+  }
+
+  @Override public void writeToParcel(Parcel dest, int flags) {
+    dest.writeLong(this.speed);
+    dest.writeString(this.convertSpeed);
+    dest.writeString(this.str);
+    dest.writeLong(this.fileSize);
+    dest.writeInt(this.state);
+    dest.writeLong(this.currentProgress);
+    dest.writeLong(this.completeTime);
+  }
+
+  protected AbsGroupEntity(Parcel in) {
+    this.speed = in.readLong();
+    this.convertSpeed = in.readString();
+    this.str = in.readString();
+    this.fileSize = in.readLong();
+    this.state = in.readInt();
+    this.currentProgress = in.readLong();
+    this.completeTime = in.readLong();
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java
new file mode 100644
index 00000000..34834da5
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.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.RequestEnum;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ * 任务组超类
+ */
+public abstract class AbsGroupTarget
+    implements ITarget {
+
+  protected TASK_ENTITY mTaskEntity;
+
+  @Override public void resume() {
+
+  }
+
+  @Override public void start() {
+
+  }
+
+  @Override public void stop() {
+
+  }
+
+  @Override public void cancel() {
+
+  }
+
+  @Override public long getSize() {
+    return 0;
+  }
+
+  @Override public String getConvertSize() {
+    return null;
+  }
+
+  @Override public long getCurrentProgress() {
+    return 0;
+  }
+
+  @Override public TARGET addHeader(@NonNull String key, @NonNull String header) {
+    mTaskEntity.headers.put(key, header);
+    return (TARGET) this;
+  }
+
+  @Override public TARGET addHeaders(Map headers) {
+    if (headers != null && headers.size() > 0) {
+      Set keys = headers.keySet();
+      for (String key : keys) {
+        mTaskEntity.headers.put(key, headers.get(key));
+      }
+    }
+    return (TARGET) this;
+  }
+
+  @Override public TARGET setRequestMode(RequestEnum requestEnum) {
+    mTaskEntity.requestEnum = requestEnum;
+    return (TARGET) this;
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java
similarity index 95%
rename from Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java
rename to Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java
index e6b4d2b9..8411c960 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java
@@ -23,7 +23,7 @@ import com.arialyy.aria.orm.Ignore;
 /**
  * Created by AriaL on 2017/6/3.
  */
-public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable {
+public abstract class AbsNormalEntity extends DbEntity implements IEntity, Parcelable {
   /**
    * 速度
    */
@@ -130,7 +130,7 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
     this.fileName = fileName;
   }
 
-  public AbsEntity() {
+  public AbsNormalEntity() {
   }
 
   @Override public int describeContents() {
@@ -149,7 +149,7 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
     dest.writeString(this.fileName);
   }
 
-  protected AbsEntity(Parcel in) {
+  protected AbsNormalEntity(Parcel in) {
     this.speed = in.readLong();
     this.convertSpeed = in.readString();
     this.failNum = in.readInt();
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java
similarity index 61%
rename from Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
rename to Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java
index c3dcbb48..c281b038 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java
@@ -20,31 +20,29 @@ import android.text.TextUtils;
 import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.RequestEnum;
-import com.arialyy.aria.core.command.AbsCmd;
-import com.arialyy.aria.core.command.CmdFactory;
+import com.arialyy.aria.core.command.normal.NormalCmdFactory;
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.upload.UploadEntity;
 import com.arialyy.aria.util.CommonUtil;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 /**
  * Created by lyy on 2017/2/28.
  */
-public abstract class AbsTarget {
-  protected ENTITY entity;
-  protected TASK_ENTITY taskEntity;
-  protected String targetName;
+public abstract class AbsNormalTarget
+    implements ITarget {
+  protected ENTITY mEntity;
+  protected TASK_ENTITY mTaskEntity;
+  protected String mTargetName;
 
   /**
    * 设置扩展字段,用来保存你的其它数据,如果你的数据比较多,你可以把你的数据转换为JSON字符串,然后再存到Aria中
    *
    * @param str 扩展数据
    */
-  public AbsTarget setExtendField(String str) {
-    entity.setStr(str);
+  public AbsNormalTarget setExtendField(String str) {
+    mEntity.setStr(str);
     return this;
   }
 
@@ -53,7 +51,7 @@ public abstract class AbsTarget headers) {
+  public TARGET addHeaders(Map headers) {
     if (headers != null && headers.size() > 0) {
       Set keys = headers.keySet();
       for (String key : keys) {
-        taskEntity.headers.put(key, headers.get(key));
+        mTaskEntity.headers.put(key, headers.get(key));
       }
     }
+    return (TARGET) this;
   }
 
   /**
@@ -189,56 +204,60 @@ public abstract class AbsTarget cmds = new ArrayList<>();
-    //cmds.add(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_CREATE));
-    //cmds.add(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_START));
-    //cmds.clear();
+  @Override public void start() {
     AriaManager.getInstance(AriaManager.APP)
-        .setCmd(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_START))
+        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
         .exe();
   }
 
   /**
    * 停止下载
+   *
+   * @see #stop()
    */
-  protected void pause() {
+  @Deprecated protected void pause() {
+    stop();
+  }
+
+  @Override public void stop() {
     AriaManager.getInstance(AriaManager.APP)
-        .setCmd(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_STOP))
+        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP))
         .exe();
   }
 
   /**
    * 恢复下载
    */
-  protected void resume() {
+  @Override public void resume() {
     AriaManager.getInstance(AriaManager.APP)
-        .setCmd(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_START))
+        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
         .exe();
   }
 
   /**
    * 取消下载
    */
-  public void cancel() {
+  @Override public void cancel() {
     AriaManager.getInstance(AriaManager.APP)
-        .setCmd(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_CANCEL))
+        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL))
         .exe();
   }
 
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java
index 4e67339e..e19d6945 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java
@@ -20,7 +20,7 @@ package com.arialyy.aria.core.inf;
  * Created by AriaL on 2017/6/27.
  */
 
-public abstract class AbsReceiver implements IReceiver{
+public abstract class AbsReceiver implements IReceiver{
   public String targetName;
   public Object obj;
 
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
index 5521a882..3be9ea52 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
@@ -21,7 +21,7 @@ import com.arialyy.aria.util.CommonUtil;
 /**
  * Created by lyy on 2017/6/3.
  */
-public abstract class AbsTask
+public abstract class AbsTask
     implements ITask {
 
   protected ENTITY mEntity;
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 fe63cd37..8bbb8137 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
@@ -44,5 +44,5 @@ public abstract class AbsTaskEntity {
    */
   public boolean removeFile = false;
 
-  public abstract AbsEntity getEntity();
+  public abstract AbsNormalEntity getEntity();
 }
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
new file mode 100644
index 00000000..6a12071b
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java
@@ -0,0 +1,86 @@
+/*
+ * 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.RequestEnum;
+import java.util.Map;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ */
+public interface ITarget {
+  /**
+   * 任务文件大小
+   */
+  long getSize();
+
+  /**
+   * 转换后的大小
+   */
+  String getConvertSize();
+
+  /**
+   * 获取任务进度百分比
+   */
+  int getPercent();
+
+  /**
+   * 获取任务进度,如果任务存在,则返回当前进度
+   */
+  long getCurrentProgress();
+
+  /**
+   * 给url请求添加头部
+   *
+   * @param key 头部key
+   * @param header 头部value
+   */
+  TARGET addHeader(@NonNull String key, @NonNull String header) ;
+
+  /**
+   * 给url请求添加头部
+   */
+  TARGET addHeaders(Map headers);
+
+  /**
+   * 设置请求类型
+   *
+   * @param requestEnum {@link RequestEnum}
+   */
+  TARGET setRequestMode(RequestEnum requestEnum);
+
+  /**
+   * 开始下载
+   */
+  void start();
+
+  /**
+   * 停止下载
+   */
+  void stop();
+
+  /**
+   * 恢复下载
+   */
+  void resume();
+
+  /**
+   * 取消下载
+   */
+  void cancel();
+
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java b/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
index 27b4af9b..5535ad92 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
@@ -19,7 +19,11 @@ package com.arialyy.aria.core.inf;
  * Created by lyy on 2017/2/13.
  */
 
-public interface ITask {
+public interface ITask {
+
+  /**
+   * 获取
+   */
 
   /**
    * 暂停任务,并让任务处于等待状态
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 0bd83e6e..c2b1d239 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
@@ -17,11 +17,9 @@
 package com.arialyy.aria.core.queue;
 
 import android.util.Log;
-import com.arialyy.aria.core.Aria;
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.inf.AbsEntity;
+import com.arialyy.aria.core.inf.AbsNormalEntity;
 import com.arialyy.aria.core.inf.AbsTask;
-import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.queue.pool.CachePool;
 import com.arialyy.aria.core.queue.pool.ExecutePool;
@@ -31,7 +29,7 @@ import java.util.Set;
  * Created by lyy on 2017/2/23.
  * 任务队列
  */
-abstract class AbsTaskQueue
+abstract class AbsTaskQueue
     implements ITaskQueue {
   private final String TAG = "AbsTaskQueue";
   CachePool mCachePool = new CachePool<>();
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
new file mode 100644
index 00000000..4516ae3b
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadGroupTaskQueue.java
@@ -0,0 +1,24 @@
+/*
+ * 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.queue;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ * 任务组下载队列
+ */
+public class DownloadGroupTaskQueue {
+}
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 1bafa3e7..4931e673 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
@@ -20,11 +20,10 @@ import android.os.Message;
 import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.download.DownloadTask;
-import com.arialyy.aria.core.inf.AbsEntity;
+import com.arialyy.aria.core.inf.AbsNormalEntity;
 import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IEntity;
-import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.queue.ITaskQueue;
 import com.arialyy.aria.core.upload.UploadTask;
 import java.util.Iterator;
@@ -35,7 +34,7 @@ import java.util.concurrent.ConcurrentHashMap;
 /**
  * Created by lyy on 2017/6/4.
  */
-public abstract class AbsSchedulers, QUEUE extends ITaskQueue>
+public abstract class AbsSchedulers, QUEUE extends ITaskQueue>
     implements ISchedulers {
   private static final String TAG = "AbsSchedulers";
 
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 dafc69d9..e9105255 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
@@ -17,14 +17,14 @@ package com.arialyy.aria.core.upload;
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import com.arialyy.aria.core.inf.AbsEntity;
+import com.arialyy.aria.core.inf.AbsNormalEntity;
 import com.arialyy.aria.orm.Ignore;
 
 /**
  * Created by lyy on 2017/2/9.
  * 上传文件实体
  */
-public class UploadEntity extends AbsEntity implements Parcelable {
+public class UploadEntity extends AbsNormalEntity implements Parcelable {
 
   private String filePath;  //文件路径
   private boolean isComplete = false;
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 47ee5c6c..4430fb56 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
@@ -17,14 +17,12 @@ package com.arialyy.aria.core.upload;
 
 import android.support.annotation.NonNull;
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.command.AbsCmd;
-import com.arialyy.aria.core.command.CmdFactory;
-import com.arialyy.aria.core.download.DownloadReceiver;
+import com.arialyy.aria.core.command.normal.AbsNormalCmd;
+import com.arialyy.aria.core.command.normal.NormalCmdFactory;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.inf.AbsReceiver;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.IReceiver;
-import com.arialyy.aria.core.scheduler.DownloadSchedulers;
 import com.arialyy.aria.core.scheduler.ISchedulerListener;
 import com.arialyy.aria.core.scheduler.UploadSchedulers;
 import com.arialyy.aria.orm.DbEntity;
@@ -84,11 +82,11 @@ public class UploadReceiver extends AbsReceiver {
 
   @Override public void stopAllTask() {
     List allEntity = DbEntity.findAllData(UploadEntity.class);
-    List stopCmds = new ArrayList<>();
+    List stopCmds = new ArrayList<>();
     for (UploadEntity entity : allEntity) {
       if (entity.getState() == IEntity.STATE_RUNNING) {
         stopCmds.add(
-            CommonUtil.createCmd(targetName, new UploadTaskEntity(entity), CmdFactory.TASK_STOP));
+            CommonUtil.createCmd(targetName, new UploadTaskEntity(entity), NormalCmdFactory.TASK_STOP));
       }
     }
     AriaManager.getInstance(AriaManager.APP).setCmds(stopCmds).exe();
@@ -105,7 +103,7 @@ public class UploadReceiver extends AbsReceiver {
 
     AriaManager.getInstance(AriaManager.APP)
         .setCmd(
-            CommonUtil.createCmd(targetName, new DownloadTaskEntity(), CmdFactory.TASK_CANCEL_ALL))
+            CommonUtil.createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_CANCEL_ALL))
         .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 1868d51c..cdbde0e1 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,28 +16,25 @@
 package com.arialyy.aria.core.upload;
 
 import android.support.annotation.NonNull;
-import com.arialyy.aria.core.RequestEnum;
-import com.arialyy.aria.core.inf.AbsTarget;
+import com.arialyy.aria.core.inf.AbsNormalTarget;
 import com.arialyy.aria.core.queue.UploadTaskQueue;
-import com.arialyy.aria.orm.DbEntity;
-import java.util.Map;
 
 /**
  * Created by lyy on 2017/2/28.
  */
-public class UploadTarget extends AbsTarget {
+public class UploadTarget extends AbsNormalTarget {
 
   UploadTarget(UploadEntity entity, String targetName) {
-    this.entity = entity;
-    this.targetName = targetName;
-    taskEntity = new UploadTaskEntity(entity);
+    this.mEntity = entity;
+    this.mTargetName = targetName;
+    mTaskEntity = new UploadTaskEntity(entity);
   }
 
   /**
    * 设置userAgent
    */
   public UploadTarget setUserAngent(@NonNull String userAgent) {
-    taskEntity.userAgent = userAgent;
+    mTaskEntity.userAgent = userAgent;
     return this;
   }
 
@@ -47,7 +44,7 @@ public class UploadTarget extends AbsTarget {
    * @param uploadUrl 上传路径
    */
   public UploadTarget setUploadUrl(@NonNull String uploadUrl) {
-    taskEntity.uploadUrl = uploadUrl;
+    mTaskEntity.uploadUrl = uploadUrl;
     return this;
   }
 
@@ -57,7 +54,7 @@ public class UploadTarget extends AbsTarget {
    * @param attachment 附件key
    */
   public UploadTarget setAttachment(@NonNull String attachment) {
-    taskEntity.attachment = attachment;
+    mTaskEntity.attachment = attachment;
     return this;
   }
 
@@ -65,7 +62,7 @@ public class UploadTarget extends AbsTarget {
    * 设置文件名
    */
   public UploadTarget setFileName(String fileName) {
-    entity.setFileName(fileName);
+    mEntity.setFileName(fileName);
     return this;
   }
 
@@ -75,28 +72,7 @@ public class UploadTarget extends AbsTarget {
    * @param contentType tip:multipart/form-data
    */
   public UploadTarget setContentType(String contentType) {
-    taskEntity.contentType = contentType;
-    return this;
-  }
-
-  /**
-   * 给url请求添加头部
-   *
-   * @param key 头部key
-   * @param header 头部value
-   */
-  public UploadTarget addHeader(@NonNull String key, @NonNull String header) {
-    super._addHeader(key, header);
-    return this;
-  }
-
-  /**
-   * 给url请求添加头部
-   *
-   * @param headers key为http头部的key,Value为http头对应的配置
-   */
-  public UploadTarget addHeaders(Map headers) {
-    super._addHeaders(headers);
+    mTaskEntity.contentType = contentType;
     return this;
   }
 
@@ -104,28 +80,16 @@ public class UploadTarget extends AbsTarget {
    * 下载任务是否存在
    */
   @Override public boolean taskExists() {
-    return UploadTaskQueue.getInstance().getTask(entity.getFilePath()) != null;
-  }
-
-  /**
-   * 设置请求类型
-   *
-   * @param requestEnum {@link RequestEnum}
-   */
-  public UploadTarget setRequestMode(RequestEnum requestEnum) {
-    super._setRequestMode(requestEnum);
-    return this;
+    return UploadTaskQueue.getInstance().getTask(mEntity.getFilePath()) != null;
   }
 
-  private UploadEntity getDownloadEntity() {
-    return entity;
-  }
 
   /**
    * 是否在下载
    */
   public boolean isUploading() {
-    UploadTask task = UploadTaskQueue.getInstance().getTask(entity);
+    UploadTask task = UploadTaskQueue.getInstance().getTask(mEntity);
     return task != null && task.isRunning();
   }
+
 }
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 2b42354a..d9407c60 100644
--- a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
@@ -23,8 +23,8 @@ import android.net.Uri;
 import android.text.TextUtils;
 import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.command.CmdFactory;
-import com.arialyy.aria.core.command.AbsCmd;
+import com.arialyy.aria.core.command.normal.NormalCmdFactory;
+import com.arialyy.aria.core.command.normal.AbsNormalCmd;
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.upload.UploadEntity;
@@ -225,8 +225,8 @@ public class CommonUtil {
     }
   }
 
-  public static  AbsCmd createCmd(String target, T entity, int cmd) {
-    return CmdFactory.getInstance().createCmd(target, entity, cmd);
+  public static  AbsNormalCmd createCmd(String target, T entity, int cmd) {
+    return NormalCmdFactory.getInstance().createCmd(target, entity, cmd);
   }
 
   /**

From 8cf4c36d719d353175307dc69f38c6a1879f0bc1 Mon Sep 17 00:00:00 2001
From: AriaLyy <511455842@qq.com>
Date: Sat, 1 Jul 2017 20:44:51 +0800
Subject: [PATCH 13/34] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E7=BB=84=E5=AE=9E?=
 =?UTF-8?q?=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../aria/core/command/normal/AddCmd.java      |   4 +-
 .../aria/core/command/normal/CancelCmd.java   |   4 +-
 .../command/normal/HighestPriorityCmd.java    |   4 +-
 .../core/command/normal/ResumeAllCmd.java     |   8 +-
 .../aria/core/command/normal/StartCmd.java    |   4 +-
 .../aria/core/command/normal/StopCmd.java     |   4 +-
 .../core/download/DownloadGroupEntity.java    |  65 ++++
 .../core/download/DownloadGroupListener.java  |  24 ++
 .../aria/core/download/DownloadGroupTask.java | 269 ++++++++++++++
 .../download/DownloadGroupTaskEntity.java     |  28 ++
 .../aria/core/download/DownloadTask.java      |  30 +-
 .../core/download/DownloadTaskEntity.java     |  13 +-
 .../aria/core/download/DownloadTaskGroup.java |   8 -
 .../downloader/ChildThreadConfigEntity.java   |  24 ++
 .../{ => downloader}/ConnectionHelp.java      |   3 +-
 .../downloader/DownloadGroupUtil.java         | 240 ++++++++++++
 .../{ => downloader}/DownloadListener.java    |   5 +-
 .../DownloadStateConstance.java               |   2 +-
 .../download/downloader/DownloadThreader.java | 346 ++++++++++++++++++
 .../{ => downloader}/DownloadUtil.java        |  58 ++-
 .../download/downloader/FileInfoThread.java   | 161 ++++++++
 .../{ => downloader}/IDownloadListener.java   |   2 +-
 .../{ => downloader}/IDownloadUtil.java       |  22 +-
 .../{ => downloader}/SingleThreadTask.java    |   6 +-
 .../com/arialyy/aria/core/inf/AbsEntity.java  | 136 +++++++
 .../arialyy/aria/core/inf/AbsGroupEntity.java | 106 +-----
 .../arialyy/aria/core/inf/AbsGroupTask.java   |  71 ++++
 .../aria/core/inf/AbsNormalEntity.java        | 104 +-----
 .../arialyy/aria/core/inf/AbsNormalTask.java  | 100 +++++
 .../com/arialyy/aria/core/inf/AbsTask.java    |  89 +----
 .../arialyy/aria/core/inf/AbsTaskEntity.java  |  24 +-
 .../java/com/arialyy/aria/core/inf/ITask.java |  22 +-
 .../arialyy/aria/core/queue/AbsTaskQueue.java |  16 +-
 .../aria/core/queue/DownloadTaskQueue.java    |   4 +-
 .../arialyy/aria/core/queue/ITaskQueue.java   |   5 +-
 .../aria/core/queue/UploadTaskQueue.java      |   4 +-
 .../aria/core/queue/pool/GroupCachePool.java  |  23 ++
 .../core/queue/pool/GroupExecutePool.java     |  23 ++
 .../{CachePool.java => NormalCachePool.java}  |   6 +-
 ...xecutePool.java => NormalExecutePool.java} |   6 +-
 .../aria/core/scheduler/AbsSchedulers.java    |   4 +-
 .../arialyy/aria/core/upload/UploadTask.java  |   5 +-
 42 files changed, 1664 insertions(+), 418 deletions(-)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java
 delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskGroup.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/ChildThreadConfigEntity.java
 rename Aria/src/main/java/com/arialyy/aria/core/download/{ => downloader}/ConnectionHelp.java (97%)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
 rename Aria/src/main/java/com/arialyy/aria/core/download/{ => downloader}/DownloadListener.java (92%)
 rename Aria/src/main/java/com/arialyy/aria/core/download/{ => downloader}/DownloadStateConstance.java (97%)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadThreader.java
 rename Aria/src/main/java/com/arialyy/aria/core/download/{ => downloader}/DownloadUtil.java (92%)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/download/downloader/FileInfoThread.java
 rename Aria/src/main/java/com/arialyy/aria/core/download/{ => downloader}/IDownloadListener.java (97%)
 rename Aria/src/main/java/com/arialyy/aria/core/download/{ => downloader}/IDownloadUtil.java (82%)
 rename Aria/src/main/java/com/arialyy/aria/core/download/{ => downloader}/SingleThreadTask.java (98%)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTask.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupCachePool.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupExecutePool.java
 rename Aria/src/main/java/com/arialyy/aria/core/queue/pool/{CachePool.java => NormalCachePool.java} (96%)
 rename Aria/src/main/java/com/arialyy/aria/core/queue/pool/{ExecutePool.java => NormalExecutePool.java} (96%)

diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
index e848813b..9e0d094e 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
@@ -17,7 +17,7 @@
 package com.arialyy.aria.core.command.normal;
 
 import android.util.Log;
-import com.arialyy.aria.core.inf.AbsTask;
+import com.arialyy.aria.core.inf.AbsNormalTask;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
@@ -33,7 +33,7 @@ class AddCmd extends AbsNormalCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
+    AbsNormalTask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
       mTaskEntity.getEntity().setState(IEntity.STATE_WAIT);
       mQueue.createTask(mTargetName, mTaskEntity);
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
index d12f0cad..5621da16 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
@@ -17,7 +17,7 @@
 package com.arialyy.aria.core.command.normal;
 
 import android.text.TextUtils;
-import com.arialyy.aria.core.inf.AbsTask;
+import com.arialyy.aria.core.inf.AbsNormalTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
@@ -31,7 +31,7 @@ class CancelCmd extends AbsNormalCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
+    AbsNormalTask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
       task = mQueue.createTask(mTargetName, mTaskEntity);
     }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java
index a52555a8..f12b6487 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java
@@ -16,7 +16,7 @@
 package com.arialyy.aria.core.command.normal;
 
 import android.text.TextUtils;
-import com.arialyy.aria.core.inf.AbsTask;
+import com.arialyy.aria.core.inf.AbsNormalTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
@@ -39,7 +39,7 @@ final class HighestPriorityCmd extends AbsNormalCmd
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
+    AbsNormalTask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
       task = mQueue.createTask(mTargetName, mTaskEntity);
     }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
index 58b26bdc..8ae46e85 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
@@ -3,7 +3,7 @@ package com.arialyy.aria.core.command.normal;
 import android.util.Log;
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.core.inf.AbsTask;
+import com.arialyy.aria.core.inf.AbsNormalTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.orm.DbEntity;
@@ -29,7 +29,7 @@ final class ResumeAllCmd extends AbsNormalCmd {
     for (DownloadEntity entity : allEntity) {
       int exeNum = mQueue.getExePoolSize();
       if (exeNum == 0 || exeNum < mQueue.getMaxTaskNum()) {
-        AbsTask task = createTask(entity);
+        AbsNormalTask task = createTask(entity);
         mQueue.startTask(task);
       } else {
         entity.setState(IEntity.STATE_WAIT);
@@ -38,8 +38,8 @@ final class ResumeAllCmd extends AbsNormalCmd {
     }
   }
 
-  private AbsTask createTask(DownloadEntity entity) {
-    AbsTask task = mQueue.getTask(entity);
+  private AbsNormalTask createTask(DownloadEntity entity) {
+    AbsNormalTask task = mQueue.getTask(entity);
     if (task == null) {
       DownloadTaskEntity taskEntity = new DownloadTaskEntity(entity);
       task = mQueue.createTask(mTargetName, taskEntity);
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 2b042a27..39f58cd7 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
@@ -19,7 +19,7 @@ package com.arialyy.aria.core.command.normal;
 import android.text.TextUtils;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.QueueMod;
-import com.arialyy.aria.core.inf.AbsTask;
+import com.arialyy.aria.core.inf.AbsNormalTask;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
@@ -47,7 +47,7 @@ class StartCmd extends AbsNormalCmd {
       maxTaskNum = manager.getUploadConfig().getMaxTaskNum();
     }
 
-    AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
+    AbsNormalTask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
       task = mQueue.createTask(mTargetName, mTaskEntity);
       if (!TextUtils.isEmpty(mTargetName)) {
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
index 9d0b0811..84d55329 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
@@ -18,7 +18,7 @@ package com.arialyy.aria.core.command.normal;
 
 import android.text.TextUtils;
 import android.util.Log;
-import com.arialyy.aria.core.inf.AbsTask;
+import com.arialyy.aria.core.inf.AbsNormalTask;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
@@ -34,7 +34,7 @@ class StopCmd extends AbsNormalCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
+    AbsNormalTask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
       if (mTaskEntity.getEntity().getState() == IEntity.STATE_RUNNING) {
         task = mQueue.createTask(mTargetName, mTaskEntity);
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
new file mode 100644
index 00000000..4cfaa7a3
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.arialyy.aria.core.download;
+
+import android.os.Parcel;
+import com.arialyy.aria.core.inf.AbsGroupEntity;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ * 下载任务组实体
+ */
+public class DownloadGroupEntity extends AbsGroupEntity {
+
+  private List mChild = new LinkedList<>();
+
+  public List getChild() {
+    return mChild;
+  }
+
+  public void setChild(List child) {
+    this.mChild = child;
+  }
+
+  @Override public int describeContents() {
+    return 0;
+  }
+
+  @Override public void writeToParcel(Parcel dest, int flags) {
+    super.writeToParcel(dest, flags);
+    dest.writeTypedList(this.mChild);
+  }
+
+  public DownloadGroupEntity() {
+  }
+
+  protected DownloadGroupEntity(Parcel in) {
+    super(in);
+    this.mChild = in.createTypedArrayList(DownloadEntity.CREATOR);
+  }
+
+  public static final Creator CREATOR = new Creator() {
+    @Override public DownloadGroupEntity createFromParcel(Parcel source) {
+      return new DownloadGroupEntity(source);
+    }
+
+    @Override public DownloadGroupEntity[] newArray(int size) {
+      return new DownloadGroupEntity[size];
+    }
+  };
+}
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
new file mode 100644
index 00000000..9a60b807
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+/**
+ * Created by AriaL on 2017/6/30.
+ */
+
+public class DownloadGroupListener {
+
+}
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
new file mode 100644
index 00000000..308c041e
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java
@@ -0,0 +1,269 @@
+///*
+// * 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.content.Context;
+//import android.os.Handler;
+//import android.util.SparseArray;
+//import com.arialyy.aria.core.Aria;
+//import com.arialyy.aria.core.AriaManager;
+//import com.arialyy.aria.core.download.downloader.DownloadListener;
+//import com.arialyy.aria.core.download.downloader.DownloadUtil;
+//import com.arialyy.aria.core.inf.AbsGroupTask;
+//import com.arialyy.aria.core.inf.IEntity;
+//import com.arialyy.aria.core.scheduler.DownloadSchedulers;
+//import com.arialyy.aria.core.scheduler.ISchedulers;
+//import com.arialyy.aria.util.CheckUtil;
+//import com.arialyy.aria.util.CommonUtil;
+//import java.lang.ref.WeakReference;
+//import java.util.HashMap;
+//import java.util.List;
+//import java.util.Map;
+//import java.util.concurrent.ExecutorService;
+//import java.util.concurrent.Executors;
+//
+///**
+// * Created by AriaL on 2017/6/27.
+// * 任务组任务
+// */
+//public class DownloadGroupTask extends AbsGroupTask {
+//  DListener mListener;
+//  SparseArray mUtils = new SparseArray<>();
+//  boolean isStop = false;
+//
+//  private ExecutorService mFixedThreadPool;
+//
+//  private DownloadGroupTask(DownloadTaskEntity taskEntity, Handler outHandler) {
+//    mTaskEntity = taskEntity;
+//    mEntity = taskEntity.groupEntity;
+//    mOutHandler = outHandler;
+//    mContext = AriaManager.APP;
+//    mListener = new DListener(mContext, this, mOutHandler);
+//    mFixedThreadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
+//  }
+//
+//  @Override public void start() {
+//    List childs = mEntity.getChild();
+//    int i = 1;
+//    mListener.sendInState2Target(ISchedulers.PRE);
+//    for (DownloadEntity entity : childs) {
+//      DownloadUtil util = createChildDownload(entity);
+//      if (isStop) break;
+//      mUtils.append(i, util);
+//      mFixedThreadPool.execute(util);
+//      i++;
+//    }
+//  }
+//
+//  /**
+//   * 创建任务组单个任务下载工具
+//   */
+//  private DownloadUtil createChildDownload(DownloadEntity entity) {
+//    DownloadTaskEntity taskEntity = new DownloadTaskEntity(entity);
+//    taskEntity.headers = mTaskEntity.headers;
+//    taskEntity.requestEnum = mTaskEntity.requestEnum;
+//    taskEntity.redirectUrlKey = mTaskEntity.redirectUrlKey;
+//    taskEntity.removeFile = mTaskEntity.removeFile;
+//    return new DownloadUtil(mContext, taskEntity, mListener);
+//  }
+//
+//  @Override public void stop() {
+//    isStop = true;
+//    if (mFixedThreadPool != null) {
+//      mFixedThreadPool.shutdown();
+//    }
+//    for (int i = 1, len = mUtils.size(); i <= len; i++) {
+//      DownloadUtil util = mUtils.get(i);
+//      if (util != null && util.isDownloading()) {
+//        util.stopDownload();
+//      }
+//    }
+//  }
+//
+//  @Override public void cancel() {
+//    isStop = true;
+//    if (mFixedThreadPool != null) {
+//      mFixedThreadPool.shutdown();
+//    }
+//    for (int i = 1, len = mUtils.size(); i <= len; i++) {
+//      DownloadUtil util = mUtils.get(i);
+//      if (util != null) {
+//        util.cancelDownload();
+//      }
+//    }
+//  }
+//
+//  /**
+//   * 下载监听类
+//   */
+//  private static class DListener extends DownloadListener {
+//    WeakReference outHandler;
+//    WeakReference wTask;
+//    Context context;
+//    long lastLen = 0;   //上一次发送长度
+//    long lastTime = 0;
+//    long INTERVAL_TIME = 1000;   //1m更新周期
+//    boolean isFirst = true;
+//    DownloadGroupEntity groupEntity;
+//    DownloadGroupTask task;
+//    boolean isConvertSpeed = false;
+//    Map mEntityMap = new HashMap<>();
+//
+//    DListener(Context context, DownloadGroupTask task, Handler outHandler) {
+//      this.context = context;
+//      this.outHandler = new WeakReference<>(outHandler);
+//      this.wTask = new WeakReference<>(task);
+//      this.task = wTask.get();
+//      this.groupEntity = this.task.getEntity();
+//      final AriaManager manager = AriaManager.getInstance(context);
+//      isConvertSpeed = manager.getDownloadConfig().isConvertSpeed();
+//      for (DownloadEntity entity : groupEntity.getChild()) {
+//        mEntityMap.put(entity.getDownloadUrl(), entity);
+//      }
+//    }
+//
+//    @Override public void onPre(String url) {
+//      saveData(url, IEntity.STATE_PRE, -1);
+//    }
+//
+//    @Override public void onPostPre(String url, long fileSize) {
+//      DownloadEntity entity = mEntityMap.get(url);
+//      if (entity != null){
+//        entity.setFileSize(fileSize);
+//      }
+//      saveData(url, IEntity.STATE_POST_PRE, -1);
+//    }
+//
+//    @Override public void onStart(String url, long startLocation) {
+//      downloadEntity.setState(IEntity.STATE_RUNNING);
+//      sendInState2Target(ISchedulers.START);
+//      sendIntent(Aria.ACTION_START, startLocation);
+//    }
+//
+//    @Override public void onResume(String url, long resumeLocation) {
+//      downloadEntity.setState(IEntity.STATE_RUNNING);
+//      sendInState2Target(ISchedulers.RESUME);
+//      sendIntent(Aria.ACTION_RESUME, resumeLocation);
+//    }
+//
+//    @Override public void onProgress(String url, long currentLocation) {
+//      if (System.currentTimeMillis() - lastTime > INTERVAL_TIME) {
+//        long speed = currentLocation - lastLen;
+//        sendIntent.putExtra(Aria.CURRENT_LOCATION, currentLocation);
+//        sendIntent.putExtra(Aria.CURRENT_SPEED, speed);
+//        lastTime = System.currentTimeMillis();
+//        if (isFirst) {
+//          speed = 0;
+//          isFirst = false;
+//        }
+//        handleSpeed(speed);
+//        downloadEntity.setCurrentProgress(currentLocation);
+//        lastLen = currentLocation;
+//        sendInState2Target(ISchedulers.RUNNING);
+//        context.sendBroadcast(sendIntent);
+//      }
+//    }
+//
+//    @Override public void onStop(String url, long stopLocation) {
+//      downloadEntity.setState(task.isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP);
+//      handleSpeed(0);
+//      sendInState2Target(ISchedulers.STOP);
+//      sendIntent(Aria.ACTION_STOP, stopLocation);
+//    }
+//
+//    @Override public void onCancel(String url) {
+//      downloadEntity.setState(IEntity.STATE_CANCEL);
+//      handleSpeed(0);
+//      sendInState2Target(ISchedulers.CANCEL);
+//      sendIntent(Aria.ACTION_CANCEL, -1);
+//      downloadEntity.deleteData();
+//    }
+//
+//    @Override public void onComplete(String url) {
+//      downloadEntity.setState(IEntity.STATE_COMPLETE);
+//      downloadEntity.setDownloadComplete(true);
+//      handleSpeed(0);
+//      sendInState2Target(ISchedulers.COMPLETE);
+//      sendIntent(Aria.ACTION_COMPLETE, downloadEntity.getFileSize());
+//    }
+//
+//    @Override public void onFail(String url) {
+//      downloadEntity.setFailNum(downloadEntity.getFailNum() + 1);
+//      downloadEntity.setState(IEntity.STATE_FAIL);
+//      handleSpeed(0);
+//      sendInState2Target(ISchedulers.FAIL);
+//      sendIntent(Aria.ACTION_FAIL, -1);
+//    }
+//
+//    private void handleSpeed(long speed) {
+//      if (isConvertSpeed) {
+//        downloadEntity.setConvertSpeed(CommonUtil.formatFileSize(speed) + "/s");
+//      } else {
+//        downloadEntity.setSpeed(speed);
+//      }
+//    }
+//
+//    /**
+//     * 将任务状态发送给下载器
+//     *
+//     * @param state {@link DownloadSchedulers#START}
+//     */
+//    private void sendInState2Target(int state) {
+//      if (outHandler.get() != null) {
+//        outHandler.get().obtainMessage(state, task).sendToTarget();
+//      }
+//    }
+//
+//    private void saveData(String url, int state, long location) {
+//      DownloadEntity child = mEntityMap.get(url);
+//      if (child != null) {
+//        child.setState(state);
+//        child.setDownloadComplete(state == IEntity.STATE_COMPLETE);
+//        child.setCurrentProgress(location);
+//        child.update();
+//      }
+//    }
+//  }
+//
+//  public static class Builder {
+//    DownloadTaskEntity taskEntity;
+//    Handler outHandler;
+//    String targetName;
+//
+//    public Builder(String targetName, DownloadTaskEntity taskEntity) {
+//      CheckUtil.checkTaskEntity(taskEntity);
+//      this.targetName = targetName;
+//      this.taskEntity = taskEntity;
+//    }
+//
+//    /**
+//     * 设置自定义Handler处理下载状态时间
+//     *
+//     * @param schedulers {@link ISchedulers}
+//     */
+//    public DownloadGroupTask.Builder setOutHandler(ISchedulers schedulers) {
+//      this.outHandler = new Handler(schedulers);
+//      return this;
+//    }
+//
+//    public DownloadGroupTask build() {
+//      DownloadGroupTask task = new DownloadGroupTask(taskEntity, outHandler);
+//      task.setTargetName(targetName);
+//      taskEntity.downloadEntity.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
new file mode 100644
index 00000000..94c7cd29
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.arialyy.aria.core.download;
+
+import com.arialyy.aria.core.inf.AbsTaskEntity;
+
+/**
+ * Created by AriaL on 2017/7/1.
+ */
+public class DownloadGroupTaskEntity extends AbsTaskEntity {
+
+  public DownloadGroupTaskEntity(DownloadGroupEntity entity) {
+    this.entity = entity;
+  }
+}
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 f72d68b2..46d87b73 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
@@ -22,7 +22,10 @@ import android.os.Handler;
 import android.util.Log;
 import com.arialyy.aria.core.Aria;
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.inf.AbsTask;
+import com.arialyy.aria.core.download.downloader.DownloadListener;
+import com.arialyy.aria.core.download.downloader.DownloadUtil;
+import com.arialyy.aria.core.download.downloader.IDownloadListener;
+import com.arialyy.aria.core.inf.AbsNormalTask;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.scheduler.DownloadSchedulers;
 import com.arialyy.aria.core.scheduler.ISchedulers;
@@ -35,12 +38,11 @@ import java.lang.ref.WeakReference;
  * Created by lyy on 2016/8/11.
  * 下载任务类
  */
-public class DownloadTask extends AbsTask {
+public class DownloadTask extends AbsNormalTask {
   public static final String TAG = "DownloadTask";
 
   private IDownloadListener mListener;
-  private Handler mOutHandler;
-  private IDownloadUtil mUtil;
+  private DownloadUtil mUtil;
   private boolean isWait = false;
 
   private DownloadTask(DownloadTaskEntity taskEntity, Handler outHandler) {
@@ -98,7 +100,6 @@ public class DownloadTask extends AbsTask {
    * 暂停任务,并让任务处于等待状态
    */
   @Override public void stopAndWait() {
-    super.stopAndWait();
     stop(true);
   }
 
@@ -166,9 +167,6 @@ public class DownloadTask extends AbsTask {
         mContext.sendBroadcast(intent);
       }
       mUtil.cancelDownload();
-      mUtil.delConfigFile();
-      mUtil.delTempFile();
-      mEntity.deleteData();
     }
   }
 
@@ -232,7 +230,6 @@ public class DownloadTask extends AbsTask {
     }
 
     @Override public void supportBreakpoint(boolean support) {
-      super.supportBreakpoint(support);
       if (!support) {
         sendInState2Target(ISchedulers.SUPPORT_BREAK_POINT);
         sendIntent(Aria.ACTION_SUPPORT_BREAK_POINT, -1);
@@ -240,14 +237,12 @@ public class DownloadTask extends AbsTask {
     }
 
     @Override public void onPre() {
-      super.onPre();
       downloadEntity.setState(IEntity.STATE_PRE);
       sendInState2Target(ISchedulers.PRE);
       sendIntent(Aria.ACTION_PRE, -1);
     }
 
     @Override public void onPostPre(long fileSize) {
-      super.onPostPre(fileSize);
       downloadEntity.setFileSize(fileSize);
       downloadEntity.setState(IEntity.STATE_POST_PRE);
       sendInState2Target(ISchedulers.POST_PRE);
@@ -255,25 +250,20 @@ public class DownloadTask extends AbsTask {
     }
 
     @Override public void onResume(long resumeLocation) {
-      super.onResume(resumeLocation);
       downloadEntity.setState(IEntity.STATE_RUNNING);
       sendInState2Target(ISchedulers.RESUME);
       sendIntent(Aria.ACTION_RESUME, resumeLocation);
     }
 
     @Override public void onStart(long startLocation) {
-      super.onStart(startLocation);
       downloadEntity.setState(IEntity.STATE_RUNNING);
       sendInState2Target(ISchedulers.START);
       sendIntent(Aria.ACTION_START, startLocation);
     }
 
     @Override public void onProgress(long currentLocation) {
-      super.onProgress(currentLocation);
       if (System.currentTimeMillis() - lastTime > INTERVAL_TIME) {
         long speed = currentLocation - lastLen;
-        sendIntent.putExtra(Aria.CURRENT_LOCATION, currentLocation);
-        sendIntent.putExtra(Aria.CURRENT_SPEED, speed);
         lastTime = System.currentTimeMillis();
         if (isFirst) {
           speed = 0;
@@ -283,12 +273,15 @@ public class DownloadTask extends AbsTask {
         downloadEntity.setCurrentProgress(currentLocation);
         lastLen = currentLocation;
         sendInState2Target(ISchedulers.RUNNING);
+
+        if (!isOpenBroadCast) return;
+        sendIntent.putExtra(Aria.CURRENT_LOCATION, currentLocation);
+        sendIntent.putExtra(Aria.CURRENT_SPEED, speed);
         context.sendBroadcast(sendIntent);
       }
     }
 
     @Override public void onStop(long stopLocation) {
-      super.onStop(stopLocation);
       downloadEntity.setState(task.isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP);
       handleSpeed(0);
       sendInState2Target(ISchedulers.STOP);
@@ -296,7 +289,6 @@ public class DownloadTask extends AbsTask {
     }
 
     @Override public void onCancel() {
-      super.onCancel();
       downloadEntity.setState(IEntity.STATE_CANCEL);
       handleSpeed(0);
       sendInState2Target(ISchedulers.CANCEL);
@@ -305,7 +297,6 @@ public class DownloadTask extends AbsTask {
     }
 
     @Override public void onComplete() {
-      super.onComplete();
       downloadEntity.setState(IEntity.STATE_COMPLETE);
       downloadEntity.setDownloadComplete(true);
       handleSpeed(0);
@@ -314,7 +305,6 @@ public class DownloadTask extends AbsTask {
     }
 
     @Override public void onFail() {
-      super.onFail();
       downloadEntity.setFailNum(downloadEntity.getFailNum() + 1);
       downloadEntity.setState(IEntity.STATE_FAIL);
       handleSpeed(0);
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 75f6a17b..70439cba 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
@@ -21,17 +21,12 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
  * Created by lyy on 2017/1/23.
  * 下载任务实体
  */
-public class DownloadTaskEntity extends AbsTaskEntity {
+public class DownloadTaskEntity extends AbsTaskEntity {
 
-  public DownloadEntity downloadEntity;
-
-  public DownloadTaskEntity(){}
-
-  public DownloadTaskEntity(DownloadEntity downloadEntity) {
-    this.downloadEntity = downloadEntity;
+  public DownloadTaskEntity() {
   }
 
-  @Override public DownloadEntity getEntity() {
-    return downloadEntity;
+  public DownloadTaskEntity(DownloadEntity entity) {
+    this.entity = entity;
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskGroup.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskGroup.java
deleted file mode 100644
index edb322a4..00000000
--- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskGroup.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.arialyy.aria.core.download;
-
-/**
- * Created by AriaL on 2017/6/27.
- */
-
-public class DownloadTaskGroup {
-}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ChildThreadConfigEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ChildThreadConfigEntity.java
new file mode 100644
index 00000000..94b865ea
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ChildThreadConfigEntity.java
@@ -0,0 +1,24 @@
+package com.arialyy.aria.core.download.downloader;
+
+import com.arialyy.aria.core.download.DownloadTaskEntity;
+import java.io.File;
+
+/**
+ * 子线程下载信息类
+ */
+final class ChildThreadConfigEntity {
+  //线程Id
+  int THREAD_ID;
+  //下载文件大小
+  long FILE_SIZE;
+  //子线程启动下载位置
+  long START_LOCATION;
+  //子线程结束下载位置
+  long END_LOCATION;
+  //下载路径
+  File TEMP_FILE;
+  String DOWNLOAD_URL;
+  String CONFIG_FILE_PATH;
+  DownloadTaskEntity DOWNLOAD_TASK_ENTITY;
+  boolean IS_SUPPORT_BREAK_POINT = true;
+}
\ No newline at end of file
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/ConnectionHelp.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
similarity index 97%
rename from Aria/src/main/java/com/arialyy/aria/core/download/ConnectionHelp.java
rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
index e05f0aee..028db87c 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/ConnectionHelp.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
@@ -13,8 +13,9 @@
  * 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.downloader;
 
+import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.util.SSLContextUtil;
 import java.io.IOException;
 import java.net.HttpURLConnection;
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
new file mode 100644
index 00000000..914f70a9
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
@@ -0,0 +1,240 @@
+/*
+ * 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.downloader;
+
+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.IEntity;
+import com.arialyy.aria.orm.DbEntity;
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Created by AriaL on 2017/6/30.
+ * 下载组工具
+ */
+public class DownloadGroupUtil implements IDownloadUtil {
+  private static final String TAG = "DownloadGroupUtil";
+  /**
+   * 任务组所有任务总大小
+   */
+  private long mTotalSize = 0;
+  private long mCurrentProgress = 0;
+  private ExecutorService mInfoPool;
+  private ExecutorService mExePool;
+  private IDownloadListener mListener;
+  private DownloadGroupTaskEntity mTaskEntity;
+  private boolean isRunning = true;
+  /**
+   * 保存所有没有下载完成的任务,key为下载地址
+   */
+  private Map mExeMap = new HashMap<>();
+
+  /**
+   * 下载失败的映射表,key为下载地址
+   */
+  private Map mFailMap = new HashMap<>();
+
+  /**
+   * 下载器映射表,key为下载地址
+   */
+  private Map mDownloaderMap = new HashMap<>();
+
+  DownloadGroupUtil(IDownloadListener listener, DownloadGroupTaskEntity taskEntity) {
+    mListener = listener;
+    mTaskEntity = taskEntity;
+    mInfoPool = Executors.newCachedThreadPool();
+
+    for (DownloadEntity entity : mTaskEntity.entity.getChild()) {
+      File file = new File(entity.getDownloadPath());
+      if (entity.isDownloadComplete() && file.exists()) {
+        mTotalSize += entity.getFileSize();
+      } else {
+        mExeMap.put(entity.getDownloadUrl(), createDownloadTask(entity));
+      }
+      mCurrentProgress += entity.getCurrentProgress();
+    }
+  }
+
+  @Override public long getFileSize() {
+    return mTotalSize;
+  }
+
+  @Override public long getCurrentLocation() {
+    return mCurrentProgress;
+  }
+
+  @Override public boolean isDownloading() {
+    return isRunning;
+  }
+
+  @Override public void cancelDownload() {
+    isRunning = false;
+    if (!mInfoPool.isShutdown()) {
+      mInfoPool.shutdown();
+    }
+
+    Set keys = mDownloaderMap.keySet();
+    for (String key : keys) {
+      DownloadThreader db = mDownloaderMap.get(key);
+      if (db != null) {
+        db.cancelDownload();
+      }
+    }
+  }
+
+  @Override public void stopDownload() {
+    isRunning = false;
+    if (!mInfoPool.isShutdown()) {
+      mInfoPool.shutdown();
+    }
+
+    Set keys = mDownloaderMap.keySet();
+    for (String key : keys) {
+      DownloadThreader db = mDownloaderMap.get(key);
+      if (db != null) {
+        db.stopDownload();
+      }
+    }
+  }
+
+  @Override public void startDownload() {
+    isRunning = true;
+    Set keys = mExeMap.keySet();
+    for (String key : keys) {
+      DownloadTaskEntity taskEntity = mExeMap.get(key);
+      mInfoPool.execute(new FileInfoThread(taskEntity, new FileInfoThread.OnFileInfoCallback() {
+
+        @Override public void onComplete(String url, int code) {
+          DownloadTaskEntity te = mExeMap.get(url);
+          if (te != null) {
+            mTotalSize += te.getEntity().getFileSize();
+            startChildDownload(te);
+          }
+        }
+
+        @Override public void onFail(String url, String errorMsg) {
+          mFailMap.put(url, mExeMap.get(url));
+        }
+      }));
+    }
+    mListener.onPostPre(mTotalSize);
+  }
+
+  @Override public void resumeDownload() {
+    startDownload();
+  }
+
+  /**
+   * 启动子任务下载器
+   */
+  private void startChildDownload(DownloadTaskEntity taskEntity) {
+    ChildDownloadListener listener = new ChildDownloadListener(taskEntity);
+    DownloadThreader dt = new DownloadThreader(listener, taskEntity);
+    mDownloaderMap.put(taskEntity.getEntity().getDownloadUrl(), dt);
+    mExePool.execute(dt);
+  }
+
+  /**
+   * 创建子任务下载信息
+   */
+  private DownloadTaskEntity createDownloadTask(DownloadEntity entity) {
+    DownloadTaskEntity taskEntity =
+        DbEntity.findData(DownloadTaskEntity.class, "key=?", entity.getDownloadUrl());
+    if (taskEntity != null) {
+      return taskEntity;
+    }
+    taskEntity = new DownloadTaskEntity(entity);
+    taskEntity.headers = mTaskEntity.headers;
+    taskEntity.requestEnum = mTaskEntity.requestEnum;
+    taskEntity.redirectUrlKey = mTaskEntity.redirectUrlKey;
+    taskEntity.removeFile = mTaskEntity.removeFile;
+    return taskEntity;
+  }
+
+  /**
+   * 子任务事件监听
+   */
+  private class ChildDownloadListener extends DownloadListener {
+
+    DownloadTaskEntity taskEntity;
+    DownloadEntity entity;
+    long lastLen = 0;   //上一次发送长度
+    long lastTime = 0;
+    long INTERVAL_TIME = 1000;   //1m更新周期
+
+    ChildDownloadListener(DownloadTaskEntity entity) {
+      this.taskEntity = entity;
+      this.entity = taskEntity.getEntity();
+    }
+
+    @Override public void onPre() {
+      saveData(IEntity.STATE_PRE, -1);
+    }
+
+    @Override public void onPostPre(long fileSize) {
+      entity.setFileSize(fileSize);
+      saveData(IEntity.STATE_POST_PRE, -1);
+    }
+
+    @Override public void onResume(long resumeLocation) {
+      saveData(IEntity.STATE_POST_PRE, IEntity.STATE_RUNNING);
+    }
+
+    @Override public void onStart(long startLocation) {
+      saveData(IEntity.STATE_POST_PRE, IEntity.STATE_RUNNING);
+    }
+
+    @Override public void onProgress(long currentLocation) {
+      if (System.currentTimeMillis() - lastTime > INTERVAL_TIME) {
+        long speed = currentLocation - lastLen;
+        lastTime = System.currentTimeMillis();
+        handleSpeed(speed);
+        entity.setCurrentProgress(currentLocation);
+        lastLen = currentLocation;
+      }
+    }
+
+    @Override public void onStop(long stopLocation) {
+      saveData(IEntity.STATE_STOP, stopLocation);
+    }
+
+    @Override public void onCancel() {
+      saveData(IEntity.STATE_CANCEL, -1);
+    }
+
+    @Override public void onComplete() {
+      saveData(IEntity.STATE_COMPLETE, entity.getFileSize());
+    }
+
+    @Override public void onFail() {
+      entity.setFailNum(entity.getFailNum() + 1);
+      saveData(IEntity.STATE_FAIL, -1);
+    }
+
+    private void saveData(int state, long location) {
+      entity.setState(state);
+      entity.setDownloadComplete(state == IEntity.STATE_COMPLETE);
+      entity.setCurrentProgress(location);
+      entity.update();
+    }
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadListener.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadListener.java
similarity index 92%
rename from Aria/src/main/java/com/arialyy/aria/core/download/DownloadListener.java
rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadListener.java
index a2cbf237..f8d2349e 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadListener.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadListener.java
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-package com.arialyy.aria.core.download;
+package com.arialyy.aria.core.download.downloader;
+
 
 /**
  * @author lyy
  */
-class DownloadListener implements IDownloadListener {
+public class DownloadListener implements IDownloadListener {
 
   @Override public void onResume(long resumeLocation) {
 
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadStateConstance.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadStateConstance.java
similarity index 97%
rename from Aria/src/main/java/com/arialyy/aria/core/download/DownloadStateConstance.java
rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadStateConstance.java
index 8c815ee9..7d145a1a 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadStateConstance.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadStateConstance.java
@@ -13,7 +13,7 @@
  * 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.downloader;
 
 /**
  * Created by lyy on 2017/1/18.
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadThreader.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadThreader.java
new file mode 100644
index 00000000..ca70cc7c
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadThreader.java
@@ -0,0 +1,346 @@
+/*
+ * 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.downloader;
+
+import android.content.Context;
+import android.util.Log;
+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.orm.DbEntity;
+import com.arialyy.aria.util.BufferedRandomAccessFile;
+import com.arialyy.aria.util.CommonUtil;
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Created by AriaL on 2017/7/1.
+ */
+class DownloadThreader implements Runnable, IDownloadUtil {
+  private final String TAG = "DownloadThreader";
+  private IDownloadListener mListener;
+  private DownloadTaskEntity mTaskEntity;
+  private DownloadEntity mEntity;
+  private ExecutorService mFixedThreadPool;
+  private File mConfigFile;//下载信息配置文件
+  private Context mContext;
+  private File mTempFile; //下载的文件
+  private boolean isNewTask = true;
+  private int mThreadNum, mRealThreadNum;
+  private DownloadStateConstance mConstance;
+  private SparseArray mTask = new SparseArray<>();
+
+  DownloadThreader(IDownloadListener listener, DownloadTaskEntity taskEntity) {
+    mListener = listener;
+    mTaskEntity = taskEntity;
+    mEntity = mTaskEntity.getEntity();
+    mContext = AriaManager.APP;
+    mConstance = new DownloadStateConstance();
+  }
+
+  @Override public void run() {
+    checkTask();
+    startDownload();
+  }
+
+  @Override public long getFileSize() {
+    return mEntity.getFileSize();
+  }
+
+  /**
+   * 获取当前下载位置
+   */
+  @Override public long getCurrentLocation() {
+    return mConstance.CURRENT_LOCATION;
+  }
+
+  @Override public boolean isDownloading() {
+    return mConstance.isDownloading;
+  }
+
+  @Override public void cancelDownload() {
+    mConstance.isCancel = true;
+    mConstance.isDownloading = false;
+    if (mFixedThreadPool != null) {
+      mFixedThreadPool.shutdown();
+    }
+    for (int i = 0; i < mThreadNum; i++) {
+      SingleThreadTask task = (SingleThreadTask) mTask.get(i);
+      if (task != null) {
+        task.cancel();
+      }
+    }
+    CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, mEntity);
+  }
+
+  @Override public void stopDownload() {
+    mConstance.isStop = true;
+    mConstance.isDownloading = false;
+    if (mFixedThreadPool != null) {
+      mFixedThreadPool.shutdown();
+    }
+    for (int i = 0; i < mThreadNum; i++) {
+      SingleThreadTask task = (SingleThreadTask) mTask.get(i);
+      if (task != null) {
+        task.stop();
+      }
+    }
+  }
+
+  @Override public void startDownload() {
+    mConstance.isDownloading = true;
+    try {
+      if (!mTaskEntity.isSupportBP) {
+        mThreadNum = 1;
+        handleNoSupportBreakpointDownload();
+      } else {
+        mThreadNum =
+            isNewTask ? AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum()
+                : mRealThreadNum;
+        mFixedThreadPool = Executors.newFixedThreadPool(mThreadNum);
+        handleBreakpoint();
+      }
+    } catch (IOException e) {
+      failDownload("下载失败【downloadUrl:"
+          + mEntity.getDownloadUrl()
+          + "】\n【filePath:"
+          + mEntity.getDownloadPath()
+          + "】\n"
+          + CommonUtil.getPrintException(e));
+    }
+  }
+
+  @Override public void resumeDownload() {
+    startDownload();
+  }
+
+  /**
+   * 返回该下载器的
+   */
+  public IDownloadListener getListener() {
+    return mListener;
+  }
+
+  /**
+   * 检查任务是否是新任务,新任务条件:
+   * 1、文件不存在
+   * 2、下载记录文件不存在
+   * 3、下载记录文件缺失或不匹配
+   * 4、数据库记录不存在
+   * 5、不支持断点,则是新任务
+   */
+  private void checkTask() {
+    if (!mTaskEntity.isSupportBP) {
+      isNewTask = true;
+      return;
+    }
+    mConfigFile = new File(mContext.getFilesDir().getPath()
+        + AriaManager.DOWNLOAD_TEMP_DIR
+        + mEntity.getFileName()
+        + ".properties");
+    mTempFile = new File(mEntity.getDownloadPath());
+    if (!mConfigFile.exists()) { //记录文件被删除,则重新下载
+      isNewTask = true;
+      CommonUtil.createFile(mConfigFile.getPath());
+    } else if (!mTempFile.exists()) {
+      isNewTask = true;
+    } else if (DbEntity.findData(DownloadEntity.class, "downloadUrl=?", mEntity.getDownloadUrl())
+        == null) {
+      isNewTask = true;
+    } else {
+      isNewTask = checkConfigFile();
+    }
+  }
+
+  /**
+   * 检查记录文件,如果是新任务返回{@code true},否则返回{@code false}
+   */
+  private boolean checkConfigFile() {
+    Properties pro = CommonUtil.loadConfig(mConfigFile);
+    if (pro.isEmpty()) {
+      return true;
+    }
+    Set keys = pro.keySet();
+    int num = 0;
+    for (Object key : keys) {
+      if (String.valueOf(key).contains("_record_")) {
+        num++;
+      }
+    }
+    if (num == 0) {
+      return true;
+    }
+    mRealThreadNum = num;
+    for (int i = 0; i < mRealThreadNum; i++) {
+      if (pro.getProperty(mTempFile.getName() + "_record_" + i) == null) {
+        Object state = pro.getProperty(mTempFile.getName() + "_state_" + i);
+        if (state != null && Integer.parseInt(state + "") == 1) {
+          continue;
+        }
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * 恢复记录地址
+   *
+   * @return true 表示下载完成
+   */
+  private boolean resumeRecordLocation(int i, long startL, long endL) {
+    mConstance.CURRENT_LOCATION += endL - startL;
+    Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++");
+    mConstance.COMPLETE_THREAD_NUM++;
+    mConstance.STOP_NUM++;
+    mConstance.CANCEL_NUM++;
+    if (mConstance.isComplete()) {
+      if (mConfigFile.exists()) {
+        mConfigFile.delete();
+      }
+      mListener.onComplete();
+      mConstance.isDownloading = false;
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * 创建单线程任务
+   */
+  private void addSingleTask(int i, long startL, long endL, long fileLength) {
+    ChildThreadConfigEntity entity = new ChildThreadConfigEntity();
+    entity.FILE_SIZE = fileLength;
+    entity.DOWNLOAD_URL =
+        mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getDownloadUrl();
+    entity.TEMP_FILE = mTempFile;
+    entity.THREAD_ID = i;
+    entity.START_LOCATION = startL;
+    entity.END_LOCATION = endL;
+    entity.CONFIG_FILE_PATH = mConfigFile.getPath();
+    entity.IS_SUPPORT_BREAK_POINT = mTaskEntity.isSupportBP;
+    entity.DOWNLOAD_TASK_ENTITY = mTaskEntity;
+    mConstance.THREAD_NUM = mThreadNum;
+    SingleThreadTask task = new SingleThreadTask(mConstance, mListener, entity);
+    mTask.put(i, task);
+  }
+
+  /**
+   * 启动单线程下载任务
+   */
+  private void startSingleTask(int[] recordL) {
+    if (mConstance.CURRENT_LOCATION > 0) {
+      mListener.onResume(mConstance.CURRENT_LOCATION);
+    } else {
+      mListener.onStart(mConstance.CURRENT_LOCATION);
+    }
+    mFixedThreadPool = Executors.newFixedThreadPool(recordL.length);
+    for (int l : recordL) {
+      if (l == -1) continue;
+      Runnable task = mTask.get(l);
+      if (task != null) {
+        mFixedThreadPool.execute(task);
+      }
+    }
+  }
+
+  /**
+   * 处理断点
+   */
+  private void handleBreakpoint() throws IOException {
+    long fileLength = mEntity.getFileSize();
+    Properties pro = CommonUtil.loadConfig(mConfigFile);
+    int blockSize = (int) (fileLength / mThreadNum);
+    int[] recordL = new int[mThreadNum];
+    for (int i = 0; i < mThreadNum; i++) {
+      recordL[i] = -1;
+    }
+    int rl = 0;
+    if (isNewTask) {
+      CommonUtil.createFile(mTempFile.getPath());
+      BufferedRandomAccessFile file =
+          new BufferedRandomAccessFile(new File(mTempFile.getPath()), "rwd", 8192);
+      //设置文件长度
+      file.setLength(fileLength);
+      file.close();
+    }
+
+    for (int i = 0; i < mThreadNum; i++) {
+      long startL = i * blockSize, endL = (i + 1) * blockSize;
+      Object state = pro.getProperty(mTempFile.getName() + "_state_" + i);
+      if (state != null && Integer.parseInt(state + "") == 1) {  //该线程已经完成
+        if (resumeRecordLocation(i, startL, endL)) return;
+        continue;
+      }
+      //分配下载位置
+      Object record = pro.getProperty(mTempFile.getName() + "_record_" + i);
+      //如果有记录,则恢复下载
+      if (!isNewTask && record != null && Long.parseLong(record + "") >= 0) {
+        Long r = Long.parseLong(record + "");
+        mConstance.CURRENT_LOCATION += r - startL;
+        Log.d(TAG, "任务【" + mEntity.getFileName() + "】线程__" + i + "__恢复下载");
+        mListener.onChildResume(r);
+        startL = r;
+        recordL[rl] = i;
+        rl++;
+      } else {
+        recordL[rl] = i;
+        rl++;
+      }
+      if (i == (mThreadNum - 1)) {
+        //最后一个线程的结束位置即为文件的总长度
+        endL = fileLength;
+      }
+      addSingleTask(i, startL, endL, fileLength);
+    }
+    startSingleTask(recordL);
+  }
+
+  /**
+   * 处理不支持断点的下载
+   */
+  private void handleNoSupportBreakpointDownload() {
+    ChildThreadConfigEntity entity = new ChildThreadConfigEntity();
+    long len = mEntity.getFileSize();
+    entity.FILE_SIZE = len;
+    entity.DOWNLOAD_URL =
+        mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getDownloadUrl();
+    entity.TEMP_FILE = mTempFile;
+    entity.THREAD_ID = 0;
+    entity.START_LOCATION = 0;
+    entity.END_LOCATION = entity.FILE_SIZE;
+    entity.CONFIG_FILE_PATH = mConfigFile.getPath();
+    entity.IS_SUPPORT_BREAK_POINT = mTaskEntity.isSupportBP;
+    entity.DOWNLOAD_TASK_ENTITY = mTaskEntity;
+    mConstance.THREAD_NUM = mThreadNum;
+    SingleThreadTask task = new SingleThreadTask(mConstance, mListener, entity);
+    mTask.put(0, task);
+    mFixedThreadPool.execute(task);
+    mListener.onPostPre(len);
+    mListener.onStart(0);
+  }
+
+  private void failDownload(String errorMsg) {
+    Log.e(TAG, errorMsg);
+    mConstance.isDownloading = false;
+    mListener.onFail();
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadUtil.java
similarity index 92%
rename from Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadUtil.java
index 526f08ba..d2b3b8fe 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadUtil.java
@@ -14,14 +14,15 @@
  * limitations under the License.
  */
 
-package com.arialyy.aria.core.download;
+package com.arialyy.aria.core.download.downloader;
 
 import android.content.Context;
 import android.util.Log;
 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.orm.DbEntity;
-import com.arialyy.aria.orm.DbUtil;
 import com.arialyy.aria.util.BufferedRandomAccessFile;
 import com.arialyy.aria.util.CommonUtil;
 import java.io.File;
@@ -37,7 +38,7 @@ import java.util.concurrent.Executors;
  * Created by lyy on 2015/8/25.
  * 下载工具类
  */
-class DownloadUtil implements IDownloadUtil, Runnable {
+public class DownloadUtil implements IDownloadUtil, Runnable {
   private static final String TAG = "DownloadUtil";
   /**
    * 线程数
@@ -54,7 +55,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
   private boolean isSupportBreakpoint = true;
   private Context mContext;
   private DownloadEntity mDownloadEntity;
-  private DownloadTaskEntity mDownloadTaskEntity;
+  private DownloadTaskEntity mTaskEntity;
   private ExecutorService mFixedThreadPool;
   private File mDownloadFile; //下载的文件
   private File mConfigFile;//下载信息配置文件
@@ -62,9 +63,9 @@ class DownloadUtil implements IDownloadUtil, Runnable {
   private DownloadStateConstance CONSTANCE;
 
   DownloadUtil(Context context, DownloadTaskEntity entity, IDownloadListener downloadListener) {
-    mDownloadEntity = entity.downloadEntity;
+    mDownloadEntity = entity.getEntity();
     mContext = context.getApplicationContext();
-    mDownloadTaskEntity = entity;
+    mTaskEntity = entity;
     mListener = downloadListener;
     // 线程下载数改变后,新的下载才会生效
     //mFixedThreadPool = Executors.newFixedThreadPool(Integer.MAX_VALUE);
@@ -74,7 +75,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
 
   private void init() {
     mConnectTimeOut = AriaManager.getInstance(mContext).getDownloadConfig().getConnectTimeOut();
-    mDownloadFile = new File(mDownloadTaskEntity.downloadEntity.getDownloadPath());
+    mDownloadFile = new File(mTaskEntity.getEntity().getDownloadPath());
     //读取已完成的线程数
     mConfigFile = new File(mContext.getFilesDir().getPath()
         + AriaManager.DOWNLOAD_TEMP_DIR
@@ -113,6 +114,10 @@ class DownloadUtil implements IDownloadUtil, Runnable {
     return mListener;
   }
 
+  @Override public long getFileSize() {
+    return mDownloadEntity.getFileSize();
+  }
+
   /**
    * 获取当前下载位置
    */
@@ -148,6 +153,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
         task.cancel();
       }
     }
+    CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, mDownloadEntity);
   }
 
   /**
@@ -170,7 +176,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
   /**
    * 删除下载记录文件
    */
-  @Override public void delConfigFile() {
+  public void delConfigFile() {
     if (mContext != null && mDownloadEntity != null) {
       File dFile = new File(mDownloadEntity.getDownloadPath());
       File config =
@@ -184,7 +190,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
   /**
    * 删除temp文件
    */
-  @Override public void delTempFile() {
+  public void delTempFile() {
     if (mContext != null && mDownloadEntity != null) {
       File dFile = new File(mDownloadEntity.getDownloadPath());
       if (dFile.exists()) {
@@ -217,7 +223,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
     try {
       URL url = new URL(mDownloadEntity.getDownloadUrl());
       conn = ConnectionHelp.handleConnection(url);
-      conn = ConnectionHelp.setConnectParam(mDownloadTaskEntity, conn);
+      conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
       conn.setRequestProperty("Range", "bytes=" + 0 + "-");
       conn.setConnectTimeout(mConnectTimeOut);
       conn.connect();
@@ -237,7 +243,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
   }
 
   /**
-   * 处理状态吗
+   * 处理状态码
    */
   private void handleConnect(HttpURLConnection conn) throws IOException {
     int len = conn.getContentLength();
@@ -290,19 +296,18 @@ class DownloadUtil implements IDownloadUtil, Runnable {
    * 处理30x跳转
    */
   private void handle302Turn(HttpURLConnection conn) throws IOException {
-    String newUrl = conn.getHeaderField(mDownloadTaskEntity.redirectUrlKey);
+    String newUrl = conn.getHeaderField(mTaskEntity.redirectUrlKey);
     Log.d(TAG, "30x跳转,新url为【" + newUrl + "】");
     mDownloadEntity.setRedirect(true);
     mDownloadEntity.setRedirectUrl(newUrl);
     mDownloadEntity.update();
     String cookies = conn.getHeaderField("Set-Cookie");
     conn = (HttpURLConnection) new URL(newUrl).openConnection();
-    conn = ConnectionHelp.setConnectParam(mDownloadTaskEntity, conn);
+    conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
     conn.setRequestProperty("Cookie", cookies);
     conn.setRequestProperty("Range", "bytes=" + 0 + "-");
     conn.setConnectTimeout(mConnectTimeOut);
     conn.connect();
-
     handleConnect(conn);
   }
 
@@ -333,7 +338,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
       //分配下载位置
       Object record = pro.getProperty(mDownloadFile.getName() + "_record_" + i);
       //如果有记录,则恢复下载
-      if (!isNewTask && record != null && Long.parseLong(record + "") > 0) {
+      if (!isNewTask && record != null && Long.parseLong(record + "") >= 0) {
         Long r = Long.parseLong(record + "");
         CONSTANCE.CURRENT_LOCATION += r - startL;
         Log.d(TAG, "任务【" + mDownloadEntity.getFileName() + "】线程__" + i + "__恢复下载");
@@ -373,7 +378,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
     entity.END_LOCATION = entity.FILE_SIZE;
     entity.CONFIG_FILE_PATH = mConfigFile.getPath();
     entity.IS_SUPPORT_BREAK_POINT = isSupportBreakpoint;
-    entity.DOWNLOAD_TASK_ENTITY = mDownloadTaskEntity;
+    entity.DOWNLOAD_TASK_ENTITY = mTaskEntity;
     THREAD_NUM = 1;
     CONSTANCE.THREAD_NUM = THREAD_NUM;
     SingleThreadTask task = new SingleThreadTask(CONSTANCE, mListener, entity);
@@ -473,7 +478,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
     entity.END_LOCATION = endL;
     entity.CONFIG_FILE_PATH = mConfigFile.getPath();
     entity.IS_SUPPORT_BREAK_POINT = isSupportBreakpoint;
-    entity.DOWNLOAD_TASK_ENTITY = mDownloadTaskEntity;
+    entity.DOWNLOAD_TASK_ENTITY = mTaskEntity;
     CONSTANCE.THREAD_NUM = THREAD_NUM;
     SingleThreadTask task = new SingleThreadTask(CONSTANCE, mListener, entity);
     mTask.put(i, task);
@@ -498,23 +503,4 @@ class DownloadUtil implements IDownloadUtil, Runnable {
     }
   }
 
-  /**
-   * 子线程下载信息类
-   */
-  final static class ChildThreadConfigEntity {
-    //线程Id
-    int THREAD_ID;
-    //下载文件大小
-    long FILE_SIZE;
-    //子线程启动下载位置
-    long START_LOCATION;
-    //子线程结束下载位置
-    long END_LOCATION;
-    //下载路径
-    File TEMP_FILE;
-    String DOWNLOAD_URL;
-    String CONFIG_FILE_PATH;
-    DownloadTaskEntity DOWNLOAD_TASK_ENTITY;
-    boolean IS_SUPPORT_BREAK_POINT = true;
-  }
 }
\ No newline at end of file
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FileInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FileInfoThread.java
new file mode 100644
index 00000000..71e33f78
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FileInfoThread.java
@@ -0,0 +1,161 @@
+/*
+ * 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.downloader;
+
+import android.util.Log;
+import com.arialyy.aria.core.AriaManager;
+import com.arialyy.aria.core.download.DownloadEntity;
+import com.arialyy.aria.core.download.DownloadTaskEntity;
+import com.arialyy.aria.util.CommonUtil;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+/**
+ * 下载文件信息获取
+ */
+class FileInfoThread implements Runnable {
+  private final String TAG = "FileInfoThread";
+  private DownloadEntity mEntity;
+  private DownloadTaskEntity mTaskEntity;
+  private int mConnectTimeOut;
+  private OnFileInfoCallback onFileInfoListener;
+
+  interface OnFileInfoCallback {
+    /**
+     * 处理完成
+     *
+     * @param code 状态码
+     */
+    void onComplete(String url, int code);
+
+    /**
+     * 请求失败
+     *
+     * @param errorMsg 错误信息
+     */
+    void onFail(String url, String errorMsg);
+  }
+
+  FileInfoThread(DownloadTaskEntity taskEntity) {
+    this(taskEntity, null);
+  }
+
+  FileInfoThread(DownloadTaskEntity taskEntity, OnFileInfoCallback callback) {
+    this.mTaskEntity = taskEntity;
+    mEntity = taskEntity.getEntity();
+    mConnectTimeOut =
+        AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getConnectTimeOut();
+    onFileInfoListener = callback;
+  }
+
+  @Override public void run() {
+    HttpURLConnection conn = null;
+    try {
+      URL url = new URL(mEntity.getDownloadUrl());
+      conn = ConnectionHelp.handleConnection(url);
+      conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
+      conn.setRequestProperty("Range", "bytes=" + 0 + "-");
+      conn.setConnectTimeout(mConnectTimeOut);
+      conn.connect();
+      handleConnect(conn);
+    } catch (IOException e) {
+      failDownload("下载失败【downloadUrl:"
+          + mEntity.getDownloadUrl()
+          + "】\n【filePath:"
+          + mEntity.getDownloadPath()
+          + "】\n"
+          + CommonUtil.getPrintException(e));
+    } finally {
+      if (conn != null) {
+        conn.disconnect();
+      }
+    }
+  }
+
+  private void handleConnect(HttpURLConnection conn) throws IOException {
+    int len = conn.getContentLength();
+    int code = conn.getResponseCode();
+    boolean isComplete = false;
+    mTaskEntity.code = code;
+    if (code == HttpURLConnection.HTTP_PARTIAL) {
+      if (!checkLen(len)) return;
+      mEntity.setFileSize(len);
+      mTaskEntity.isSupportBP = true;
+      isComplete = true;
+    } else if (code == HttpURLConnection.HTTP_OK) {
+      if (!checkLen(len)) return;
+      mEntity.setFileSize(len);
+      mTaskEntity.isSupportBP = false;
+      isComplete = true;
+    } else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
+      failDownload("任务【" + mEntity.getDownloadUrl() + "】下载失败,错误码:404");
+    } else if (code == HttpURLConnection.HTTP_MOVED_TEMP
+        || code == HttpURLConnection.HTTP_MOVED_PERM
+        || code == HttpURLConnection.HTTP_SEE_OTHER) {
+      mTaskEntity.redirectUrlKey = conn.getHeaderField(mTaskEntity.redirectUrlKey);
+      mEntity.setRedirect(true);
+      mEntity.setRedirectUrl(mTaskEntity.redirectUrlKey);
+      handle302Turn(conn);
+    } else {
+      failDownload("任务【" + mEntity.getDownloadUrl() + "】下载失败,错误码:" + code);
+    }
+    if (isComplete) {
+      if (onFileInfoListener != null) {
+        onFileInfoListener.onComplete(mEntity.getDownloadUrl(), code);
+      }
+      mEntity.update();
+      mTaskEntity.update();
+    }
+  }
+
+  /**
+   * 处理30x跳转
+   */
+  private void handle302Turn(HttpURLConnection conn) throws IOException {
+    String newUrl = conn.getHeaderField(mTaskEntity.redirectUrlKey);
+    Log.d(TAG, "30x跳转,新url为【" + newUrl + "】");
+    String cookies = conn.getHeaderField("Set-Cookie");
+    conn = (HttpURLConnection) new URL(newUrl).openConnection();
+    conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
+    conn.setRequestProperty("Cookie", cookies);
+    conn.setRequestProperty("Range", "bytes=" + 0 + "-");
+    conn.setConnectTimeout(mConnectTimeOut);
+    conn.connect();
+    handleConnect(conn);
+  }
+
+  /**
+   * 检查长度是否合法
+   *
+   * @param len 从服务器获取的文件长度
+   * @return true, 合法
+   */
+  private boolean checkLen(long len) {
+    if (len < 0) {
+      failDownload("任务【" + mEntity.getDownloadUrl() + "】下载失败,文件长度小于0");
+      return false;
+    }
+    return true;
+  }
+
+  private void failDownload(String errorMsg) {
+    Log.e(TAG, errorMsg);
+    if (onFileInfoListener != null) {
+      onFileInfoListener.onFail(mEntity.getDownloadUrl(), errorMsg);
+    }
+  }
+}
\ No newline at end of file
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/IDownloadListener.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadListener.java
similarity index 97%
rename from Aria/src/main/java/com/arialyy/aria/core/download/IDownloadListener.java
rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadListener.java
index 0e805e35..d9c06376 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/IDownloadListener.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadListener.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.arialyy.aria.core.download;
+package com.arialyy.aria.core.download.downloader;
 
 /**
  * 下载监听
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/IDownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java
similarity index 82%
rename from Aria/src/main/java/com/arialyy/aria/core/download/IDownloadUtil.java
rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java
index 471d0048..f0265cf3 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/IDownloadUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.arialyy.aria.core.download;
+package com.arialyy.aria.core.download.downloader;
 
 /**
  * Created by lyy on 2016/10/31.
@@ -22,6 +22,11 @@ package com.arialyy.aria.core.download;
  */
 interface IDownloadUtil {
 
+  /**
+   * 获取文件大小
+   */
+  public long getFileSize();
+
   /**
    * 获取当前下载位置
    */
@@ -53,19 +58,4 @@ interface IDownloadUtil {
    * 从上次断点恢复下载
    */
   public void resumeDownload();
-
-  /**
-   * 删除下载记录文件
-   */
-  public void delConfigFile();
-
-  /**
-   * 删除temp文件
-   */
-  public void delTempFile();
-
-  /**
-   * 设置最大下载速度
-   */
-  public void setMaxSpeed(double maxSpeed);
 }
\ No newline at end of file
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SingleThreadTask.java
similarity index 98%
rename from Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java
rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/SingleThreadTask.java
index b46b8750..245d32e6 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SingleThreadTask.java
@@ -13,7 +13,7 @@
  * 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.downloader;
 
 import android.os.Build;
 import android.text.TextUtils;
@@ -36,7 +36,7 @@ import java.util.Properties;
  */
 final class SingleThreadTask implements Runnable {
   private static final String TAG = "SingleThreadTask";
-  private DownloadUtil.ChildThreadConfigEntity mConfigEntity;
+  private ChildThreadConfigEntity mConfigEntity;
   private String mConfigFPath;
   private long mChildCurrentLocation = 0;
   private int mBufSize;
@@ -45,7 +45,7 @@ final class SingleThreadTask implements Runnable {
   private long mSleepTime = 0;
 
   SingleThreadTask(DownloadStateConstance constance, IDownloadListener listener,
-      DownloadUtil.ChildThreadConfigEntity downloadInfo) {
+      ChildThreadConfigEntity downloadInfo) {
     AriaManager manager = AriaManager.getInstance(AriaManager.APP);
     CONSTANCE = constance;
     CONSTANCE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut();
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
new file mode 100644
index 00000000..63806454
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java
@@ -0,0 +1,136 @@
+/*
+ * 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.os.Parcel;
+import android.os.Parcelable;
+import com.arialyy.aria.orm.DbEntity;
+import com.arialyy.aria.orm.Ignore;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ */
+public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable {
+  /**
+   * 速度
+   */
+  @Ignore private long speed = 0;
+  /**
+   * 单位转换后的速度
+   */
+  @Ignore private String convertSpeed = "0b/s";
+
+  /**
+   * 扩展字段
+   */
+  private String str = "";
+  /**
+   * 文件大小
+   */
+  private long fileSize = 1;
+  private int state = STATE_WAIT;
+  /**
+   * 当前下载进度
+   */
+  private long currentProgress = 0;
+  /**
+   * 完成时间
+   */
+  private long completeTime;
+
+  public long getSpeed() {
+    return speed;
+  }
+
+  public void setSpeed(long speed) {
+    this.speed = speed;
+  }
+
+  public String getConvertSpeed() {
+    return convertSpeed;
+  }
+
+  public void setConvertSpeed(String convertSpeed) {
+    this.convertSpeed = convertSpeed;
+  }
+
+  public String getStr() {
+    return str;
+  }
+
+  public void setStr(String str) {
+    this.str = str;
+  }
+
+  public long getFileSize() {
+    return fileSize;
+  }
+
+  public void setFileSize(long fileSize) {
+    this.fileSize = fileSize;
+  }
+
+  public int getState() {
+    return state;
+  }
+
+  public void setState(int state) {
+    this.state = state;
+  }
+
+  public long getCurrentProgress() {
+    return currentProgress;
+  }
+
+  public void setCurrentProgress(long currentProgress) {
+    this.currentProgress = currentProgress;
+  }
+
+  public long getCompleteTime() {
+    return completeTime;
+  }
+
+  public void setCompleteTime(long completeTime) {
+    this.completeTime = completeTime;
+  }
+
+  public AbsEntity() {
+  }
+
+  @Override public int describeContents() {
+    return 0;
+  }
+
+  @Override public void writeToParcel(Parcel dest, int flags) {
+    dest.writeLong(this.speed);
+    dest.writeString(this.convertSpeed);
+    dest.writeString(this.str);
+    dest.writeLong(this.fileSize);
+    dest.writeInt(this.state);
+    dest.writeLong(this.currentProgress);
+    dest.writeLong(this.completeTime);
+  }
+
+  protected AbsEntity(Parcel in) {
+    this.speed = in.readLong();
+    this.convertSpeed = in.readString();
+    this.str = in.readString();
+    this.fileSize = in.readLong();
+    this.state = in.readInt();
+    this.currentProgress = in.readLong();
+    this.completeTime = in.readLong();
+  }
+}
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 c50258f7..9432a0de 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
@@ -23,92 +23,18 @@ import com.arialyy.aria.orm.Ignore;
 /**
  * Created by AriaL on 2017/6/3.
  */
-public abstract class AbsGroupEntity extends DbEntity implements IEntity, Parcelable {
+public abstract class AbsGroupEntity extends AbsEntity implements Parcelable {
   /**
-   * 速度
+   * 组名
    */
-  @Ignore private long speed = 0;
-  /**
-   * 单位转换后的速度
-   */
-  @Ignore private String convertSpeed = "0b/s";
-
-  /**
-   * 扩展字段
-   */
-  private String str = "";
-  /**
-   * 文件大小
-   */
-  private long fileSize = 1;
-  private int state = STATE_WAIT;
-  /**
-   * 当前下载进度
-   */
-  private long currentProgress = 0;
-  /**
-   * 完成时间
-   */
-  private long completeTime;
-  /**
-   * 文件名
-   */
-  private String grooupName = "";
-
-  public long getSpeed() {
-    return speed;
-  }
-
-  public void setSpeed(long speed) {
-    this.speed = speed;
-  }
-
-  public String getConvertSpeed() {
-    return convertSpeed;
-  }
-
-  public void setConvertSpeed(String convertSpeed) {
-    this.convertSpeed = convertSpeed;
-  }
-
-  public String getStr() {
-    return str;
-  }
-
-  public void setStr(String str) {
-    this.str = str;
-  }
-
-  public long getFileSize() {
-    return fileSize;
-  }
-
-  public void setFileSize(long fileSize) {
-    this.fileSize = fileSize;
-  }
-
-  public int getState() {
-    return state;
-  }
-
-  public void setState(int state) {
-    this.state = state;
-  }
-
-  public long getCurrentProgress() {
-    return currentProgress;
-  }
-
-  public void setCurrentProgress(long currentProgress) {
-    this.currentProgress = currentProgress;
-  }
+  private String groupName = "";
 
-  public long getCompleteTime() {
-    return completeTime;
+  public String getGroupName() {
+    return groupName;
   }
 
-  public void setCompleteTime(long completeTime) {
-    this.completeTime = completeTime;
+  public void setGroupName(String groupName) {
+    this.groupName = groupName;
   }
 
   public AbsGroupEntity() {
@@ -119,22 +45,12 @@ public abstract class AbsGroupEntity exten
   }
 
   @Override public void writeToParcel(Parcel dest, int flags) {
-    dest.writeLong(this.speed);
-    dest.writeString(this.convertSpeed);
-    dest.writeString(this.str);
-    dest.writeLong(this.fileSize);
-    dest.writeInt(this.state);
-    dest.writeLong(this.currentProgress);
-    dest.writeLong(this.completeTime);
+    super.writeToParcel(dest, flags);
+    dest.writeString(this.groupName);
   }
 
   protected AbsGroupEntity(Parcel in) {
-    this.speed = in.readLong();
-    this.convertSpeed = in.readString();
-    this.str = in.readString();
-    this.fileSize = in.readLong();
-    this.state = in.readInt();
-    this.currentProgress = in.readLong();
-    this.completeTime = in.readLong();
+    super(in);
+    this.groupName = in.readString();
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java
new file mode 100644
index 00000000..b7eb3a93
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java
@@ -0,0 +1,71 @@
+/*
+ * 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 com.arialyy.aria.util.CommonUtil;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ */
+public abstract class AbsGroupTask
+    extends AbsTask {
+
+  protected TASK_ENTITY mTaskEntity;
+
+  @Override public int getPercent() {
+    return 0;
+  }
+
+  @Override public long getFileSize() {
+    return 0;
+  }
+
+  @Override public String getConvertFileSize() {
+    return null;
+  }
+
+  @Override public long getCurrentProgress() {
+    return 0;
+  }
+
+  @Override public String getConvertCurrentProgress() {
+    return null;
+  }
+
+  @Override public int getState() {
+    return mEntity.getState();
+  }
+
+  @Override public String getExtendField() {
+    return mEntity.getStr();
+  }
+
+  @Override public String getKey() {
+    return mEntity.getGroupName();
+  }
+
+  @Override public boolean isRunning() {
+    return false;
+  }
+
+  @Override public ENTITY getEntity() {
+    return mEntity;
+  }
+
+  @Override public void removeRecord() {
+
+  }
+}
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 8411c960..91a1dae5 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
@@ -23,55 +23,27 @@ import com.arialyy.aria.orm.Ignore;
 /**
  * Created by AriaL on 2017/6/3.
  */
-public abstract class AbsNormalEntity extends DbEntity implements IEntity, Parcelable {
-  /**
-   * 速度
-   */
-  @Ignore private long speed = 0;
-  /**
-   * 单位转换后的速度
-   */
-  @Ignore private String convertSpeed = "0b/s";
+public abstract class AbsNormalEntity extends AbsEntity implements Parcelable {
   /**
    * 下载失败计数,每次开始都重置为0
    */
   @Ignore private int failNum = 0;
-  /**
-   * 扩展字段
-   */
-  private String str = "";
-  /**
-   * 文件大小
-   */
-  private long fileSize = 1;
-  private int state = STATE_WAIT;
-  /**
-   * 当前下载进度
-   */
-  private long currentProgress = 0;
-  /**
-   * 完成时间
-   */
-  private long completeTime;
   /**
    * 文件名
    */
   private String fileName = "";
 
-  public long getSpeed() {
-    return speed;
-  }
-
-  public void setSpeed(long speed) {
-    this.speed = speed;
-  }
+  /**
+   * 是否是任务组里面的下载实体
+   */
+  private boolean isGroupChild = false;
 
-  public String getConvertSpeed() {
-    return convertSpeed;
+  public boolean isGroupChild() {
+    return isGroupChild;
   }
 
-  public void setConvertSpeed(String convertSpeed) {
-    this.convertSpeed = convertSpeed;
+  public void setGroupChild(boolean groupChild) {
+    isGroupChild = groupChild;
   }
 
   public int getFailNum() {
@@ -82,46 +54,6 @@ public abstract class AbsNormalEntity extends DbEntity implements IEntity, Parce
     this.failNum = failNum;
   }
 
-  public String getStr() {
-    return str;
-  }
-
-  public void setStr(String str) {
-    this.str = str;
-  }
-
-  public long getFileSize() {
-    return fileSize;
-  }
-
-  public void setFileSize(long fileSize) {
-    this.fileSize = fileSize;
-  }
-
-  public int getState() {
-    return state;
-  }
-
-  public void setState(int state) {
-    this.state = state;
-  }
-
-  public long getCurrentProgress() {
-    return currentProgress;
-  }
-
-  public void setCurrentProgress(long currentProgress) {
-    this.currentProgress = currentProgress;
-  }
-
-  public long getCompleteTime() {
-    return completeTime;
-  }
-
-  public void setCompleteTime(long completeTime) {
-    this.completeTime = completeTime;
-  }
-
   public String getFileName() {
     return fileName;
   }
@@ -138,26 +70,16 @@ public abstract class AbsNormalEntity extends DbEntity implements IEntity, Parce
   }
 
   @Override public void writeToParcel(Parcel dest, int flags) {
-    dest.writeLong(this.speed);
-    dest.writeString(this.convertSpeed);
+    super.writeToParcel(dest, flags);
     dest.writeInt(this.failNum);
-    dest.writeString(this.str);
-    dest.writeLong(this.fileSize);
-    dest.writeInt(this.state);
-    dest.writeLong(this.currentProgress);
-    dest.writeLong(this.completeTime);
     dest.writeString(this.fileName);
+    dest.writeByte(this.isGroupChild ? (byte) 1 : (byte) 0);
   }
 
   protected AbsNormalEntity(Parcel in) {
-    this.speed = in.readLong();
-    this.convertSpeed = in.readString();
+    super(in);
     this.failNum = in.readInt();
-    this.str = in.readString();
-    this.fileSize = in.readLong();
-    this.state = in.readInt();
-    this.currentProgress = in.readLong();
-    this.completeTime = in.readLong();
     this.fileName = in.readString();
+    this.isGroupChild = in.readByte() != 0;
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTask.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTask.java
new file mode 100644
index 00000000..a381edef
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTask.java
@@ -0,0 +1,100 @@
+/*
+ * 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 com.arialyy.aria.util.CommonUtil;
+
+/**
+ * Created by lyy on 2017/6/3.
+ */
+public abstract class AbsNormalTask extends AbsTask {
+
+  private boolean isHeighestTask = false;
+
+  /**
+   * 暂停任务,并让任务处于等待状态
+   */
+  public void stopAndWait() {
+
+  }
+
+  /**
+   * 最高优先级命令,最高优先级命令有以下属性
+   * 1、在下载队列中,有且只有一个最高优先级任务
+   * 2、最高优先级任务会一直存在,直到用户手动暂停或任务完成
+   * 3、任务调度器不会暂停最高优先级任务
+   * 4、用户手动暂停或任务完成后,第二次重新执行该任务,该命令将失效
+   * 5、如果下载队列中已经满了,则会停止队尾的任务
+   * 6、把任务设置为最高优先级任务后,将自动执行任务,不需要重新调用start()启动任务
+   */
+  public void setHighestPriority(boolean isHighestPriority) {
+    isHeighestTask = isHighestPriority;
+  }
+
+  public boolean isHighestPriorityTask() {
+    return isHeighestTask;
+  }
+
+  /**
+   * 获取百分比进度
+   *
+   * @return 返回百分比进度,如果文件长度为0,返回0
+   */
+  @Override public int getPercent() {
+    if (mEntity.getFileSize() == 0) {
+      return 0;
+    }
+    return (int) (mEntity.getCurrentProgress() * 100 / mEntity.getFileSize());
+  }
+
+  /**
+   * 获取文件大小
+   */
+  @Override public long getFileSize() {
+    return mEntity.getFileSize();
+  }
+
+  /**
+   * 转换单位后的文件长度
+   *
+   * @return 如果文件长度为0,则返回0m,否则返回转换后的长度1b、1kb、1mb、1gb、1tb
+   */
+  @Override public String getConvertFileSize() {
+    if (mEntity.getFileSize() == 0) {
+      return "0mb";
+    }
+    return CommonUtil.formatFileSize(mEntity.getFileSize());
+  }
+
+  /**
+   * 获取当前下载进度
+   */
+  @Override public long getCurrentProgress() {
+    return mEntity.getCurrentProgress();
+  }
+
+  /**
+   * 获取单位转换后的进度
+   *
+   * @return 如:已经下载3mb的大小,则返回{@code 3mb}
+   */
+  @Override public String getConvertCurrentProgress() {
+    if (mEntity.getCurrentProgress() == 0) {
+      return "0b";
+    }
+    return CommonUtil.formatFileSize(mEntity.getCurrentProgress());
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
index 3be9ea52..02a476bd 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
@@ -16,26 +16,21 @@
 package com.arialyy.aria.core.inf;
 
 import android.content.Context;
-import com.arialyy.aria.util.CommonUtil;
+import android.os.Handler;
 
 /**
- * Created by lyy on 2017/6/3.
+ * Created by AriaL on 2017/6/29.
  */
-public abstract class AbsTask
-    implements ITask {
+public abstract class AbsTask implements ITask {
 
   protected ENTITY mEntity;
+  protected Handler mOutHandler;
 
   /**
    * 用于生成该任务对象的hash码
    */
   private String mTargetName;
   protected Context mContext;
-  private boolean isHeighestTask = false;
-
-  @Override public void stopAndWait() {
-
-  }
 
   /**
    * 任务当前状态
@@ -46,6 +41,15 @@ public abstract class AbsTask
@@ -88,73 +92,6 @@ public abstract class AbsTask extends DbEntity {
+
+  public ENTITY entity;
+
+  /**
+   * Task实体对应的key
+   */
+  public String key;
 
-public abstract class AbsTaskEntity {
   /**
    * http 请求头
    */
@@ -44,5 +52,17 @@ public abstract class AbsTaskEntity {
    */
   public boolean removeFile = false;
 
-  public abstract AbsNormalEntity getEntity();
+  /**
+   * 是否支持断点, {@code true} 为支持断点
+   */
+  public boolean isSupportBP = true;
+
+  /**
+   * 状态码
+   */
+  public int code;
+
+  public ENTITY getEntity() {
+    return entity;
+  }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java b/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
index 5535ad92..b5caee25 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
@@ -18,29 +18,17 @@ package com.arialyy.aria.core.inf;
 /**
  * Created by lyy on 2017/2/13.
  */
-
-public interface ITask {
-
-  /**
-   * 获取
-   */
+public interface ITask {
 
   /**
-   * 暂停任务,并让任务处于等待状态
+   * 获取下载状态
    */
-  public void stopAndWait();
+  int getState();
 
   /**
-   * 设置任务为最高优先级任务,在下载队列中,有且只有一个最高优先级任务
-   */
-  public void setHighestPriority(boolean isHighestPriority);
-
-  /**
-   * 该任务是否是最高优先级任务
-   *
-   * @return {@code true} 任务为最高优先级任务
+   * 获取扩展字段
    */
-  public boolean isHighestPriorityTask();
+  String getExtendField();
 
   /**
    * 唯一标识符,DownloadTask 为下载地址,UploadTask 为文件路径
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 c2b1d239..fa307650 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
@@ -19,21 +19,21 @@ package com.arialyy.aria.core.queue;
 import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.inf.AbsNormalEntity;
-import com.arialyy.aria.core.inf.AbsTask;
+import com.arialyy.aria.core.inf.AbsNormalTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
-import com.arialyy.aria.core.queue.pool.CachePool;
-import com.arialyy.aria.core.queue.pool.ExecutePool;
+import com.arialyy.aria.core.queue.pool.NormalCachePool;
+import com.arialyy.aria.core.queue.pool.NormalExecutePool;
 import java.util.Set;
 
 /**
  * Created by lyy on 2017/2/23.
  * 任务队列
  */
-abstract class AbsTaskQueue
+abstract class AbsTaskQueue
     implements ITaskQueue {
   private final String TAG = "AbsTaskQueue";
-  CachePool mCachePool = new CachePool<>();
-  ExecutePool mExecutePool;
+  NormalCachePool mCachePool = new NormalCachePool<>();
+  NormalExecutePool mExecutePool;
 
   @Override public boolean taskIsRunning(String key) {
     return mExecutePool.getTask(key) != null;
@@ -73,14 +73,14 @@ abstract class AbsTaskQueue(true);
+    mExecutePool = new NormalExecutePool<>(true);
   }
 
   @Override public void setTaskHighestPriority(DownloadTask task) {
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
index b628a1d3..4ce69d80 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
@@ -19,9 +19,8 @@ package com.arialyy.aria.core.queue;
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.download.DownloadTask;
-import com.arialyy.aria.core.inf.AbsTask;
+import com.arialyy.aria.core.inf.AbsNormalTask;
 import com.arialyy.aria.core.inf.IEntity;
-import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.upload.UploadEntity;
 import com.arialyy.aria.core.upload.UploadTask;
@@ -31,7 +30,7 @@ import com.arialyy.aria.core.upload.UploadTaskEntity;
  * Created by lyy on 2016/8/16.
  * 任务功能接口
  */
-public interface ITaskQueue {
+public interface ITaskQueue {
 
   /**
    * 通过key判断任务是否正在执行
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java
index 2b56ac84..3e0eb262 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java
@@ -19,7 +19,7 @@ package com.arialyy.aria.core.queue;
 import android.text.TextUtils;
 import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.queue.pool.ExecutePool;
+import com.arialyy.aria.core.queue.pool.NormalExecutePool;
 import com.arialyy.aria.core.scheduler.UploadSchedulers;
 import com.arialyy.aria.core.upload.UploadEntity;
 import com.arialyy.aria.core.upload.UploadTask;
@@ -43,7 +43,7 @@ public class UploadTaskQueue extends AbsTaskQueue(false);
+    mExecutePool = new NormalExecutePool<>(false);
   }
 
   @Override public void setMaxTaskNum(int newMaxNum) {
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupCachePool.java b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupCachePool.java
new file mode 100644
index 00000000..3e256198
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupCachePool.java
@@ -0,0 +1,23 @@
+/*
+ * 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.queue.pool;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ * 任务组缓冲池
+ */
+public class GroupCachePool {
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupExecutePool.java b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupExecutePool.java
new file mode 100644
index 00000000..188b84d4
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupExecutePool.java
@@ -0,0 +1,23 @@
+/*
+ * 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.queue.pool;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ */
+
+public class GroupExecutePool {
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/CachePool.java b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/NormalCachePool.java
similarity index 96%
rename from Aria/src/main/java/com/arialyy/aria/core/queue/pool/CachePool.java
rename to Aria/src/main/java/com/arialyy/aria/core/queue/pool/NormalCachePool.java
index 964137a4..9f4d54ab 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/CachePool.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/NormalCachePool.java
@@ -32,14 +32,14 @@ import java.util.concurrent.TimeUnit;
  * Created by lyy on 2016/8/14.
  * 任务缓存池,所有下载任务最先缓存在这个池中
  */
-public class CachePool implements IPool {
-  private static final String TAG = "CachePool";
+public class NormalCachePool implements IPool {
+  private static final String TAG = "NormalCachePool";
   private static final int MAX_NUM = Integer.MAX_VALUE;  //最大下载任务数
   private static final long TIME_OUT = 1000;
   private Map mCacheMap;
   private LinkedBlockingQueue mCacheQueue;
 
-  public CachePool() {
+  public NormalCachePool() {
     mCacheQueue = new LinkedBlockingQueue<>(MAX_NUM);
     mCacheMap = new HashMap<>();
   }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/ExecutePool.java b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/NormalExecutePool.java
similarity index 96%
rename from Aria/src/main/java/com/arialyy/aria/core/queue/pool/ExecutePool.java
rename to Aria/src/main/java/com/arialyy/aria/core/queue/pool/NormalExecutePool.java
index 6892d208..756d40cf 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/ExecutePool.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/NormalExecutePool.java
@@ -31,14 +31,14 @@ import java.util.concurrent.TimeUnit;
  * Created by lyy on 2016/8/15.
  * 任务执行池,所有当前下载任务都该任务池中,默认下载大小为2
  */
-public class ExecutePool implements IPool {
-  private static final String TAG = "ExecutePool";
+public class NormalExecutePool implements IPool {
+  private static final String TAG = "NormalExecutePool";
   private static final long TIME_OUT = 1000;
   private ArrayBlockingQueue mExecuteQueue;
   private Map mExecuteMap;
   private int mSize;
 
-  public ExecutePool(boolean isDownload) {
+  public NormalExecutePool(boolean isDownload) {
     if (isDownload) {
       mSize = AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxTaskNum();
     } else {
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 4931e673..8e097f48 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
@@ -21,7 +21,7 @@ import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.download.DownloadTask;
 import com.arialyy.aria.core.inf.AbsNormalEntity;
-import com.arialyy.aria.core.inf.AbsTask;
+import com.arialyy.aria.core.inf.AbsNormalTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.queue.ITaskQueue;
@@ -34,7 +34,7 @@ import java.util.concurrent.ConcurrentHashMap;
 /**
  * Created by lyy on 2017/6/4.
  */
-public abstract class AbsSchedulers, QUEUE extends ITaskQueue>
+public abstract class AbsSchedulers, QUEUE extends ITaskQueue>
     implements ISchedulers {
   private static final String TAG = "AbsSchedulers";
 
diff --git a/aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java b/aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java
index ba799ca0..88c30140 100644
--- a/aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java
+++ b/aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java
@@ -22,7 +22,7 @@ import android.util.Log;
 import com.arialyy.aria.core.Aria;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.download.DownloadEntity;
-import com.arialyy.aria.core.inf.AbsTask;
+import com.arialyy.aria.core.inf.AbsNormalTask;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.scheduler.DownloadSchedulers;
 import com.arialyy.aria.core.scheduler.ISchedulers;
@@ -33,9 +33,8 @@ import java.lang.ref.WeakReference;
  * Created by lyy on 2017/2/23.
  * 上传任务
  */
-public class UploadTask extends AbsTask {
+public class UploadTask extends AbsNormalTask {
   private static final String TAG = "UploadTask";
-  private Handler mOutHandler;
 
   private UploadUtil mUtil;
   private UListener mListener;

From ad136576dcc5a2e20481a810778a485d9c0bb609 Mon Sep 17 00:00:00 2001
From: AriaLyy <511455842@qq.com>
Date: Sat, 1 Jul 2017 23:30:44 +0800
Subject: [PATCH 14/34] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E7=BB=84bug=20fix?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../downloader/DownloadGroupUtil.java         | 105 +++++++++++++++---
 1 file changed, 88 insertions(+), 17 deletions(-)

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 914f70a9..1b1f7300 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
@@ -15,6 +15,7 @@
  */
 package com.arialyy.aria.core.download.downloader;
 
+import android.util.SparseArray;
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
@@ -24,12 +25,14 @@ import java.io.File;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 /**
  * Created by AriaL on 2017/6/30.
- * 下载组工具
+ * 任务组下载工具
  */
 public class DownloadGroupUtil implements IDownloadUtil {
   private static final String TAG = "DownloadGroupUtil";
@@ -43,6 +46,15 @@ public class DownloadGroupUtil implements IDownloadUtil {
   private IDownloadListener mListener;
   private DownloadGroupTaskEntity mTaskEntity;
   private boolean isRunning = true;
+  private Timer mTimer;
+  /**
+   * 初始化完成的任务书数
+   */
+  private int mInitNum = 0;
+  /**
+   * 初始化失败的任务数
+   */
+  private int mFailNum = 0;
   /**
    * 保存所有没有下载完成的任务,key为下载地址
    */
@@ -58,10 +70,16 @@ public class DownloadGroupUtil implements IDownloadUtil {
    */
   private Map mDownloaderMap = new HashMap<>();
 
+  /**
+   * 文件信息回调组
+   */
+  private SparseArray mFileInfoCallbacks = new SparseArray<>();
+
   DownloadGroupUtil(IDownloadListener listener, DownloadGroupTaskEntity taskEntity) {
     mListener = listener;
     mTaskEntity = taskEntity;
     mInfoPool = Executors.newCachedThreadPool();
+    mExePool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
 
     for (DownloadEntity entity : mTaskEntity.entity.getChild()) {
       File file = new File(entity.getDownloadPath());
@@ -88,9 +106,13 @@ public class DownloadGroupUtil implements IDownloadUtil {
 
   @Override public void cancelDownload() {
     isRunning = false;
+    closeTimer();
     if (!mInfoPool.isShutdown()) {
       mInfoPool.shutdown();
     }
+    if (!mExePool.isShutdown()) {
+      mExePool.shutdown();
+    }
 
     Set keys = mDownloaderMap.keySet();
     for (String key : keys) {
@@ -103,9 +125,13 @@ public class DownloadGroupUtil implements IDownloadUtil {
 
   @Override public void stopDownload() {
     isRunning = false;
+    closeTimer();
     if (!mInfoPool.isShutdown()) {
       mInfoPool.shutdown();
     }
+    if (!mExePool.isShutdown()) {
+      mExePool.shutdown();
+    }
 
     Set keys = mDownloaderMap.keySet();
     for (String key : keys) {
@@ -119,9 +145,28 @@ public class DownloadGroupUtil implements IDownloadUtil {
   @Override public void startDownload() {
     isRunning = true;
     Set keys = mExeMap.keySet();
+    mListener.onPre();
     for (String key : keys) {
       DownloadTaskEntity taskEntity = mExeMap.get(key);
-      mInfoPool.execute(new FileInfoThread(taskEntity, new FileInfoThread.OnFileInfoCallback() {
+      if (taskEntity != null) {
+        mInfoPool.execute(createFileInfoThread(taskEntity));
+      }
+    }
+  }
+
+  @Override public void resumeDownload() {
+    startDownload();
+  }
+
+  /**
+   * 创建文件信息获取线程
+   */
+  private FileInfoThread createFileInfoThread(DownloadTaskEntity taskEntity) {
+    FileInfoThread.OnFileInfoCallback callback = mFileInfoCallbacks.get(taskEntity.hashCode());
+
+    if (callback == null) {
+      callback = new FileInfoThread.OnFileInfoCallback() {
+        int failNum = 0;
 
         @Override public void onComplete(String url, int code) {
           DownloadTaskEntity te = mExeMap.get(url);
@@ -129,18 +174,53 @@ public class DownloadGroupUtil implements IDownloadUtil {
             mTotalSize += te.getEntity().getFileSize();
             startChildDownload(te);
           }
+          mInitNum++;
+          if (mInitNum + mFailNum == mTaskEntity.getEntity().getChild().size()) {
+            startRunningFlow();
+          }
         }
 
         @Override public void onFail(String url, String errorMsg) {
-          mFailMap.put(url, mExeMap.get(url));
+          DownloadTaskEntity te = mExeMap.get(url);
+          if (te != null) {
+            mFailMap.put(url, te);
+            mFileInfoCallbacks.put(te.hashCode(), this);
+          }
+          mFailNum++;
+          failNum++;
+          if (failNum < 10){
+            mInfoPool.execute(createFileInfoThread(te));
+          }
+          if (mInitNum + mFailNum == mTaskEntity.getEntity().getChild().size()) {
+            startRunningFlow();
+          }
         }
-      }));
+      };
     }
-    mListener.onPostPre(mTotalSize);
+
+    return new FileInfoThread(taskEntity, callback);
   }
 
-  @Override public void resumeDownload() {
-    startDownload();
+  private void closeTimer() {
+    if (mTimer != null) {
+      mTimer.purge();
+      mTimer.cancel();
+    }
+  }
+
+  /**
+   * 开始进度流程
+   */
+  private void startRunningFlow() {
+    mListener.onPostPre(mTotalSize);
+    mListener.onStart(mCurrentProgress);
+    closeTimer();
+    mTimer = new Timer(true);
+    mTimer.schedule(new TimerTask() {
+      @Override public void run() {
+        mListener.onProgress(mCurrentProgress);
+      }
+    }, 1000);
   }
 
   /**
@@ -177,9 +257,6 @@ public class DownloadGroupUtil implements IDownloadUtil {
 
     DownloadTaskEntity taskEntity;
     DownloadEntity entity;
-    long lastLen = 0;   //上一次发送长度
-    long lastTime = 0;
-    long INTERVAL_TIME = 1000;   //1m更新周期
 
     ChildDownloadListener(DownloadTaskEntity entity) {
       this.taskEntity = entity;
@@ -204,13 +281,7 @@ public class DownloadGroupUtil implements IDownloadUtil {
     }
 
     @Override public void onProgress(long currentLocation) {
-      if (System.currentTimeMillis() - lastTime > INTERVAL_TIME) {
-        long speed = currentLocation - lastLen;
-        lastTime = System.currentTimeMillis();
-        handleSpeed(speed);
-        entity.setCurrentProgress(currentLocation);
-        lastLen = currentLocation;
-      }
+      mCurrentProgress += currentLocation;
     }
 
     @Override public void onStop(long stopLocation) {

From 4e305dcf01d5a953c38d7416f67ffcfa54bfe022 Mon Sep 17 00:00:00 2001
From: AriaLyy <511455842@qq.com>
Date: Sun, 2 Jul 2017 22:41:17 +0800
Subject: [PATCH 15/34] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E7=BB=84=E9=98=9F?=
 =?UTF-8?q?=E5=88=97=E5=AE=8C=E6=88=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../aria/core/command/group/AbsGroupCmd.java  |   9 +-
 .../aria/core/command/normal/AddCmd.java      |   2 +-
 .../aria/core/command/normal/CancelCmd.java   |   4 +-
 .../command/normal/HighestPriorityCmd.java    |  10 +-
 .../core/command/normal/ResumeAllCmd.java     |   4 +-
 .../aria/core/command/normal/StartCmd.java    |   4 +-
 .../aria/core/command/normal/StopCmd.java     |   4 +-
 .../aria/core/download/DownloadGroupTask.java | 474 ++++++++----------
 .../aria/core/download/DownloadTask.java      |   6 +-
 .../downloader/DownloadGroupUtil.java         |  20 +-
 .../download/downloader/DownloadUtil.java     | 443 +---------------
 ...{DownloadThreader.java => Downloader.java} |  36 +-
 .../downloader/IDownloadListener.java         |   2 +-
 .../download/downloader/IDownloadUtil.java    |   2 +-
 .../download/downloader/SingleThreadTask.java |   4 +-
 ...tateConstance.java => StateConstance.java} |   4 +-
 .../com/arialyy/aria/core/inf/AbsEntity.java  |  14 +
 .../arialyy/aria/core/inf/AbsGroupTask.java   |  40 --
 .../aria/core/inf/AbsNormalEntity.java        |  15 +-
 .../aria/core/inf/AbsNormalTarget.java        |   2 +-
 .../arialyy/aria/core/inf/AbsNormalTask.java  |  52 --
 .../com/arialyy/aria/core/inf/AbsTask.java    |  58 ++-
 .../java/com/arialyy/aria/core/inf/ITask.java |   1 -
 .../arialyy/aria/core/queue/AbsTaskQueue.java |  74 ++-
 .../core/queue/DownloadGroupTaskQueue.java    |  48 +-
 .../aria/core/queue/DownloadTaskQueue.java    |  63 +--
 .../arialyy/aria/core/queue/ITaskQueue.java   |  11 +-
 .../arialyy/aria/core/queue/TaskFactory.java  |  32 +-
 .../aria/core/queue/UploadTaskQueue.java      |  26 +-
 ...ormalCachePool.java => BaseCachePool.java} |   8 +-
 ...lExecutePool.java => BaseExecutePool.java} |  28 +-
 .../core/queue/pool/DownloadExecutePool.java  |  82 +++
 .../aria/core/queue/pool/GroupCachePool.java  |  23 -
 .../core/queue/pool/GroupExecutePool.java     |  23 -
 .../arialyy/aria/core/queue/pool/IPool.java   |  14 +-
 .../aria/core/scheduler/AbsSchedulers.java    |  12 +-
 .../scheduler/DownloadGroupSchedulers.java    |  45 ++
 .../core/scheduler/DownloadSchedulers.java    |   2 +-
 .../arialyy/aria/core/upload/UploadUtil.java  |   6 +-
 .../java/com/arialyy/aria/util/CheckUtil.java |   8 +-
 .../com/arialyy/aria/core/Configuration.java  |   5 +-
 .../aria/core/upload/UploadTaskEntity.java    |  10 +-
 42 files changed, 688 insertions(+), 1042 deletions(-)
 rename Aria/src/main/java/com/arialyy/aria/core/download/downloader/{DownloadThreader.java => Downloader.java} (92%)
 rename Aria/src/main/java/com/arialyy/aria/core/download/downloader/{DownloadStateConstance.java => StateConstance.java} (96%)
 rename Aria/src/main/java/com/arialyy/aria/core/queue/pool/{NormalCachePool.java => BaseCachePool.java} (95%)
 rename Aria/src/main/java/com/arialyy/aria/core/queue/pool/{NormalExecutePool.java => BaseExecutePool.java} (87%)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/queue/pool/DownloadExecutePool.java
 delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupCachePool.java
 delete mode 100644 Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupExecutePool.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadGroupSchedulers.java

diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java
index f8b2e0ed..56b8e17d 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java
@@ -16,8 +16,10 @@
 package com.arialyy.aria.core.command.group;
 
 import com.arialyy.aria.core.command.AbsCmd;
+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.queue.DownloadGroupTaskQueue;
 import com.arialyy.aria.core.queue.DownloadTaskQueue;
 import com.arialyy.aria.core.queue.UploadTaskQueue;
 import com.arialyy.aria.core.upload.UploadTaskEntity;
@@ -36,12 +38,9 @@ public abstract class AbsGroupCmd extends AbsCmd {
     mTargetName = targetName;
     mTaskEntity = entity;
     TAG = CommonUtil.getClassName(this);
-    if (entity instanceof DownloadTaskEntity) {
-      mQueue = DownloadTaskQueue.getInstance();
+    if (entity instanceof DownloadGroupTaskEntity) {
+      mQueue = DownloadGroupTaskQueue.getInstance();
       isDownloadCmd = true;
-    } else if (entity instanceof UploadTaskEntity) {
-      mQueue = UploadTaskQueue.getInstance();
-      isDownloadCmd = false;
     }
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
index 9e0d094e..6f7f3e9f 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
@@ -33,7 +33,7 @@ class AddCmd extends AbsNormalCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    AbsNormalTask task = mQueue.getTask(mTaskEntity.getEntity());
+    AbsNormalTask task = (AbsNormalTask) mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
       mTaskEntity.getEntity().setState(IEntity.STATE_WAIT);
       mQueue.createTask(mTargetName, mTaskEntity);
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
index 5621da16..4e13b329 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
@@ -31,9 +31,9 @@ class CancelCmd extends AbsNormalCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    AbsNormalTask task = mQueue.getTask(mTaskEntity.getEntity());
+    AbsNormalTask task = (AbsNormalTask) mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
-      task = mQueue.createTask(mTargetName, mTaskEntity);
+      task = (AbsNormalTask) mQueue.createTask(mTargetName, mTaskEntity);
     }
     if (task != null) {
       if (!TextUtils.isEmpty(mTargetName)) {
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java
index f12b6487..e0efa2f7 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java
@@ -16,8 +16,10 @@
 package com.arialyy.aria.core.command.normal;
 
 import android.text.TextUtils;
+import com.arialyy.aria.core.download.DownloadTask;
 import com.arialyy.aria.core.inf.AbsNormalTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
+import com.arialyy.aria.core.queue.DownloadTaskQueue;
 
 /**
  * Created by lyy on 2017/6/2.
@@ -28,6 +30,8 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
  * 4、用户手动暂停或任务完成后,第二次重新执行该任务,该命令将失效
  * 5、如果下载队列中已经满了,则会停止队尾的任务,当高优先级任务完成后,该队尾任务将自动执行
  * 6、把任务设置为最高优先级任务后,将自动执行任务,不需要重新调用start()启动任务
+ *
+ * 目前只只支持单下载任务的最高优先级任务
  */
 final class HighestPriorityCmd extends AbsNormalCmd {
   /**
@@ -39,15 +43,15 @@ final class HighestPriorityCmd extends AbsNormalCmd
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    AbsNormalTask task = mQueue.getTask(mTaskEntity.getEntity());
+    DownloadTask task = (DownloadTask) mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
-      task = mQueue.createTask(mTargetName, mTaskEntity);
+      task = (DownloadTask) mQueue.createTask(mTargetName, mTaskEntity);
     }
     if (task != null) {
       if (!TextUtils.isEmpty(mTargetName)) {
         task.setTargetName(mTargetName);
       }
-      mQueue.setTaskHighestPriority(task);
+      ((DownloadTaskQueue) mQueue).setTaskHighestPriority(task);
     }
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
index 8ae46e85..cd3336e7 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
@@ -39,10 +39,10 @@ final class ResumeAllCmd extends AbsNormalCmd {
   }
 
   private AbsNormalTask createTask(DownloadEntity entity) {
-    AbsNormalTask task = mQueue.getTask(entity);
+    AbsNormalTask task = (AbsNormalTask) mQueue.getTask(entity);
     if (task == null) {
       DownloadTaskEntity taskEntity = new DownloadTaskEntity(entity);
-      task = mQueue.createTask(mTargetName, taskEntity);
+      task = (AbsNormalTask) mQueue.createTask(mTargetName, taskEntity);
     } else {
       Log.w(TAG, "添加命令执行失败,【该任务已经存在】");
     }
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 39f58cd7..11c713af 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
@@ -47,9 +47,9 @@ class StartCmd extends AbsNormalCmd {
       maxTaskNum = manager.getUploadConfig().getMaxTaskNum();
     }
 
-    AbsNormalTask task = mQueue.getTask(mTaskEntity.getEntity());
+    AbsNormalTask task = (AbsNormalTask) mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
-      task = mQueue.createTask(mTargetName, mTaskEntity);
+      task = (AbsNormalTask) mQueue.createTask(mTargetName, mTaskEntity);
       if (!TextUtils.isEmpty(mTargetName)) {
         task.setTargetName(mTargetName);
       }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
index 84d55329..cd926b7c 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
@@ -34,10 +34,10 @@ class StopCmd extends AbsNormalCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    AbsNormalTask task = mQueue.getTask(mTaskEntity.getEntity());
+    AbsNormalTask task = (AbsNormalTask) mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
       if (mTaskEntity.getEntity().getState() == IEntity.STATE_RUNNING) {
-        task = mQueue.createTask(mTargetName, mTaskEntity);
+        task = (AbsNormalTask) mQueue.createTask(mTargetName, mTaskEntity);
         mQueue.stopTask(task);
       } else {
         Log.w(TAG, "停止命令执行失败,【调度器中没有该任务】");
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 308c041e..9c3d778e 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
@@ -1,269 +1,205 @@
-///*
-// * 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.content.Context;
-//import android.os.Handler;
-//import android.util.SparseArray;
-//import com.arialyy.aria.core.Aria;
-//import com.arialyy.aria.core.AriaManager;
-//import com.arialyy.aria.core.download.downloader.DownloadListener;
-//import com.arialyy.aria.core.download.downloader.DownloadUtil;
-//import com.arialyy.aria.core.inf.AbsGroupTask;
-//import com.arialyy.aria.core.inf.IEntity;
-//import com.arialyy.aria.core.scheduler.DownloadSchedulers;
-//import com.arialyy.aria.core.scheduler.ISchedulers;
-//import com.arialyy.aria.util.CheckUtil;
-//import com.arialyy.aria.util.CommonUtil;
-//import java.lang.ref.WeakReference;
-//import java.util.HashMap;
-//import java.util.List;
-//import java.util.Map;
-//import java.util.concurrent.ExecutorService;
-//import java.util.concurrent.Executors;
-//
-///**
-// * Created by AriaL on 2017/6/27.
-// * 任务组任务
-// */
-//public class DownloadGroupTask extends AbsGroupTask {
-//  DListener mListener;
-//  SparseArray mUtils = new SparseArray<>();
-//  boolean isStop = false;
-//
-//  private ExecutorService mFixedThreadPool;
-//
-//  private DownloadGroupTask(DownloadTaskEntity taskEntity, Handler outHandler) {
-//    mTaskEntity = taskEntity;
-//    mEntity = taskEntity.groupEntity;
-//    mOutHandler = outHandler;
-//    mContext = AriaManager.APP;
-//    mListener = new DListener(mContext, this, mOutHandler);
-//    mFixedThreadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
-//  }
-//
-//  @Override public void start() {
-//    List childs = mEntity.getChild();
-//    int i = 1;
-//    mListener.sendInState2Target(ISchedulers.PRE);
-//    for (DownloadEntity entity : childs) {
-//      DownloadUtil util = createChildDownload(entity);
-//      if (isStop) break;
-//      mUtils.append(i, util);
-//      mFixedThreadPool.execute(util);
-//      i++;
-//    }
-//  }
-//
-//  /**
-//   * 创建任务组单个任务下载工具
-//   */
-//  private DownloadUtil createChildDownload(DownloadEntity entity) {
-//    DownloadTaskEntity taskEntity = new DownloadTaskEntity(entity);
-//    taskEntity.headers = mTaskEntity.headers;
-//    taskEntity.requestEnum = mTaskEntity.requestEnum;
-//    taskEntity.redirectUrlKey = mTaskEntity.redirectUrlKey;
-//    taskEntity.removeFile = mTaskEntity.removeFile;
-//    return new DownloadUtil(mContext, taskEntity, mListener);
-//  }
-//
-//  @Override public void stop() {
-//    isStop = true;
-//    if (mFixedThreadPool != null) {
-//      mFixedThreadPool.shutdown();
-//    }
-//    for (int i = 1, len = mUtils.size(); i <= len; i++) {
-//      DownloadUtil util = mUtils.get(i);
-//      if (util != null && util.isDownloading()) {
-//        util.stopDownload();
-//      }
-//    }
-//  }
-//
-//  @Override public void cancel() {
-//    isStop = true;
-//    if (mFixedThreadPool != null) {
-//      mFixedThreadPool.shutdown();
-//    }
-//    for (int i = 1, len = mUtils.size(); i <= len; i++) {
-//      DownloadUtil util = mUtils.get(i);
-//      if (util != null) {
-//        util.cancelDownload();
-//      }
-//    }
-//  }
-//
-//  /**
-//   * 下载监听类
-//   */
-//  private static class DListener extends DownloadListener {
-//    WeakReference outHandler;
-//    WeakReference wTask;
-//    Context context;
-//    long lastLen = 0;   //上一次发送长度
-//    long lastTime = 0;
-//    long INTERVAL_TIME = 1000;   //1m更新周期
-//    boolean isFirst = true;
-//    DownloadGroupEntity groupEntity;
-//    DownloadGroupTask task;
-//    boolean isConvertSpeed = false;
-//    Map mEntityMap = new HashMap<>();
-//
-//    DListener(Context context, DownloadGroupTask task, Handler outHandler) {
-//      this.context = context;
-//      this.outHandler = new WeakReference<>(outHandler);
-//      this.wTask = new WeakReference<>(task);
-//      this.task = wTask.get();
-//      this.groupEntity = this.task.getEntity();
-//      final AriaManager manager = AriaManager.getInstance(context);
-//      isConvertSpeed = manager.getDownloadConfig().isConvertSpeed();
-//      for (DownloadEntity entity : groupEntity.getChild()) {
-//        mEntityMap.put(entity.getDownloadUrl(), entity);
-//      }
-//    }
-//
-//    @Override public void onPre(String url) {
-//      saveData(url, IEntity.STATE_PRE, -1);
-//    }
-//
-//    @Override public void onPostPre(String url, long fileSize) {
-//      DownloadEntity entity = mEntityMap.get(url);
-//      if (entity != null){
-//        entity.setFileSize(fileSize);
-//      }
-//      saveData(url, IEntity.STATE_POST_PRE, -1);
-//    }
-//
-//    @Override public void onStart(String url, long startLocation) {
-//      downloadEntity.setState(IEntity.STATE_RUNNING);
-//      sendInState2Target(ISchedulers.START);
-//      sendIntent(Aria.ACTION_START, startLocation);
-//    }
-//
-//    @Override public void onResume(String url, long resumeLocation) {
-//      downloadEntity.setState(IEntity.STATE_RUNNING);
-//      sendInState2Target(ISchedulers.RESUME);
-//      sendIntent(Aria.ACTION_RESUME, resumeLocation);
-//    }
-//
-//    @Override public void onProgress(String url, long currentLocation) {
-//      if (System.currentTimeMillis() - lastTime > INTERVAL_TIME) {
-//        long speed = currentLocation - lastLen;
-//        sendIntent.putExtra(Aria.CURRENT_LOCATION, currentLocation);
-//        sendIntent.putExtra(Aria.CURRENT_SPEED, speed);
-//        lastTime = System.currentTimeMillis();
-//        if (isFirst) {
-//          speed = 0;
-//          isFirst = false;
-//        }
-//        handleSpeed(speed);
-//        downloadEntity.setCurrentProgress(currentLocation);
-//        lastLen = currentLocation;
-//        sendInState2Target(ISchedulers.RUNNING);
-//        context.sendBroadcast(sendIntent);
-//      }
-//    }
-//
-//    @Override public void onStop(String url, long stopLocation) {
-//      downloadEntity.setState(task.isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP);
-//      handleSpeed(0);
-//      sendInState2Target(ISchedulers.STOP);
-//      sendIntent(Aria.ACTION_STOP, stopLocation);
-//    }
-//
-//    @Override public void onCancel(String url) {
-//      downloadEntity.setState(IEntity.STATE_CANCEL);
-//      handleSpeed(0);
-//      sendInState2Target(ISchedulers.CANCEL);
-//      sendIntent(Aria.ACTION_CANCEL, -1);
-//      downloadEntity.deleteData();
-//    }
-//
-//    @Override public void onComplete(String url) {
-//      downloadEntity.setState(IEntity.STATE_COMPLETE);
-//      downloadEntity.setDownloadComplete(true);
-//      handleSpeed(0);
-//      sendInState2Target(ISchedulers.COMPLETE);
-//      sendIntent(Aria.ACTION_COMPLETE, downloadEntity.getFileSize());
-//    }
-//
-//    @Override public void onFail(String url) {
-//      downloadEntity.setFailNum(downloadEntity.getFailNum() + 1);
-//      downloadEntity.setState(IEntity.STATE_FAIL);
-//      handleSpeed(0);
-//      sendInState2Target(ISchedulers.FAIL);
-//      sendIntent(Aria.ACTION_FAIL, -1);
-//    }
-//
-//    private void handleSpeed(long speed) {
-//      if (isConvertSpeed) {
-//        downloadEntity.setConvertSpeed(CommonUtil.formatFileSize(speed) + "/s");
-//      } else {
-//        downloadEntity.setSpeed(speed);
-//      }
-//    }
-//
-//    /**
-//     * 将任务状态发送给下载器
-//     *
-//     * @param state {@link DownloadSchedulers#START}
-//     */
-//    private void sendInState2Target(int state) {
-//      if (outHandler.get() != null) {
-//        outHandler.get().obtainMessage(state, task).sendToTarget();
-//      }
-//    }
-//
-//    private void saveData(String url, int state, long location) {
-//      DownloadEntity child = mEntityMap.get(url);
-//      if (child != null) {
-//        child.setState(state);
-//        child.setDownloadComplete(state == IEntity.STATE_COMPLETE);
-//        child.setCurrentProgress(location);
-//        child.update();
-//      }
-//    }
-//  }
-//
-//  public static class Builder {
-//    DownloadTaskEntity taskEntity;
-//    Handler outHandler;
-//    String targetName;
-//
-//    public Builder(String targetName, DownloadTaskEntity taskEntity) {
-//      CheckUtil.checkTaskEntity(taskEntity);
-//      this.targetName = targetName;
-//      this.taskEntity = taskEntity;
-//    }
-//
-//    /**
-//     * 设置自定义Handler处理下载状态时间
-//     *
-//     * @param schedulers {@link ISchedulers}
-//     */
-//    public DownloadGroupTask.Builder setOutHandler(ISchedulers schedulers) {
-//      this.outHandler = new Handler(schedulers);
-//      return this;
-//    }
-//
-//    public DownloadGroupTask build() {
-//      DownloadGroupTask task = new DownloadGroupTask(taskEntity, outHandler);
-//      task.setTargetName(targetName);
-//      taskEntity.downloadEntity.save();
-//      return task;
-//    }
-//  }
-//}
+/*
+ * 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.content.Context;
+import android.os.Handler;
+import com.arialyy.aria.core.AriaManager;
+import com.arialyy.aria.core.download.downloader.DownloadGroupUtil;
+import com.arialyy.aria.core.download.downloader.DownloadListener;
+import com.arialyy.aria.core.download.downloader.IDownloadUtil;
+import com.arialyy.aria.core.inf.AbsGroupTask;
+import com.arialyy.aria.core.inf.IEntity;
+import com.arialyy.aria.core.scheduler.DownloadSchedulers;
+import com.arialyy.aria.core.scheduler.ISchedulers;
+import com.arialyy.aria.util.CheckUtil;
+import com.arialyy.aria.util.CommonUtil;
+import java.lang.ref.WeakReference;
+
+/**
+ * Created by AriaL on 2017/6/27.
+ * 任务组任务
+ */
+public class DownloadGroupTask extends AbsGroupTask {
+  private DListener mListener;
+  private IDownloadUtil mUtil;
+
+  private DownloadGroupTask(DownloadGroupTaskEntity taskEntity, Handler outHandler) {
+    mTaskEntity = taskEntity;
+    mEntity = taskEntity.getEntity();
+    mOutHandler = outHandler;
+    mContext = AriaManager.APP;
+    mListener = new DListener(mContext, this, mOutHandler);
+    mUtil = new DownloadGroupUtil(mListener, mTaskEntity);
+  }
+
+  @Override public boolean isRunning() {
+    return mUtil.isDownloading();
+  }
+
+  @Override public void start() {
+    mUtil.stopDownload();
+  }
+
+  @Override public void stop() {
+    mUtil.startDownload();
+  }
+
+  @Override public void cancel() {
+    mUtil.cancelDownload();
+  }
+
+  /**
+   * 下载监听类
+   */
+  private static class DListener extends DownloadListener {
+    WeakReference outHandler;
+    WeakReference wTask;
+    Context context;
+    long lastLen = 0;   //上一次发送长度
+    boolean isFirst = true;
+    DownloadGroupEntity entity;
+    DownloadGroupTask task;
+    boolean isConvertSpeed = false;
+
+    DListener(Context context, DownloadGroupTask task, Handler outHandler) {
+      this.context = context;
+      this.outHandler = new WeakReference<>(outHandler);
+      this.wTask = new WeakReference<>(task);
+      this.task = wTask.get();
+      this.entity = this.task.getEntity();
+      final AriaManager manager = AriaManager.getInstance(context);
+      isConvertSpeed = manager.getDownloadConfig().isConvertSpeed();
+    }
+
+    @Override public void onPre() {
+      saveData(IEntity.STATE_PRE, -1);
+      sendInState2Target(ISchedulers.PRE);
+    }
+
+    @Override public void onPostPre(long fileSize) {
+      entity.setFileSize(fileSize);
+      saveData(IEntity.STATE_POST_PRE, -1);
+      sendInState2Target(ISchedulers.POST_PRE);
+    }
+
+    @Override public void onStart(long startLocation) {
+      saveData(IEntity.STATE_RUNNING, startLocation);
+      sendInState2Target(ISchedulers.START);
+    }
+
+    @Override public void onResume(long resumeLocation) {
+      saveData(IEntity.STATE_RUNNING, resumeLocation);
+      sendInState2Target(ISchedulers.RESUME);
+    }
+
+    @Override public void onProgress(long currentLocation) {
+      long speed = currentLocation - lastLen;
+      if (isFirst) {
+        speed = 0;
+        isFirst = false;
+      }
+      handleSpeed(speed);
+      lastLen = currentLocation;
+      sendInState2Target(ISchedulers.RUNNING);
+    }
+
+    @Override public void onStop(long stopLocation) {
+      saveData(IEntity.STATE_STOP, stopLocation);
+      handleSpeed(0);
+      sendInState2Target(ISchedulers.STOP);
+    }
+
+    @Override public void onCancel() {
+      saveData(IEntity.STATE_CANCEL, -1);
+      handleSpeed(0);
+      sendInState2Target(ISchedulers.CANCEL);
+    }
+
+    @Override public void onComplete() {
+      saveData(IEntity.STATE_COMPLETE, entity.getFileSize());
+      handleSpeed(0);
+      sendInState2Target(ISchedulers.COMPLETE);
+    }
+
+    @Override public void onFail() {
+      entity.setFailNum(entity.getFailNum() + 1);
+      saveData(IEntity.STATE_FAIL, -1);
+      handleSpeed(0);
+      sendInState2Target(ISchedulers.FAIL);
+    }
+
+    private void handleSpeed(long speed) {
+      if (isConvertSpeed) {
+        entity.setConvertSpeed(CommonUtil.formatFileSize(speed) + "/s");
+      } else {
+        entity.setSpeed(speed);
+      }
+    }
+
+    /**
+     * 将任务状态发送给下载器
+     *
+     * @param state {@link DownloadSchedulers#START}
+     */
+    private void sendInState2Target(int state) {
+      if (outHandler.get() != null) {
+        outHandler.get().obtainMessage(state, task).sendToTarget();
+      }
+    }
+
+    private void saveData(int state, long location) {
+      if (state == IEntity.STATE_CANCEL) {
+        entity.deleteData();
+      } else {
+        entity.setState(state);
+        if (location != -1) {
+          entity.setCurrentProgress(location);
+        }
+        entity.update();
+      }
+    }
+  }
+
+  public static class Builder {
+    DownloadGroupTaskEntity taskEntity;
+    Handler outHandler;
+    String targetName;
+
+    public Builder(String targetName, DownloadGroupTaskEntity taskEntity) {
+      CheckUtil.checkTaskEntity(taskEntity);
+      this.targetName = targetName;
+      this.taskEntity = taskEntity;
+    }
+
+    /**
+     * 设置自定义Handler处理下载状态时间
+     *
+     * @param schedulers {@link ISchedulers}
+     */
+    public DownloadGroupTask.Builder setOutHandler(ISchedulers schedulers) {
+      this.outHandler = new Handler(schedulers);
+      return this;
+    }
+
+    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/DownloadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java
index 46d87b73..e70f6eb4 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
@@ -46,11 +46,11 @@ public class DownloadTask extends AbsNormalTask {
   private boolean isWait = false;
 
   private DownloadTask(DownloadTaskEntity taskEntity, Handler outHandler) {
-    mEntity = taskEntity.downloadEntity;
+    mEntity = taskEntity.getEntity();
     mOutHandler = outHandler;
     mContext = AriaManager.APP;
     mListener = new DListener(mContext, this, mOutHandler);
-    mUtil = new DownloadUtil(mContext, taskEntity, mListener);
+    mUtil = new DownloadUtil(taskEntity, mListener);
   }
 
   /**
@@ -194,7 +194,7 @@ public class DownloadTask extends AbsNormalTask {
     public DownloadTask build() {
       DownloadTask task = new DownloadTask(taskEntity, outHandler);
       task.setTargetName(targetName);
-      taskEntity.downloadEntity.save();
+      taskEntity.getEntity().save();
       return task;
     }
   }
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 1b1f7300..01e3c6bb 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
@@ -68,14 +68,14 @@ public class DownloadGroupUtil implements IDownloadUtil {
   /**
    * 下载器映射表,key为下载地址
    */
-  private Map mDownloaderMap = new HashMap<>();
+  private Map mDownloaderMap = new HashMap<>();
 
   /**
    * 文件信息回调组
    */
   private SparseArray mFileInfoCallbacks = new SparseArray<>();
 
-  DownloadGroupUtil(IDownloadListener listener, DownloadGroupTaskEntity taskEntity) {
+  public DownloadGroupUtil(IDownloadListener listener, DownloadGroupTaskEntity taskEntity) {
     mListener = listener;
     mTaskEntity = taskEntity;
     mInfoPool = Executors.newCachedThreadPool();
@@ -116,9 +116,9 @@ public class DownloadGroupUtil implements IDownloadUtil {
 
     Set keys = mDownloaderMap.keySet();
     for (String key : keys) {
-      DownloadThreader db = mDownloaderMap.get(key);
-      if (db != null) {
-        db.cancelDownload();
+      Downloader dt = mDownloaderMap.get(key);
+      if (dt != null) {
+        dt.cancelDownload();
       }
     }
   }
@@ -135,9 +135,9 @@ public class DownloadGroupUtil implements IDownloadUtil {
 
     Set keys = mDownloaderMap.keySet();
     for (String key : keys) {
-      DownloadThreader db = mDownloaderMap.get(key);
-      if (db != null) {
-        db.stopDownload();
+      Downloader dt = mDownloaderMap.get(key);
+      if (dt != null) {
+        dt.stopDownload();
       }
     }
   }
@@ -188,7 +188,7 @@ public class DownloadGroupUtil implements IDownloadUtil {
           }
           mFailNum++;
           failNum++;
-          if (failNum < 10){
+          if (failNum < 10) {
             mInfoPool.execute(createFileInfoThread(te));
           }
           if (mInitNum + mFailNum == mTaskEntity.getEntity().getChild().size()) {
@@ -228,7 +228,7 @@ public class DownloadGroupUtil implements IDownloadUtil {
    */
   private void startChildDownload(DownloadTaskEntity taskEntity) {
     ChildDownloadListener listener = new ChildDownloadListener(taskEntity);
-    DownloadThreader dt = new DownloadThreader(listener, taskEntity);
+    Downloader dt = new Downloader(listener, taskEntity);
     mDownloaderMap.put(taskEntity.getEntity().getDownloadUrl(), dt);
     mExePool.execute(dt);
   }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadUtil.java
index d2b3b8fe..1555dc67 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadUtil.java
@@ -16,23 +16,8 @@
 
 package com.arialyy.aria.core.download.downloader;
 
-import android.content.Context;
 import android.util.Log;
-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.orm.DbEntity;
-import com.arialyy.aria.util.BufferedRandomAccessFile;
-import com.arialyy.aria.util.CommonUtil;
-import java.io.File;
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 
 /**
  * Created by lyy on 2015/8/25.
@@ -40,170 +25,49 @@ import java.util.concurrent.Executors;
  */
 public class DownloadUtil implements IDownloadUtil, Runnable {
   private static final String TAG = "DownloadUtil";
-  /**
-   * 线程数
-   */
-  private int THREAD_NUM;
-  /**
-   * 小于1m的文件不启用多线程
-   */
-  private static final long SUB_LEN = 1024 * 1024;
-  //下载监听
   private IDownloadListener mListener;
-  private int mConnectTimeOut = 0; //连接超时时间
-  private boolean isNewTask = true;
-  private boolean isSupportBreakpoint = true;
-  private Context mContext;
-  private DownloadEntity mDownloadEntity;
+  private Downloader mDT;
   private DownloadTaskEntity mTaskEntity;
-  private ExecutorService mFixedThreadPool;
-  private File mDownloadFile; //下载的文件
-  private File mConfigFile;//下载信息配置文件
-  private SparseArray mTask = new SparseArray<>();
-  private DownloadStateConstance CONSTANCE;
 
-  DownloadUtil(Context context, DownloadTaskEntity entity, IDownloadListener downloadListener) {
-    mDownloadEntity = entity.getEntity();
-    mContext = context.getApplicationContext();
+  public DownloadUtil(DownloadTaskEntity entity, IDownloadListener downloadListener) {
     mTaskEntity = entity;
     mListener = downloadListener;
-    // 线程下载数改变后,新的下载才会生效
-    //mFixedThreadPool = Executors.newFixedThreadPool(Integer.MAX_VALUE);
-    CONSTANCE = new DownloadStateConstance();
-    init();
-  }
-
-  private void init() {
-    mConnectTimeOut = AriaManager.getInstance(mContext).getDownloadConfig().getConnectTimeOut();
-    mDownloadFile = new File(mTaskEntity.getEntity().getDownloadPath());
-    //读取已完成的线程数
-    mConfigFile = new File(mContext.getFilesDir().getPath()
-        + AriaManager.DOWNLOAD_TEMP_DIR
-        + mDownloadFile.getName()
-        + ".properties");
-    checkTask();
-  }
-
-  /**
-   * 检查任务是否是新任务,新任务条件:
-   * 1、文件不存在
-   * 2、下载记录文件不存在
-   * 3、下载记录文件缺失或不匹配
-   * 4、数据库记录不存在
-   */
-  private void checkTask() {
-    try {
-      if (!mConfigFile.exists()) { //记录文件被删除,则重新下载
-        isNewTask = true;
-        CommonUtil.createFile(mConfigFile.getPath());
-      } else if (!mDownloadFile.exists()) {
-        isNewTask = true;
-      } else if (DbEntity.findData(DownloadEntity.class, "downloadUrl=?",
-          mDownloadEntity.getDownloadUrl()) == null) {
-        isNewTask = true;
-      } else {
-        isNewTask = !mDownloadFile.exists();
-      }
-    } catch (Exception e) {
-      e.printStackTrace();
-      failDownload("下载失败,记录文件被删除");
-    }
-  }
-
-  public IDownloadListener getListener() {
-    return mListener;
+    mDT = new Downloader(downloadListener, entity);
   }
 
   @Override public long getFileSize() {
-    return mDownloadEntity.getFileSize();
+    return mDT.getFileSize();
   }
 
   /**
    * 获取当前下载位置
    */
   @Override public long getCurrentLocation() {
-    return CONSTANCE.CURRENT_LOCATION;
+    return mDT.getCurrentLocation();
   }
 
   @Override public boolean isDownloading() {
-    return CONSTANCE.isDownloading;
-  }
-
-  public void setMaxSpeed(double maxSpeed) {
-    for (int i = 0; i < THREAD_NUM; i++) {
-      SingleThreadTask task = (SingleThreadTask) mTask.get(i);
-      if (task != null) {
-        task.setMaxSpeed(maxSpeed);
-      }
-    }
+    return mDT.isDownloading();
   }
 
   /**
    * 取消下载
    */
   @Override public void cancelDownload() {
-    CONSTANCE.isCancel = true;
-    CONSTANCE.isDownloading = false;
-    if (mFixedThreadPool != null) {
-      mFixedThreadPool.shutdown();
-    }
-    for (int i = 0; i < THREAD_NUM; i++) {
-      SingleThreadTask task = (SingleThreadTask) mTask.get(i);
-      if (task != null) {
-        task.cancel();
-      }
-    }
-    CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, mDownloadEntity);
+    mDT.cancelDownload();
   }
 
   /**
    * 停止下载
    */
   @Override public void stopDownload() {
-    CONSTANCE.isStop = true;
-    CONSTANCE.isDownloading = false;
-    if (mFixedThreadPool != null) {
-      mFixedThreadPool.shutdown();
-    }
-    for (int i = 0; i < THREAD_NUM; i++) {
-      SingleThreadTask task = (SingleThreadTask) mTask.get(i);
-      if (task != null) {
-        task.stop();
-      }
-    }
-  }
-
-  /**
-   * 删除下载记录文件
-   */
-  public void delConfigFile() {
-    if (mContext != null && mDownloadEntity != null) {
-      File dFile = new File(mDownloadEntity.getDownloadPath());
-      File config =
-          new File(mContext.getFilesDir().getPath() + "/temp/" + dFile.getName() + ".properties");
-      if (config.exists()) {
-        config.delete();
-      }
-    }
-  }
-
-  /**
-   * 删除temp文件
-   */
-  public void delTempFile() {
-    if (mContext != null && mDownloadEntity != null) {
-      File dFile = new File(mDownloadEntity.getDownloadPath());
-      if (dFile.exists()) {
-        dFile.delete();
-      }
-    }
+    mDT.stopDownload();
   }
 
   /**
    * 多线程断点续传下载文件,开始下载
    */
   @Override public void startDownload() {
-    CONSTANCE.cleanState();
     mListener.onPre();
     new Thread(this).start();
   }
@@ -212,295 +76,24 @@ public class DownloadUtil implements IDownloadUtil, Runnable {
     startDownload();
   }
 
+  public void setMaxSpeed(double maxSpeed) {
+    mDT.setMaxSpeed(maxSpeed);
+  }
+
   private void failDownload(String msg) {
     Log.e(TAG, msg);
-    CONSTANCE.isDownloading = false;
     mListener.onFail();
   }
 
   @Override public void run() {
-    HttpURLConnection conn = null;
-    try {
-      URL url = new URL(mDownloadEntity.getDownloadUrl());
-      conn = ConnectionHelp.handleConnection(url);
-      conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
-      conn.setRequestProperty("Range", "bytes=" + 0 + "-");
-      conn.setConnectTimeout(mConnectTimeOut);
-      conn.connect();
-      handleConnect(conn);
-    } catch (IOException e) {
-      failDownload("下载失败【downloadUrl:"
-          + mDownloadEntity.getDownloadUrl()
-          + "】\n【filePath:"
-          + mDownloadFile.getPath()
-          + "】\n"
-          + CommonUtil.getPrintException(e));
-    } finally {
-      if (conn != null) {
-        conn.disconnect();
-      }
-    }
-  }
-
-  /**
-   * 处理状态码
-   */
-  private void handleConnect(HttpURLConnection conn) throws IOException {
-    int len = conn.getContentLength();
-    //if (len < 0) {  //网络被劫持时会出现这个问题
-    //  failDownload("下载失败,网络被劫持");
-    //  return;
-    //}
-    int code = conn.getResponseCode();
-    //https://zh.wikipedia.org/wiki/HTTP%E7%8A%B6%E6%80%81%E7%A0%81
-    //206支持断点
-    if (code == HttpURLConnection.HTTP_PARTIAL) {
-      if (!checkLen(len)) return;
-      isSupportBreakpoint = true;
-      mListener.supportBreakpoint(true);
-      handleBreakpoint(conn);
-    } else if (code == HttpURLConnection.HTTP_OK) {
-      //在conn.setRequestProperty("Range", "bytes=" + 0 + "-");下,200为不支持断点状态
-      if (!checkLen(len)) return;
-      isSupportBreakpoint = false;
-      mListener.supportBreakpoint(false);
-      Log.w(TAG, "该下载链接不支持断点下载");
-      handleBreakpoint(conn);
-    } else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
-      Log.w(TAG, "任务【" + mDownloadEntity.getDownloadUrl() + "】下载失败,错误码:404");
-      mListener.onCancel();
-    } else if (code == HttpURLConnection.HTTP_MOVED_TEMP
-        || code == HttpURLConnection.HTTP_MOVED_PERM
-        || code == HttpURLConnection.HTTP_SEE_OTHER) {
-      handle302Turn(conn);
-    } else {
-      failDownload("任务【" + mDownloadEntity.getDownloadUrl() + "】下载失败,错误码:" + code);
-    }
-  }
-
-  /**
-   * 检查长度是否合法
-   *
-   * @param len 从服务器获取的文件长度
-   * @return true, 合法
-   */
-  private boolean checkLen(long len) {
-    if (len < 0) {
-      failDownload("任务【" + mDownloadEntity.getDownloadUrl() + "】下载失败,文件长度小于0");
-      return false;
-    }
-    return true;
-  }
-
-  /**
-   * 处理30x跳转
-   */
-  private void handle302Turn(HttpURLConnection conn) throws IOException {
-    String newUrl = conn.getHeaderField(mTaskEntity.redirectUrlKey);
-    Log.d(TAG, "30x跳转,新url为【" + newUrl + "】");
-    mDownloadEntity.setRedirect(true);
-    mDownloadEntity.setRedirectUrl(newUrl);
-    mDownloadEntity.update();
-    String cookies = conn.getHeaderField("Set-Cookie");
-    conn = (HttpURLConnection) new URL(newUrl).openConnection();
-    conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
-    conn.setRequestProperty("Cookie", cookies);
-    conn.setRequestProperty("Range", "bytes=" + 0 + "-");
-    conn.setConnectTimeout(mConnectTimeOut);
-    conn.connect();
-    handleConnect(conn);
-  }
-
-  /**
-   * 处理断点
-   */
-  private void handleBreakpoint(HttpURLConnection conn) throws IOException {
-    //不支持断点只能单线程下载
-    if (!isSupportBreakpoint) {
-      handleNoSupportBreakpointDownload(conn);
-      return;
-    }
-    int fileLength = conn.getContentLength();
-    Properties pro = createConfigFile(fileLength);
-    int blockSize = fileLength / THREAD_NUM;
-    int[] recordL = new int[THREAD_NUM];
-    int rl = 0;
-    for (int i = 0; i < THREAD_NUM; i++) {
-      recordL[i] = -1;
-    }
-    for (int i = 0; i < THREAD_NUM; i++) {
-      long startL = i * blockSize, endL = (i + 1) * blockSize;
-      Object state = pro.getProperty(mDownloadFile.getName() + "_state_" + i);
-      if (state != null && Integer.parseInt(state + "") == 1) {  //该线程已经完成
-        if (resumeRecordLocation(i, startL, endL)) return;
-        continue;
-      }
-      //分配下载位置
-      Object record = pro.getProperty(mDownloadFile.getName() + "_record_" + i);
-      //如果有记录,则恢复下载
-      if (!isNewTask && record != null && Long.parseLong(record + "") >= 0) {
-        Long r = Long.parseLong(record + "");
-        CONSTANCE.CURRENT_LOCATION += r - startL;
-        Log.d(TAG, "任务【" + mDownloadEntity.getFileName() + "】线程__" + i + "__恢复下载");
-        mListener.onChildResume(r);
-        startL = r;
-        recordL[rl] = i;
-        rl++;
-      } else {
-        //handleNewTask(fileLength);
-        isNewTask = true;
-      }
-      if (isNewTask) {
-        recordL[rl] = i;
-        rl++;
-      }
-      if (i == (THREAD_NUM - 1)) {
-        //最后一个线程的结束位置即为文件的总长度
-        endL = fileLength;
-      }
-      addSingleTask(i, startL, endL, fileLength);
-    }
-    startSingleTask(recordL);
-  }
-
-  /**
-   * 处理不支持断点的下载
-   */
-  private void handleNoSupportBreakpointDownload(HttpURLConnection conn) {
-    ChildThreadConfigEntity entity = new ChildThreadConfigEntity();
-    long len = conn.getContentLength();
-    entity.FILE_SIZE = len;
-    entity.DOWNLOAD_URL = mDownloadEntity.isRedirect() ? mDownloadEntity.getRedirectUrl()
-        : mDownloadEntity.getDownloadUrl();
-    entity.TEMP_FILE = mDownloadFile;
-    entity.THREAD_ID = 0;
-    entity.START_LOCATION = 0;
-    entity.END_LOCATION = entity.FILE_SIZE;
-    entity.CONFIG_FILE_PATH = mConfigFile.getPath();
-    entity.IS_SUPPORT_BREAK_POINT = isSupportBreakpoint;
-    entity.DOWNLOAD_TASK_ENTITY = mTaskEntity;
-    THREAD_NUM = 1;
-    CONSTANCE.THREAD_NUM = THREAD_NUM;
-    SingleThreadTask task = new SingleThreadTask(CONSTANCE, mListener, entity);
-    mTask.put(0, task);
-    mFixedThreadPool.execute(task);
-    mListener.onPostPre(len);
-    mListener.onStart(0);
-  }
-
-  /**
-   * 创建配置文件
-   */
-  private Properties createConfigFile(long fileLength) throws IOException {
-    Properties pro = null;
-    //必须建一个文件
-    CommonUtil.createFile(mDownloadFile.getPath());
-    BufferedRandomAccessFile file =
-        new BufferedRandomAccessFile(new File(mDownloadFile.getPath()), "rwd", 8192);
-    //设置文件长度
-    file.setLength(fileLength);
-    file.close();
-    mListener.onPostPre(fileLength);
-    //分配每条线程的下载区间
-    pro = CommonUtil.loadConfig(mConfigFile);
-    if (pro.isEmpty()) {
-      handleNewTask(fileLength);
-    } else {
-      Set keys = pro.keySet();
-      int num = 0;
-      for (Object key : keys) {
-        if (String.valueOf(key).contains("_record_")) {
-          num++;
-        }
-      }
-      if (num == 0) {
-        handleNewTask(fileLength);
-        return pro;
-      }
-      THREAD_NUM = num;
-      for (int i = 0; i < THREAD_NUM; i++) {
-        if (pro.getProperty(mDownloadFile.getName() + "_record_" + i) == null) {
-          Object state = pro.getProperty(mDownloadFile.getName() + "_state_" + i);
-          if (state != null && Integer.parseInt(state + "") == 1) {
-            continue;
-          }
-          handleNewTask(fileLength);
-          return pro;
-        }
-      }
-      isNewTask = false;
-    }
-    return pro;
-  }
-
-  /**
-   * 处理新任务
-   */
-  private void handleNewTask(long fileLength) {
-    isNewTask = true;
-    THREAD_NUM = fileLength < SUB_LEN ? 1
-        : AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum();
-  }
-
-  /**
-   * 恢复记录地址
-   *
-   * @return true 表示下载完成
-   */
-  private boolean resumeRecordLocation(int i, long startL, long endL) {
-    CONSTANCE.CURRENT_LOCATION += endL - startL;
-    Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++");
-    CONSTANCE.COMPLETE_THREAD_NUM++;
-    CONSTANCE.STOP_NUM++;
-    CONSTANCE.CANCEL_NUM++;
-    if (CONSTANCE.isComplete()) {
-      if (mConfigFile.exists()) {
-        mConfigFile.delete();
+    new Thread(new FileInfoThread(mTaskEntity, new FileInfoThread.OnFileInfoCallback() {
+      @Override public void onComplete(String url, int code) {
+        mDT.startDownload();
       }
-      mListener.onComplete();
-      CONSTANCE.isDownloading = false;
-      return true;
-    }
-    return false;
-  }
-
-  /**
-   * 创建单线程任务
-   */
-  private void addSingleTask(int i, long startL, long endL, long fileLength) {
-    ChildThreadConfigEntity entity = new ChildThreadConfigEntity();
-    entity.FILE_SIZE = fileLength;
-    entity.DOWNLOAD_URL = mDownloadEntity.isRedirect() ? mDownloadEntity.getRedirectUrl()
-        : mDownloadEntity.getDownloadUrl();
-    entity.TEMP_FILE = mDownloadFile;
-    entity.THREAD_ID = i;
-    entity.START_LOCATION = startL;
-    entity.END_LOCATION = endL;
-    entity.CONFIG_FILE_PATH = mConfigFile.getPath();
-    entity.IS_SUPPORT_BREAK_POINT = isSupportBreakpoint;
-    entity.DOWNLOAD_TASK_ENTITY = mTaskEntity;
-    CONSTANCE.THREAD_NUM = THREAD_NUM;
-    SingleThreadTask task = new SingleThreadTask(CONSTANCE, mListener, entity);
-    mTask.put(i, task);
-  }
 
-  /**
-   * 启动单线程下载任务
-   */
-  private void startSingleTask(int[] recordL) {
-    if (CONSTANCE.CURRENT_LOCATION > 0) {
-      mListener.onResume(CONSTANCE.CURRENT_LOCATION);
-    } else {
-      mListener.onStart(CONSTANCE.CURRENT_LOCATION);
-    }
-    mFixedThreadPool = Executors.newFixedThreadPool(recordL.length);
-    for (int l : recordL) {
-      if (l == -1) continue;
-      Runnable task = mTask.get(l);
-      if (task != null) {
-        mFixedThreadPool.execute(task);
+      @Override public void onFail(String url, String errorMsg) {
+        failDownload(errorMsg);
       }
-    }
+    })).start();
   }
-
 }
\ No newline at end of file
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadThreader.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java
similarity index 92%
rename from Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadThreader.java
rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java
index ca70cc7c..dd2f2e40 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadThreader.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java
@@ -33,9 +33,10 @@ import java.util.concurrent.Executors;
 
 /**
  * Created by AriaL on 2017/7/1.
+ * 文件下载器
  */
-class DownloadThreader implements Runnable, IDownloadUtil {
-  private final String TAG = "DownloadThreader";
+class Downloader implements Runnable, IDownloadUtil {
+  private final String TAG = "Downloader";
   private IDownloadListener mListener;
   private DownloadTaskEntity mTaskEntity;
   private DownloadEntity mEntity;
@@ -45,15 +46,33 @@ class DownloadThreader implements Runnable, IDownloadUtil {
   private File mTempFile; //下载的文件
   private boolean isNewTask = true;
   private int mThreadNum, mRealThreadNum;
-  private DownloadStateConstance mConstance;
+  private StateConstance mConstance;
   private SparseArray mTask = new SparseArray<>();
 
-  DownloadThreader(IDownloadListener listener, DownloadTaskEntity taskEntity) {
+  /**
+   * 小于1m的文件不启用多线程
+   */
+  private static final long SUB_LEN = 1024 * 1024;
+
+  Downloader(IDownloadListener listener, DownloadTaskEntity taskEntity) {
     mListener = listener;
     mTaskEntity = taskEntity;
     mEntity = mTaskEntity.getEntity();
     mContext = AriaManager.APP;
-    mConstance = new DownloadStateConstance();
+    mConstance = new StateConstance();
+  }
+
+  void setMaxSpeed(double maxSpeed) {
+    for (int i = 0; i < mThreadNum; i++) {
+      SingleThreadTask task = (SingleThreadTask) mTask.get(i);
+      if (task != null) {
+        task.setMaxSpeed(maxSpeed);
+      }
+    }
+  }
+
+  public StateConstance getConstance() {
+    return mConstance;
   }
 
   @Override public void run() {
@@ -106,15 +125,16 @@ class DownloadThreader implements Runnable, IDownloadUtil {
   }
 
   @Override public void startDownload() {
+    mConstance.cleanState();
     mConstance.isDownloading = true;
     try {
       if (!mTaskEntity.isSupportBP) {
         mThreadNum = 1;
         handleNoSupportBreakpointDownload();
       } else {
-        mThreadNum =
-            isNewTask ? AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum()
-                : mRealThreadNum;
+        mThreadNum = isNewTask ? (mEntity.getFileSize() <= SUB_LEN ? 1
+            : AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum())
+            : mRealThreadNum;
         mFixedThreadPool = Executors.newFixedThreadPool(mThreadNum);
         handleBreakpoint();
       }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadListener.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadListener.java
index d9c06376..7b77cd59 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadListener.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadListener.java
@@ -19,7 +19,7 @@ package com.arialyy.aria.core.download.downloader;
 /**
  * 下载监听
  */
-interface IDownloadListener {
+public interface IDownloadListener {
 
   /**
    * 支持断点回调
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java
index f0265cf3..bcfe8a5a 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java
@@ -20,7 +20,7 @@ package com.arialyy.aria.core.download.downloader;
  * Created by lyy on 2016/10/31.
  * 抽象的下载接口
  */
-interface IDownloadUtil {
+public interface IDownloadUtil {
 
   /**
    * 获取文件大小
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SingleThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SingleThreadTask.java
index 245d32e6..278f4873 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SingleThreadTask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SingleThreadTask.java
@@ -41,10 +41,10 @@ final class SingleThreadTask implements Runnable {
   private long mChildCurrentLocation = 0;
   private int mBufSize;
   private IDownloadListener mListener;
-  private DownloadStateConstance CONSTANCE;
+  private StateConstance CONSTANCE;
   private long mSleepTime = 0;
 
-  SingleThreadTask(DownloadStateConstance constance, IDownloadListener listener,
+  SingleThreadTask(StateConstance constance, IDownloadListener listener,
       ChildThreadConfigEntity downloadInfo) {
     AriaManager manager = AriaManager.getInstance(AriaManager.APP);
     CONSTANCE = constance;
diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadStateConstance.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java
similarity index 96%
rename from Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadStateConstance.java
rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java
index 7d145a1a..fa082bd9 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadStateConstance.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java
@@ -19,7 +19,7 @@ package com.arialyy.aria.core.download.downloader;
  * Created by lyy on 2017/1/18.
  * 下载状态常量
  */
-final class DownloadStateConstance {
+final class StateConstance {
   int CANCEL_NUM = 0;
   int STOP_NUM = 0;
   int FAIL_NUM = 0;
@@ -32,7 +32,7 @@ final class DownloadStateConstance {
   boolean isCancel = false;
   boolean isStop = false;
 
-  DownloadStateConstance() {
+  StateConstance() {
   }
 
   void cleanState() {
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 63806454..d69d1b43 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
@@ -32,6 +32,10 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
    * 单位转换后的速度
    */
   @Ignore private String convertSpeed = "0b/s";
+  /**
+   * 下载失败计数,每次开始都重置为0
+   */
+  @Ignore private int failNum = 0;
 
   /**
    * 扩展字段
@@ -51,6 +55,14 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
    */
   private long completeTime;
 
+  public int getFailNum() {
+    return failNum;
+  }
+
+  public void setFailNum(int failNum) {
+    this.failNum = failNum;
+  }
+
   public long getSpeed() {
     return speed;
   }
@@ -117,6 +129,7 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
   @Override public void writeToParcel(Parcel dest, int flags) {
     dest.writeLong(this.speed);
     dest.writeString(this.convertSpeed);
+    dest.writeInt(this.failNum);
     dest.writeString(this.str);
     dest.writeLong(this.fileSize);
     dest.writeInt(this.state);
@@ -127,6 +140,7 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
   protected AbsEntity(Parcel in) {
     this.speed = in.readLong();
     this.convertSpeed = in.readString();
+    this.failNum = in.readInt();
     this.str = in.readString();
     this.fileSize = in.readLong();
     this.state = in.readInt();
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java
index b7eb3a93..83bc8993 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java
@@ -15,7 +15,6 @@
  */
 package com.arialyy.aria.core.inf;
 
-import com.arialyy.aria.util.CommonUtil;
 
 /**
  * Created by AriaL on 2017/6/29.
@@ -25,47 +24,8 @@ public abstract class AbsGroupTask extends AbsTask implements ITask
   private String mTargetName;
   protected Context mContext;
 
+  /**
+   * 获取当前下载进度
+   */
+  @Override public long getCurrentProgress() {
+    return mEntity.getCurrentProgress();
+  }
+
+  /**
+   * 获取单位转换后的进度
+   *
+   * @return 如:已经下载3mb的大小,则返回{@code 3mb}
+   */
+  @Override public String getConvertCurrentProgress() {
+    if (mEntity.getCurrentProgress() == 0) {
+      return "0b";
+    }
+    return CommonUtil.formatFileSize(mEntity.getCurrentProgress());
+  }
+
+  /**
+   * 转换单位后的文件长度
+   *
+   * @return 如果文件长度为0,则返回0m,否则返回转换后的长度1b、1kb、1mb、1gb、1tb
+   */
+  @Override public String getConvertFileSize() {
+    if (mEntity.getFileSize() == 0) {
+      return "0mb";
+    }
+    return CommonUtil.formatFileSize(mEntity.getFileSize());
+  }
+
+  /**
+   * 获取文件大小
+   */
+  @Override public long getFileSize() {
+    return mEntity.getFileSize();
+  }
+
+  /**
+   * 获取百分比进度
+   *
+   * @return 返回百分比进度,如果文件长度为0,返回0
+   */
+  @Override public int getPercent() {
+    if (mEntity.getFileSize() == 0) {
+      return 0;
+    }
+    return (int) (mEntity.getCurrentProgress() * 100 / mEntity.getFileSize());
+  }
+
   /**
    * 任务当前状态
    *
@@ -96,13 +147,6 @@ public abstract class AbsTask implements ITask
     return mEntity;
   }
 
-  /**
-   * 删除任务记录,删除后,再次启动该任务的下载时,将重新下载
-   */
-  @Override public void removeRecord() {
-    mEntity.deleteData();
-  }
-
   public String getTargetName() {
     return mTargetName;
   }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java b/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
index b5caee25..70bee951 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
@@ -92,5 +92,4 @@ public interface ITask {
 
   public void setTargetName(String targetName);
 
-  public void removeRecord();
 }
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 fa307650..2edafc91 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
@@ -18,22 +18,25 @@ package com.arialyy.aria.core.queue;
 
 import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.inf.AbsNormalEntity;
-import com.arialyy.aria.core.inf.AbsNormalTask;
+import com.arialyy.aria.core.download.DownloadEntity;
+import com.arialyy.aria.core.download.DownloadTask;
+import com.arialyy.aria.core.inf.AbsEntity;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
-import com.arialyy.aria.core.queue.pool.NormalCachePool;
-import com.arialyy.aria.core.queue.pool.NormalExecutePool;
+import com.arialyy.aria.core.inf.IEntity;
+import com.arialyy.aria.core.queue.pool.BaseCachePool;
+import com.arialyy.aria.core.queue.pool.BaseExecutePool;
 import java.util.Set;
 
 /**
  * Created by lyy on 2017/2/23.
  * 任务队列
  */
-abstract class AbsTaskQueue
+abstract class AbsTaskQueue
     implements ITaskQueue {
   private final String TAG = "AbsTaskQueue";
-  NormalCachePool mCachePool = new NormalCachePool<>();
-  NormalExecutePool mExecutePool;
+  BaseCachePool mCachePool = new BaseCachePool<>();
+  BaseExecutePool mExecutePool;
 
   @Override public boolean taskIsRunning(String key) {
     return mExecutePool.getTask(key) != null;
@@ -70,17 +73,27 @@ abstract class AbsTaskQueue= oldMaxSize) {
+      for (int i = 0, len = Math.abs(diff); i < len; i++) {
+        TASK eTask = mExecutePool.pollTask();
+        if (eTask != null) {
+          stopTask(eTask);
+        }
+      }
+    }
+    mExecutePool.setMaxNum(downloadNum);
+    if (diff >= 1) {
+      for (int i = 0; i < diff; i++) {
+        TASK nextTask = getNextTask();
+        if (nextTask != null && nextTask.getState() == IEntity.STATE_WAIT) {
+          startTask(nextTask);
+        }
+      }
+    }
   }
 
   @Override public TASK getTask(String url) {
@@ -124,7 +160,6 @@ abstract class AbsTaskQueue {
+  private static volatile DownloadGroupTaskQueue INSTANCE = null;
+
+  private final String TAG = "DownloadGroupTaskQueue";
+
+  public static DownloadGroupTaskQueue getInstance() {
+    if (INSTANCE == null) {
+      synchronized (AriaManager.LOCK) {
+        INSTANCE = new DownloadGroupTaskQueue();
+      }
+    }
+    return INSTANCE;
+  }
+
+  private DownloadGroupTaskQueue() {
+    mExecutePool = new BaseExecutePool<>(true);
+  }
+
+  @Override public DownloadGroupTask createTask(String targetName, DownloadGroupTaskEntity entity) {
+    DownloadGroupTask task = null;
+    if (!TextUtils.isEmpty(targetName)) {
+      task = (DownloadGroupTask) TaskFactory.getInstance()
+          .createTask(targetName, entity, DownloadGroupSchedulers.getInstance());
+      mCachePool.putTask(task);
+    } else {
+      Log.e(TAG, "target name 为 null!!");
+    }
+    return task;
+  }
+
+  @Override public String getKey(DownloadGroupEntity entity) {
+    return entity.getGroupName();
+  }
+
+  @Override public int getConfigMaxNum() {
+    return AriaManager.getInstance(AriaManager.APP).getDownloadConfig().oldMaxTaskNum;
+  }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java
index f0e9d6f4..169a9839 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java
@@ -22,8 +22,7 @@ import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.download.DownloadTask;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.core.inf.IEntity;
-import com.arialyy.aria.core.queue.pool.NormalExecutePool;
+import com.arialyy.aria.core.queue.pool.DownloadExecutePool;
 import com.arialyy.aria.core.scheduler.DownloadSchedulers;
 import java.util.LinkedHashSet;
 import java.util.Map;
@@ -48,10 +47,21 @@ public class DownloadTaskQueue
   }
 
   private DownloadTaskQueue() {
-    mExecutePool = new NormalExecutePool<>(true);
+    mExecutePool = new DownloadExecutePool(true);
   }
 
-  @Override public void setTaskHighestPriority(DownloadTask task) {
+  @Override public String getKey(DownloadEntity entity) {
+    return entity.getDownloadUrl();
+  }
+
+  @Override public int getConfigMaxNum() {
+    return AriaManager.getInstance(AriaManager.APP).getDownloadConfig().oldMaxTaskNum;
+  }
+
+  /**
+   * 设置任务为最高优先级任务
+   */
+  public void setTaskHighestPriority(DownloadTask task) {
     task.setHighestPriority(true);
     Map exeTasks = mExecutePool.getAllTask();
     if (exeTasks != null && !exeTasks.isEmpty()) {
@@ -103,33 +113,6 @@ public class DownloadTaskQueue
     }
   }
 
-  @Override public void setMaxTaskNum(int downloadNum) {
-    int oldMaxSize = AriaManager.getInstance(AriaManager.APP).getDownloadConfig().oldMaxTaskNum;
-    int diff = downloadNum - oldMaxSize;
-    if (oldMaxSize == downloadNum) {
-      Log.d(TAG, "设置的下载任务数和配置文件的下载任务数一直,跳过");
-      return;
-    }
-    //设置的任务数小于配置任务数
-    if (diff <= -1 && mExecutePool.size() >= oldMaxSize) {
-      for (int i = 0, len = Math.abs(diff); i < len; i++) {
-        DownloadTask eTask = mExecutePool.pollTask();
-        if (eTask != null) {
-          stopTask(eTask);
-        }
-      }
-    }
-    mExecutePool.setMaxNum(downloadNum);
-    if (diff >= 1) {
-      for (int i = 0; i < diff; i++) {
-        DownloadTask nextTask = getNextTask();
-        if (nextTask != null && nextTask.getDownloadEntity().getState() == IEntity.STATE_WAIT) {
-          startTask(nextTask);
-        }
-      }
-    }
-  }
-
   @Override public DownloadTask createTask(String target, DownloadTaskEntity entity) {
     DownloadTask task = null;
     if (!TextUtils.isEmpty(target)) {
@@ -137,23 +120,13 @@ public class DownloadTaskQueue
           .createTask(target, entity, DownloadSchedulers.getInstance());
       mCachePool.putTask(task);
     } else {
-      Log.e(TAG, "target name 为 null是!!");
+      Log.e(TAG, "target name 为 null!!");
     }
     return task;
   }
 
-  @Override public DownloadTask getTask(DownloadEntity entity) {
-    return getTask(entity.getDownloadUrl());
-  }
-
-  @Override public void removeTask(DownloadEntity entity) {
-    DownloadTask task = mExecutePool.getTask(entity.getDownloadUrl());
-    if (task != null) {
-      Log.d(TAG, "从执行池删除任务,删除" + (mExecutePool.removeTask(task) ? "成功" : "失败"));
-    }
-    task = mCachePool.getTask(entity.getDownloadUrl());
-    if (task != null) {
-      Log.d(TAG, "从缓存池删除任务,删除" + (mCachePool.removeTask(task) ? "成功" : "失败"));
-    }
+  @Override public void stopTask(DownloadTask task) {
+    task.setHighestPriority(false);
+    super.stopTask(task);
   }
 }
\ No newline at end of file
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
index 4ce69d80..01453ae0 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
@@ -19,7 +19,9 @@ package com.arialyy.aria.core.queue;
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.download.DownloadTask;
+import com.arialyy.aria.core.inf.AbsEntity;
 import com.arialyy.aria.core.inf.AbsNormalTask;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.upload.UploadEntity;
@@ -30,7 +32,7 @@ import com.arialyy.aria.core.upload.UploadTaskEntity;
  * Created by lyy on 2016/8/16.
  * 任务功能接口
  */
-public interface ITaskQueue {
+public interface ITaskQueue {
 
   /**
    * 通过key判断任务是否正在执行
@@ -50,13 +52,6 @@ public interface ITaskQueue {@link DownloadTaskEntity}、{@link UploadTaskEntity}
-   * @param  {@link DownloadSchedulers}
-   * @return {@link DownloadTask}、{@link UploadTask}
+   * @param  {@link DownloadTaskEntity}、{@link UploadTaskEntity}、{@link
+   * DownloadGroupTaskEntity}
+   * @param  {@link DownloadSchedulers}、{@link UploadSchedulers}
+   * @return {@link DownloadTask}、{@link UploadTask}、{@link DownloadGroupTask}
    */
-   ITask createTask(String targetName,
-      ENTITY entity, SCHEDULER schedulers) {
+   ITask createTask(
+      String targetName, TASK_ENTITY entity, SCHEDULER schedulers) {
     if (entity instanceof DownloadTaskEntity) {
       return createDownloadTask(targetName, (DownloadTaskEntity) entity, schedulers);
     } else if (entity instanceof UploadTaskEntity) {
       return createUploadTask(targetName, (UploadTaskEntity) entity, schedulers);
+    } else if (entity instanceof DownloadGroupTaskEntity) {
+      return createDownloadGroupTask(targetName, (DownloadGroupTaskEntity) entity, schedulers);
     }
     return null;
   }
 
+  /**
+   * 创建下载任务主任务
+   *
+   * @param entity 下载任务实体{@link DownloadGroupTask}
+   * @param schedulers {@link ISchedulers}
+   */
+  private DownloadGroupTask createDownloadGroupTask(String targetName,
+      DownloadGroupTaskEntity entity, ISchedulers schedulers) {
+    DownloadGroupTask.Builder builder = new DownloadGroupTask.Builder(targetName, entity);
+    builder.setOutHandler(schedulers);
+    return builder.build();
+  }
+
   /**
    * @param entity 上传任务实体{@link UploadTaskEntity}
    * @param schedulers {@link ISchedulers}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java
index 3e0eb262..0d36f105 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java
@@ -19,7 +19,7 @@ package com.arialyy.aria.core.queue;
 import android.text.TextUtils;
 import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.queue.pool.NormalExecutePool;
+import com.arialyy.aria.core.queue.pool.BaseExecutePool;
 import com.arialyy.aria.core.scheduler.UploadSchedulers;
 import com.arialyy.aria.core.upload.UploadEntity;
 import com.arialyy.aria.core.upload.UploadTask;
@@ -43,13 +43,18 @@ public class UploadTaskQueue extends AbsTaskQueue(false);
+    mExecutePool = new BaseExecutePool<>(false);
   }
 
-  @Override public void setMaxTaskNum(int newMaxNum) {
+  @Override public String getKey(UploadEntity entity) {
+    return entity.getFilePath();
+  }
 
+  @Override public int getConfigMaxNum() {
+    return AriaManager.getInstance(AriaManager.APP).getUploadConfig().oldMaxTaskNum;
   }
 
+
   @Override public UploadTask createTask(String targetName, UploadTaskEntity entity) {
     UploadTask task = null;
     if (!TextUtils.isEmpty(targetName)) {
@@ -61,19 +66,4 @@ public class UploadTaskQueue extends AbsTaskQueue implements IPool {
-  private static final String TAG = "NormalCachePool";
+public class BaseCachePool implements IPool {
+  private static final String TAG = "BaseCachePool";
   private static final int MAX_NUM = Integer.MAX_VALUE;  //最大下载任务数
   private static final long TIME_OUT = 1000;
   private Map mCacheMap;
   private LinkedBlockingQueue mCacheQueue;
 
-  public NormalCachePool() {
+  public BaseCachePool() {
     mCacheQueue = new LinkedBlockingQueue<>(MAX_NUM);
     mCacheMap = new HashMap<>();
   }
@@ -95,7 +95,7 @@ public class NormalCachePool implements IPool {
   @Override public TASK pollTask() {
     synchronized (AriaManager.LOCK) {
       try {
-        TASK task = null;
+        TASK task;
         task = mCacheQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
         if (task != null) {
           String url = task.getKey();
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/NormalExecutePool.java b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/BaseExecutePool.java
similarity index 87%
rename from Aria/src/main/java/com/arialyy/aria/core/queue/pool/NormalExecutePool.java
rename to Aria/src/main/java/com/arialyy/aria/core/queue/pool/BaseExecutePool.java
index 756d40cf..edcb67a4 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/NormalExecutePool.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/BaseExecutePool.java
@@ -23,7 +23,6 @@ import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.util.CommonUtil;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.TimeUnit;
 
@@ -31,14 +30,14 @@ import java.util.concurrent.TimeUnit;
  * Created by lyy on 2016/8/15.
  * 任务执行池,所有当前下载任务都该任务池中,默认下载大小为2
  */
-public class NormalExecutePool implements IPool {
-  private static final String TAG = "NormalExecutePool";
-  private static final long TIME_OUT = 1000;
-  private ArrayBlockingQueue mExecuteQueue;
-  private Map mExecuteMap;
-  private int mSize;
+public class BaseExecutePool implements IPool {
+  private final String TAG = "BaseExecutePool";
+  final long TIME_OUT = 1000;
+  ArrayBlockingQueue mExecuteQueue;
+  Map mExecuteMap;
+  protected int mSize;
 
-  public NormalExecutePool(boolean isDownload) {
+  public BaseExecutePool(boolean isDownload) {
     if (isDownload) {
       mSize = AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxTaskNum();
     } else {
@@ -67,10 +66,6 @@ public class NormalExecutePool implements IPool {
         return false;
       } else {
         if (mExecuteQueue.size() >= mSize) {
-          Set keys = mExecuteMap.keySet();
-          for (String key : keys) {
-            if (mExecuteMap.get(key).isHighestPriorityTask()) return false;
-          }
           if (pollFirstTask()) {
             return putNewTask(task);
           }
@@ -106,7 +101,7 @@ public class NormalExecutePool implements IPool {
    *
    * @param newTask 新任务
    */
-  private boolean putNewTask(TASK newTask) {
+  boolean putNewTask(TASK newTask) {
     String url = newTask.getKey();
     boolean s = mExecuteQueue.offer(newTask);
     Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】"));
@@ -119,16 +114,13 @@ public class NormalExecutePool implements IPool {
   /**
    * 队列满时,将移除下载队列中的第一个任务
    */
-  private boolean pollFirstTask() {
+  boolean pollFirstTask() {
     try {
       TASK oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
       if (oldTask == null) {
         Log.e(TAG, "移除任务失败");
         return false;
       }
-      if (oldTask.isHighestPriorityTask()) {
-        return false;
-      }
       oldTask.stop();
       String key = CommonUtil.keyToHashKey(oldTask.getKey());
       mExecuteMap.remove(key);
@@ -142,7 +134,7 @@ public class NormalExecutePool implements IPool {
   @Override public TASK pollTask() {
     synchronized (AriaManager.LOCK) {
       try {
-        TASK task = null;
+        TASK task;
         task = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
         if (task != null) {
           String url = task.getKey();
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/DownloadExecutePool.java b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/DownloadExecutePool.java
new file mode 100644
index 00000000..0e8e53b0
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/DownloadExecutePool.java
@@ -0,0 +1,82 @@
+/*
+ * 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.queue.pool;
+
+import android.util.Log;
+import com.arialyy.aria.core.AriaManager;
+import com.arialyy.aria.core.download.DownloadTask;
+import com.arialyy.aria.util.CommonUtil;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Created by AriaL on 2017/6/29.
+ * 单个下载任务的执行池
+ */
+public class DownloadExecutePool extends BaseExecutePool {
+  private final String TAG = "DownloadExecutePool";
+
+  public DownloadExecutePool(boolean isDownload) {
+    super(isDownload);
+  }
+
+  @Override public boolean putTask(DownloadTask task) {
+    synchronized (AriaManager.LOCK) {
+      if (task == null) {
+        Log.e(TAG, "任务不能为空!!");
+        return false;
+      }
+      String url = task.getKey();
+      if (mExecuteQueue.contains(task)) {
+        Log.e(TAG, "队列中已经包含了该任务,任务key【" + url + "】");
+        return false;
+      } else {
+        if (mExecuteQueue.size() >= mSize) {
+          Set keys = mExecuteMap.keySet();
+          for (String key : keys) {
+            if (mExecuteMap.get(key).isHighestPriorityTask()) return false;
+          }
+          if (pollFirstTask()) {
+            return putNewTask(task);
+          }
+        } else {
+          return putNewTask(task);
+        }
+      }
+    }
+    return false;
+  }
+
+  @Override boolean pollFirstTask() {
+    try {
+      DownloadTask oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
+      if (oldTask == null) {
+        Log.e(TAG, "移除任务失败");
+        return false;
+      }
+      if (oldTask.isHighestPriorityTask()) {
+        return false;
+      }
+      oldTask.stop();
+      String key = CommonUtil.keyToHashKey(oldTask.getKey());
+      mExecuteMap.remove(key);
+    } catch (InterruptedException e) {
+      e.printStackTrace();
+      return false;
+    }
+    return true;
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupCachePool.java b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupCachePool.java
deleted file mode 100644
index 3e256198..00000000
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupCachePool.java
+++ /dev/null
@@ -1,23 +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.queue.pool;
-
-/**
- * Created by AriaL on 2017/6/29.
- * 任务组缓冲池
- */
-public class GroupCachePool {
-}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupExecutePool.java b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupExecutePool.java
deleted file mode 100644
index 188b84d4..00000000
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/GroupExecutePool.java
+++ /dev/null
@@ -1,23 +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.queue.pool;
-
-/**
- * Created by AriaL on 2017/6/29.
- */
-
-public class GroupExecutePool {
-}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/IPool.java b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/IPool.java
index 970c22b9..7e143b9b 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/IPool.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/IPool.java
@@ -22,18 +22,18 @@ import com.arialyy.aria.core.inf.ITask;
  * Created by lyy on 2016/8/14.
  * 任务池
  */
-public interface IPool {
+interface IPool {
   /**
    * 将下载任务添加到任务池中
    */
-  public boolean putTask(T task);
+  boolean putTask(T task);
 
   /**
    * 按照队列原则取出下载任务
    *
    * @return 返回null或者下载任务
    */
-  public T pollTask();
+  T pollTask();
 
   /**
    * 通过下载链接获取下载任务,当任务不为空时,队列将删除该下载任务
@@ -41,7 +41,7 @@ public interface IPool {
    * @param downloadUrl 下载链接
    * @return 返回null或者下载任务
    */
-  public T getTask(String downloadUrl);
+  T getTask(String downloadUrl);
 
   /**
    * 删除任务池中的下载任务
@@ -49,7 +49,7 @@ public interface IPool {
    * @param task 下载任务
    * @return true:移除成功
    */
-  public boolean removeTask(T task);
+  boolean removeTask(T task);
 
   /**
    * 通过key除下载任务
@@ -57,12 +57,12 @@ public interface IPool {
    * @param key 下载链接
    * @return true:移除成功
    */
-  public boolean removeTask(String key);
+  boolean removeTask(String key);
 
   /**
    * 池子大小
    *
    * @return 返回缓存池或者执行池大小
    */
-  public int size();
+  int size();
 }
\ No newline at end of file
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 8e097f48..255662ab 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
@@ -20,8 +20,8 @@ import android.os.Message;
 import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.download.DownloadTask;
-import com.arialyy.aria.core.inf.AbsNormalEntity;
-import com.arialyy.aria.core.inf.AbsNormalTask;
+import com.arialyy.aria.core.inf.AbsEntity;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.queue.ITaskQueue;
@@ -34,19 +34,19 @@ import java.util.concurrent.ConcurrentHashMap;
 /**
  * Created by lyy on 2017/6/4.
  */
-public abstract class AbsSchedulers, QUEUE extends ITaskQueue>
+abstract class AbsSchedulers, QUEUE extends ITaskQueue>
     implements ISchedulers {
-  private static final String TAG = "AbsSchedulers";
+  private final String TAG = "AbsSchedulers";
 
   /**
    * 下载的动态生成的代理类后缀
    */
-  String DOWNLOAD_PROXY_CLASS_SUFFIX = "$$DownloadListenerProxy";
+  private String DOWNLOAD_PROXY_CLASS_SUFFIX = "$$DownloadListenerProxy";
 
   /**
    * 上传的动态生成的代理类后缀
    */
-  String UPLOAD_PROXY_CLASS_SUFFIX = "$$UploadListenerProxy";
+  private String UPLOAD_PROXY_CLASS_SUFFIX = "$$UploadListenerProxy";
 
   protected QUEUE mQueue;
   protected boolean isDownload = true;
diff --git a/Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadGroupSchedulers.java b/Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadGroupSchedulers.java
new file mode 100644
index 00000000..d7d98fef
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadGroupSchedulers.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.scheduler;
+
+import com.arialyy.aria.core.AriaManager;
+import com.arialyy.aria.core.download.DownloadGroupEntity;
+import com.arialyy.aria.core.download.DownloadGroupTask;
+import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
+import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
+
+/**
+ * Created by AriaL on 2017/7/2.
+ */
+public class DownloadGroupSchedulers extends
+    AbsSchedulers {
+  private final String TAG = "DownloadGroupSchedulers";
+  private static volatile DownloadGroupSchedulers INSTANCE = null;
+
+  private DownloadGroupSchedulers() {
+    mQueue = DownloadGroupTaskQueue.getInstance();
+    isDownload = true;
+  }
+
+  public static DownloadGroupSchedulers getInstance() {
+    if (INSTANCE == null) {
+      synchronized (AriaManager.LOCK) {
+        INSTANCE = new DownloadGroupSchedulers();
+      }
+    }
+    return INSTANCE;
+  }
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadSchedulers.java b/Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadSchedulers.java
index f6137abf..46e80fc0 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadSchedulers.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadSchedulers.java
@@ -29,7 +29,7 @@ import com.arialyy.aria.core.download.DownloadTask;
 public class DownloadSchedulers
     extends AbsSchedulers {
 
-  private static final String TAG = "DownloadSchedulers";
+  private final String TAG = "DownloadSchedulers";
   private static volatile DownloadSchedulers INSTANCE = null;
 
   private DownloadSchedulers() {
diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java
index 88a87caa..008869ef 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java
@@ -51,7 +51,7 @@ final class UploadUtil implements Runnable {
   UploadUtil(UploadTaskEntity taskEntity, IUploadListener listener) {
     mTaskEntity = taskEntity;
     CheckUtil.checkTaskEntity(taskEntity);
-    mUploadEntity = taskEntity.uploadEntity;
+    mUploadEntity = taskEntity.getEntity();
     if (listener == null) {
       throw new IllegalArgumentException("上传监听不能为空");
     }
@@ -162,11 +162,11 @@ final class UploadUtil implements Runnable {
     writer.append("Content-Disposition: form-data; name=\"")
         .append(attachment)
         .append("\"; filename=\"")
-        .append(mTaskEntity.uploadEntity.getFileName())
+        .append(mTaskEntity.getEntity().getFileName())
         .append("\"")
         .append(LINE_END);
     writer.append("Content-Type: ")
-        .append(URLConnection.guessContentTypeFromName(mTaskEntity.uploadEntity.getFileName()))
+        .append(URLConnection.guessContentTypeFromName(mTaskEntity.getEntity().getFileName()))
         .append(LINE_END);
     writer.append("Content-Transfer-Encoding: binary").append(LINE_END);
     writer.append(LINE_END);
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 c083c46e..41841d5b 100644
--- a/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java
@@ -88,9 +88,9 @@ public class CheckUtil {
    */
   public static void checkTaskEntity(AbsTaskEntity entity) {
     if (entity instanceof DownloadTaskEntity) {
-      checkDownloadTaskEntity(((DownloadTaskEntity) entity).downloadEntity);
+      checkDownloadTaskEntity(((DownloadTaskEntity) entity).getEntity());
     } else if (entity instanceof UploadTaskEntity) {
-      checkUploadTaskEntity(((UploadTaskEntity) entity).uploadEntity);
+      checkUploadTaskEntity(((UploadTaskEntity) entity).getEntity());
     }
   }
 
@@ -103,7 +103,7 @@ public class CheckUtil {
   public static boolean checkCmdEntity(AbsTaskEntity entity, boolean checkType) {
     boolean b = false;
     if (entity instanceof DownloadTaskEntity) {
-      DownloadEntity entity1 = ((DownloadTaskEntity) entity).downloadEntity;
+      DownloadEntity entity1 = ((DownloadTaskEntity) entity).getEntity();
       if (entity1 == null) {
         Log.e(TAG, "下载实体不能为空");
       } else if (checkType && TextUtils.isEmpty(entity1.getDownloadUrl())) {
@@ -114,7 +114,7 @@ public class CheckUtil {
         b = true;
       }
     } else if (entity instanceof UploadTaskEntity) {
-      UploadEntity entity1 = ((UploadTaskEntity) entity).uploadEntity;
+      UploadEntity entity1 = ((UploadTaskEntity) entity).getEntity();
       if (entity1 == null) {
         Log.e(TAG, "上传实体不能为空");
       } else if (TextUtils.isEmpty(entity1.getFilePath())) {
diff --git a/aria/src/main/java/com/arialyy/aria/core/Configuration.java b/aria/src/main/java/com/arialyy/aria/core/Configuration.java
index d23974f1..8adcb24a 100644
--- a/aria/src/main/java/com/arialyy/aria/core/Configuration.java
+++ b/aria/src/main/java/com/arialyy/aria/core/Configuration.java
@@ -40,7 +40,7 @@ class Configuration {
     /**
      * 旧任务数
      */
-    public static int oldMaxTaskNum = 2;
+    public int oldMaxTaskNum = 2;
 
     /**
      * 是否发送任务广播,true,发送
@@ -176,7 +176,8 @@ class Configuration {
         try {
           for (Field field : fields) {
             int m = field.getModifiers();
-            if (Modifier.isFinal(m) || Modifier.isStatic(m)) {
+            if (field.getName().equals("oldMaxTaskNum") || Modifier.isFinal(m) || Modifier.isStatic(
+                m)) {
               continue;
             }
             field.setAccessible(true);
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 84ea56f1..5200e761 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
@@ -23,8 +23,7 @@ import java.util.Map;
  * Created by lyy on 2017/2/9.
  * 上传任务实体
  */
-public class UploadTaskEntity extends AbsTaskEntity {
-  public UploadEntity uploadEntity;
+public class UploadTaskEntity extends AbsTaskEntity {
   public String uploadUrl; //上传路径
   public String attachment;  //文件上传需要的key
   public String contentType = "multipart/form-data"; //上传的文件类型
@@ -36,11 +35,8 @@ public class UploadTaskEntity extends AbsTaskEntity {
    */
   public Map formFields = new HashMap<>();
 
-  public UploadTaskEntity(UploadEntity downloadEntity) {
-    this.uploadEntity = downloadEntity;
+  public UploadTaskEntity(UploadEntity entity) {
+    this.entity = entity;
   }
 
-  @Override public UploadEntity getEntity() {
-    return uploadEntity;
-  }
 }

From aff73f92f946d556fff1c5f944ec2518b0b461c5 Mon Sep 17 00:00:00 2001
From: AriaLyy <511455842@qq.com>
Date: Mon, 3 Jul 2017 16:33:19 +0800
Subject: [PATCH 16/34] =?UTF-8?q?target=20=E7=BC=96=E5=86=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../main/java/com/arialyy/aria/core/Aria.java |  56 ------
 .../com/arialyy/aria/core/ConfigHelper.java   |  13 --
 .../core/command/group/GroupStartCmd.java     |  37 ++++
 .../aria/core/command/normal/AddCmd.java      |   3 +-
 .../aria/core/command/normal/CancelCmd.java   |   5 +-
 .../core/command/normal/ResumeAllCmd.java     |  10 +-
 .../aria/core/command/normal/StartCmd.java    |   6 +-
 .../aria/core/command/normal/StopCmd.java     |   6 +-
 .../core/download/DownloadGroupTarget.java    |  44 ++++-
 .../aria/core/download/DownloadReceiver.java  |  37 ++--
 .../aria/core/download/DownloadTask.java      |  78 ++------
 .../arialyy/aria/core/inf/AbsGroupEntity.java |  15 ++
 .../arialyy/aria/core/inf/AbsGroupTarget.java |  58 +-----
 .../aria/core/inf/AbsNormalTarget.java        | 173 +----------------
 .../com/arialyy/aria/core/inf/AbsTarget.java  | 181 ++++++++++++++++++
 .../java/com/arialyy/aria/util/CheckUtil.java |  19 ++
 .../com/arialyy/aria/util/CommonUtil.java     |  22 +++
 app/src/main/assets/aria_config.xml           |   5 -
 .../com/arialyy/aria/core/Configuration.java  |  14 --
 .../arialyy/aria/core/upload/UploadTask.java  |  78 +++-----
 20 files changed, 408 insertions(+), 452 deletions(-)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java

diff --git a/Aria/src/main/java/com/arialyy/aria/core/Aria.java b/Aria/src/main/java/com/arialyy/aria/core/Aria.java
index 27e19d2e..5dc70cfe 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/Aria.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/Aria.java
@@ -59,62 +59,6 @@ import com.arialyy.aria.core.upload.UploadTask;
  * 
  */
 @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) public class Aria {
-  /**
-   * 不支持断点
-   */
-  public static final String ACTION_SUPPORT_BREAK_POINT = "ACTION_SUPPORT_BREAK_POINT";
-  /**
-   * 预处理完成
-   */
-  public static final String ACTION_PRE = "ACTION_PRE";
-  /**
-   * 下载开始前事件
-   */
-  public static final String ACTION_POST_PRE = "ACTION_POST_PRE";
-  /**
-   * 开始下载事件
-   */
-  public static final String ACTION_START = "ACTION_START";
-  /**
-   * 恢复下载事件
-   */
-  public static final String ACTION_RESUME = "ACTION_RESUME";
-  /**
-   * 正在下载事件
-   */
-  public static final String ACTION_RUNNING = "ACTION_RUNNING";
-  /**
-   * 停止下载事件
-   */
-  public static final String ACTION_STOP = "ACTION_STOP";
-  /**
-   * 取消下载事件
-   */
-  public static final String ACTION_CANCEL = "ACTION_CANCEL";
-  /**
-   * 下载完成事件
-   */
-  public static final String ACTION_COMPLETE = "ACTION_COMPLETE";
-  /**
-   * 下载失败事件
-   */
-  public static final String ACTION_FAIL = "ACTION_FAIL";
-  /**
-   * 下载实体
-   */
-  public static final String DOWNLOAD_ENTITY = "DOWNLOAD_ENTITY";
-  /**
-   * 上传实体
-   */
-  public static final String UPLOAD_ENTITY = "UPLOAD_ENTITY";
-  /**
-   * 位置
-   */
-  public static final String CURRENT_LOCATION = "CURRENT_LOCATION";
-  /**
-   * 速度
-   */
-  public static final String CURRENT_SPEED = "CURRENT_SPEED";
 
   private Aria() {
   }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java b/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java
index 260d1d29..d0df8509 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java
@@ -54,9 +54,6 @@ class ConfigHelper extends DefaultHandler {
         case "threadNum":
           loadThreadNum(value);
           break;
-        case "openBroadcast":
-          loadBroadcast(value);
-          break;
         case "maxTaskNum":
           loadMaxQueue(value);
           break;
@@ -224,16 +221,6 @@ class ConfigHelper extends DefaultHandler {
     }
   }
 
-  private void loadBroadcast(String value) {
-    boolean open = Boolean.parseBoolean(value);
-    if (isDownloadConfig) {
-      mDownloadConfig.isOpenBreadCast = open;
-    }
-    if (isUploadConfig) {
-      mUploadConfig.isOpenBreadCast = open;
-    }
-  }
-
   private void loadThreadNum(String value) {
     int num = 3;
     if (!TextUtils.isEmpty(value)) {
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java
index 7fdb8465..3bd7bea8 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java
@@ -15,7 +15,12 @@
  */
 package com.arialyy.aria.core.command.group;
 
+import android.text.TextUtils;
+import com.arialyy.aria.core.AriaManager;
+import com.arialyy.aria.core.QueueMod;
+import com.arialyy.aria.core.inf.AbsGroupTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
+import com.arialyy.aria.core.inf.IEntity;
 
 /**
  * Created by AriaL on 2017/6/29.
@@ -30,6 +35,38 @@ class GroupStartCmd extends AbsGroupCmd {
   }
 
   @Override public void executeCmd() {
+    String mod;
+    int maxTaskNum;
+    AriaManager manager = AriaManager.getInstance(AriaManager.APP);
+    if (isDownloadCmd) {
+      mod = manager.getDownloadConfig().getQueueMod();
+      maxTaskNum = manager.getDownloadConfig().getMaxTaskNum();
+    } else {
+      mod = manager.getUploadConfig().getQueueMod();
+      maxTaskNum = manager.getUploadConfig().getMaxTaskNum();
+    }
 
+    AbsGroupTask task = (AbsGroupTask) mQueue.getTask(mTaskEntity.getEntity());
+    if (task == null) {
+      task = (AbsGroupTask) mQueue.createTask(mTargetName, mTaskEntity);
+      if (!TextUtils.isEmpty(mTargetName)) {
+        task.setTargetName(mTargetName);
+      }
+      // 任务不存在时,根据配置不同,对任务执行操作
+      if (mod.equals(QueueMod.NOW.getTag())) {
+        mQueue.startTask(task);
+      } else if (mod.equals(QueueMod.WAIT.getTag())) {
+        if (mQueue.getExePoolSize() < maxTaskNum) {
+          mQueue.startTask(task);
+        }
+      }
+    } else {
+      // 任务不存在时,根据配置不同,对任务执行操作
+      if (!task.isRunning()
+          && mod.equals(QueueMod.WAIT.getTag())
+          && task.getState() == IEntity.STATE_WAIT) {
+        mQueue.startTask(task);
+      }
+    }
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
index 6f7f3e9f..8ed5de0d 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
@@ -18,6 +18,7 @@ package com.arialyy.aria.core.command.normal;
 
 import android.util.Log;
 import com.arialyy.aria.core.inf.AbsNormalTask;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
@@ -33,7 +34,7 @@ class AddCmd extends AbsNormalCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    AbsNormalTask task = (AbsNormalTask) mQueue.getTask(mTaskEntity.getEntity());
+    AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
       mTaskEntity.getEntity().setState(IEntity.STATE_WAIT);
       mQueue.createTask(mTargetName, mTaskEntity);
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
index 4e13b329..ff859066 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
@@ -18,6 +18,7 @@ package com.arialyy.aria.core.command.normal;
 
 import android.text.TextUtils;
 import com.arialyy.aria.core.inf.AbsNormalTask;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
@@ -31,9 +32,9 @@ class CancelCmd extends AbsNormalCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    AbsNormalTask task = (AbsNormalTask) mQueue.getTask(mTaskEntity.getEntity());
+    AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
-      task = (AbsNormalTask) mQueue.createTask(mTargetName, mTaskEntity);
+      task = mQueue.createTask(mTargetName, mTaskEntity);
     }
     if (task != null) {
       if (!TextUtils.isEmpty(mTargetName)) {
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
index cd3336e7..58b26bdc 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
@@ -3,7 +3,7 @@ package com.arialyy.aria.core.command.normal;
 import android.util.Log;
 import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
-import com.arialyy.aria.core.inf.AbsNormalTask;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.orm.DbEntity;
@@ -29,7 +29,7 @@ final class ResumeAllCmd extends AbsNormalCmd {
     for (DownloadEntity entity : allEntity) {
       int exeNum = mQueue.getExePoolSize();
       if (exeNum == 0 || exeNum < mQueue.getMaxTaskNum()) {
-        AbsNormalTask task = createTask(entity);
+        AbsTask task = createTask(entity);
         mQueue.startTask(task);
       } else {
         entity.setState(IEntity.STATE_WAIT);
@@ -38,11 +38,11 @@ final class ResumeAllCmd extends AbsNormalCmd {
     }
   }
 
-  private AbsNormalTask createTask(DownloadEntity entity) {
-    AbsNormalTask task = (AbsNormalTask) mQueue.getTask(entity);
+  private AbsTask createTask(DownloadEntity entity) {
+    AbsTask task = mQueue.getTask(entity);
     if (task == null) {
       DownloadTaskEntity taskEntity = new DownloadTaskEntity(entity);
-      task = (AbsNormalTask) mQueue.createTask(mTargetName, taskEntity);
+      task = mQueue.createTask(mTargetName, taskEntity);
     } else {
       Log.w(TAG, "添加命令执行失败,【该任务已经存在】");
     }
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 11c713af..2b042a27 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
@@ -19,7 +19,7 @@ package com.arialyy.aria.core.command.normal;
 import android.text.TextUtils;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.QueueMod;
-import com.arialyy.aria.core.inf.AbsNormalTask;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
@@ -47,9 +47,9 @@ class StartCmd extends AbsNormalCmd {
       maxTaskNum = manager.getUploadConfig().getMaxTaskNum();
     }
 
-    AbsNormalTask task = (AbsNormalTask) mQueue.getTask(mTaskEntity.getEntity());
+    AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
-      task = (AbsNormalTask) mQueue.createTask(mTargetName, mTaskEntity);
+      task = mQueue.createTask(mTargetName, mTaskEntity);
       if (!TextUtils.isEmpty(mTargetName)) {
         task.setTargetName(mTargetName);
       }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
index cd926b7c..9d0b0811 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
@@ -18,7 +18,7 @@ package com.arialyy.aria.core.command.normal;
 
 import android.text.TextUtils;
 import android.util.Log;
-import com.arialyy.aria.core.inf.AbsNormalTask;
+import com.arialyy.aria.core.inf.AbsTask;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
@@ -34,10 +34,10 @@ class StopCmd extends AbsNormalCmd {
 
   @Override public void executeCmd() {
     if (!canExeCmd) return;
-    AbsNormalTask task = (AbsNormalTask) mQueue.getTask(mTaskEntity.getEntity());
+    AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
     if (task == null) {
       if (mTaskEntity.getEntity().getState() == IEntity.STATE_RUNNING) {
-        task = (AbsNormalTask) mQueue.createTask(mTargetName, mTaskEntity);
+        task = mQueue.createTask(mTargetName, mTaskEntity);
         mQueue.stopTask(task);
       } else {
         Log.w(TAG, "停止命令执行失败,【调度器中没有该任务】");
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 e556c424..f76ee2f2 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
@@ -16,23 +16,57 @@
 package com.arialyy.aria.core.download;
 
 import com.arialyy.aria.core.inf.AbsGroupTarget;
-import com.arialyy.aria.core.inf.ITarget;
+import com.arialyy.aria.core.inf.IEntity;
+import com.arialyy.aria.util.CheckUtil;
+import java.io.File;
 import java.util.List;
 
 /**
  * Created by AriaL on 2017/6/29.
  */
-public class DownloadGroupTarget extends AbsGroupTarget {
+public class DownloadGroupTarget
+    extends AbsGroupTarget {
+  private List mUrls;
+
+  DownloadGroupTarget(DownloadGroupEntity entity, String targetName, List urls) {
+    this.mEntity = entity;
+    this.mTargetName = targetName;
+    this.mUrls = urls;
+    mTaskEntity = new DownloadGroupTaskEntity(entity);
+  }
 
   /**
    * 设置保存路径组
    */
   public DownloadGroupTarget setDownloadPaths(List paths) {
-
+    CheckUtil.checkDownloadPaths(paths);
+    if (mUrls.size() != paths.size()) {
+      throw new IllegalArgumentException("下载链接数必须要和保存路径的数量一致");
+    }
+    for (int i = 0, len = mUrls.size(); i < len; i++) {
+      mTaskEntity.getEntity().getChild().add(createDownloadEntity(mUrls.get(i), paths.get(i)));
+    }
     return this;
   }
 
-  @Override public int getPercent() {
-    return 0;
+  /**
+   * 创建子任务下载实体
+   *
+   * @param url 下载地址
+   * @param path 保存路径
+   */
+  private DownloadEntity createDownloadEntity(String url, String path) {
+    DownloadEntity entity = DownloadEntity.findData(DownloadEntity.class, "downloadUrl=?", url);
+    if (entity == null) {
+      entity = new DownloadEntity();
+    }
+    File file = new File(path);
+    if (!file.exists()) {
+      entity.setState(IEntity.STATE_WAIT);
+    }
+    entity.setDownloadPath(path);
+    entity.setDownloadUrl(url);
+    entity.setFileName(file.getName());
+    return entity;
   }
 }
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 045902dd..5b6589c6 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
@@ -23,6 +23,7 @@ import com.arialyy.aria.core.inf.IReceiver;
 import com.arialyy.aria.core.command.normal.NormalCmdFactory;
 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;
 import java.io.File;
@@ -34,7 +35,7 @@ import java.util.Set;
  * 下载功能接收器
  */
 public class DownloadReceiver extends AbsReceiver {
-  private static final String TAG = "DownloadReceiver";
+  private final String TAG = "DownloadReceiver";
   public ISchedulerListener listener;
 
   /**
@@ -73,15 +74,17 @@ public class DownloadReceiver extends AbsReceiver {
   }
 
   /**
-   * 添加调度器回调
-   *
-   * @see #register()
+   * 加载下载地址,如果任务组的中的下载地址改变了,则任务从新的一个任务组
    */
-  @Deprecated public DownloadReceiver addSchedulerListener(
-      ISchedulerListener listener) {
-    this.listener = listener;
-    DownloadSchedulers.getInstance().addSchedulerListener(targetName, listener);
-    return this;
+  public DownloadGroupTarget load(List urls) {
+    CheckUtil.checkDownloadUrls(urls);
+    DownloadGroupEntity entity =
+        DbEntity.findData(DownloadGroupEntity.class, "urlHash=?", CommonUtil.getMd5Code(urls));
+
+    if (entity == null) {
+      entity = new DownloadGroupEntity();
+    }
+    return new DownloadGroupTarget(entity, targetName, urls);
   }
 
   /**
@@ -99,6 +102,18 @@ public class DownloadReceiver extends AbsReceiver {
     DownloadSchedulers.getInstance().unRegister(obj);
   }
 
+  /**
+   * 添加调度器回调
+   *
+   * @see #register()
+   */
+  @Deprecated public DownloadReceiver addSchedulerListener(
+      ISchedulerListener listener) {
+    this.listener = listener;
+    DownloadSchedulers.getInstance().addSchedulerListener(targetName, listener);
+    return this;
+  }
+
   /**
    * 移除回调
    *
@@ -165,8 +180,8 @@ public class DownloadReceiver extends AbsReceiver {
   @Override public void removeAllTask(boolean removeFile) {
     final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
     AriaManager.getInstance(AriaManager.APP)
-        .setCmd(
-            CommonUtil.createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_CANCEL_ALL))
+        .setCmd(CommonUtil.createCmd(targetName, new DownloadTaskEntity(),
+            NormalCmdFactory.TASK_CANCEL_ALL))
         .exe();
 
     Set keys = ariaManager.getReceiver().keySet();
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 e70f6eb4..2d51273c 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
@@ -20,7 +20,6 @@ import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
 import android.util.Log;
-import com.arialyy.aria.core.Aria;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.download.downloader.DownloadListener;
 import com.arialyy.aria.core.download.downloader.DownloadUtil;
@@ -144,11 +143,6 @@ public class DownloadTask extends AbsNormalTask {
       if (mOutHandler != null) {
         mOutHandler.obtainMessage(DownloadSchedulers.STOP, this).sendToTarget();
       }
-      // 发送停止下载的广播
-      Intent intent = CommonUtil.createIntent(mContext.getPackageName(), Aria.ACTION_STOP);
-      intent.putExtra(Aria.CURRENT_LOCATION, mEntity.getCurrentProgress());
-      intent.putExtra(Aria.DOWNLOAD_ENTITY, mEntity);
-      mContext.sendBroadcast(intent);
     }
   }
 
@@ -161,10 +155,6 @@ public class DownloadTask extends AbsNormalTask {
         if (mOutHandler != null) {
           mOutHandler.obtainMessage(DownloadSchedulers.CANCEL, this).sendToTarget();
         }
-        //发送取消下载的广播
-        Intent intent = CommonUtil.createIntent(mContext.getPackageName(), Aria.ACTION_CANCEL);
-        intent.putExtra(Aria.DOWNLOAD_ENTITY, mEntity);
-        mContext.sendBroadcast(intent);
       }
       mUtil.cancelDownload();
     }
@@ -206,14 +196,12 @@ public class DownloadTask extends AbsNormalTask {
     WeakReference outHandler;
     WeakReference wTask;
     Context context;
-    Intent sendIntent;
     long lastLen = 0;   //上一次发送长度
     long lastTime = 0;
     long INTERVAL_TIME = 1000;   //1m更新周期
     boolean isFirst = true;
-    DownloadEntity downloadEntity;
+    DownloadEntity entity;
     DownloadTask task;
-    boolean isOpenBroadCast = false;
     boolean isConvertSpeed = false;
 
     DListener(Context context, DownloadTask task, Handler outHandler) {
@@ -221,44 +209,36 @@ public class DownloadTask extends AbsNormalTask {
       this.outHandler = new WeakReference<>(outHandler);
       this.wTask = new WeakReference<>(task);
       this.task = wTask.get();
-      this.downloadEntity = this.task.getDownloadEntity();
-      sendIntent = CommonUtil.createIntent(context.getPackageName(), Aria.ACTION_RUNNING);
-      sendIntent.putExtra(Aria.DOWNLOAD_ENTITY, downloadEntity);
+      this.entity = this.task.getDownloadEntity();
       final AriaManager manager = AriaManager.getInstance(context);
-      isOpenBroadCast = manager.getDownloadConfig().isOpenBreadCast();
       isConvertSpeed = manager.getDownloadConfig().isConvertSpeed();
     }
 
     @Override public void supportBreakpoint(boolean support) {
       if (!support) {
         sendInState2Target(ISchedulers.SUPPORT_BREAK_POINT);
-        sendIntent(Aria.ACTION_SUPPORT_BREAK_POINT, -1);
       }
     }
 
     @Override public void onPre() {
-      downloadEntity.setState(IEntity.STATE_PRE);
       sendInState2Target(ISchedulers.PRE);
-      sendIntent(Aria.ACTION_PRE, -1);
+      saveData(IEntity.STATE_PRE, -1);
     }
 
     @Override public void onPostPre(long fileSize) {
-      downloadEntity.setFileSize(fileSize);
-      downloadEntity.setState(IEntity.STATE_POST_PRE);
+      entity.setFileSize(fileSize);
       sendInState2Target(ISchedulers.POST_PRE);
-      sendIntent(Aria.ACTION_POST_PRE, -1);
+      saveData(IEntity.STATE_POST_PRE, -1);
     }
 
     @Override public void onResume(long resumeLocation) {
-      downloadEntity.setState(IEntity.STATE_RUNNING);
       sendInState2Target(ISchedulers.RESUME);
-      sendIntent(Aria.ACTION_RESUME, resumeLocation);
+      saveData(IEntity.STATE_RUNNING, resumeLocation);
     }
 
     @Override public void onStart(long startLocation) {
-      downloadEntity.setState(IEntity.STATE_RUNNING);
       sendInState2Target(ISchedulers.START);
-      sendIntent(Aria.ACTION_START, startLocation);
+      saveData(IEntity.STATE_RUNNING, startLocation);
     }
 
     @Override public void onProgress(long currentLocation) {
@@ -270,53 +250,43 @@ public class DownloadTask extends AbsNormalTask {
           isFirst = false;
         }
         handleSpeed(speed);
-        downloadEntity.setCurrentProgress(currentLocation);
+        entity.setCurrentProgress(currentLocation);
         lastLen = currentLocation;
         sendInState2Target(ISchedulers.RUNNING);
-
-        if (!isOpenBroadCast) return;
-        sendIntent.putExtra(Aria.CURRENT_LOCATION, currentLocation);
-        sendIntent.putExtra(Aria.CURRENT_SPEED, speed);
-        context.sendBroadcast(sendIntent);
       }
     }
 
     @Override public void onStop(long stopLocation) {
-      downloadEntity.setState(task.isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP);
       handleSpeed(0);
       sendInState2Target(ISchedulers.STOP);
-      sendIntent(Aria.ACTION_STOP, stopLocation);
+      saveData(task.isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP, stopLocation);
     }
 
     @Override public void onCancel() {
-      downloadEntity.setState(IEntity.STATE_CANCEL);
       handleSpeed(0);
       sendInState2Target(ISchedulers.CANCEL);
-      sendIntent(Aria.ACTION_CANCEL, -1);
-      downloadEntity.deleteData();
+      saveData(IEntity.STATE_CANCEL, -1);
+      entity.deleteData();
     }
 
     @Override public void onComplete() {
-      downloadEntity.setState(IEntity.STATE_COMPLETE);
-      downloadEntity.setDownloadComplete(true);
       handleSpeed(0);
       sendInState2Target(ISchedulers.COMPLETE);
-      sendIntent(Aria.ACTION_COMPLETE, downloadEntity.getFileSize());
+      saveData(IEntity.STATE_COMPLETE, entity.getFileSize());
     }
 
     @Override public void onFail() {
-      downloadEntity.setFailNum(downloadEntity.getFailNum() + 1);
-      downloadEntity.setState(IEntity.STATE_FAIL);
+      entity.setFailNum(entity.getFailNum() + 1);
       handleSpeed(0);
       sendInState2Target(ISchedulers.FAIL);
-      sendIntent(Aria.ACTION_FAIL, -1);
+      saveData(IEntity.STATE_FAIL, -1);
     }
 
     private void handleSpeed(long speed) {
       if (isConvertSpeed) {
-        downloadEntity.setConvertSpeed(CommonUtil.formatFileSize(speed) + "/s");
+        entity.setConvertSpeed(CommonUtil.formatFileSize(speed) + "/s");
       } else {
-        downloadEntity.setSpeed(speed);
+        entity.setSpeed(speed);
       }
     }
 
@@ -331,17 +301,11 @@ public class DownloadTask extends AbsNormalTask {
       }
     }
 
-    private void sendIntent(String action, long location) {
-      downloadEntity.setDownloadComplete(action.equals(Aria.ACTION_COMPLETE));
-      downloadEntity.setCurrentProgress(location);
-      downloadEntity.update();
-      if (!isOpenBroadCast) return;
-      Intent intent = CommonUtil.createIntent(context.getPackageName(), action);
-      intent.putExtra(Aria.DOWNLOAD_ENTITY, downloadEntity);
-      if (location != -1) {
-        intent.putExtra(Aria.CURRENT_LOCATION, location);
-      }
-      context.sendBroadcast(intent);
+    private void saveData(int state, long location) {
+      entity.setState(state);
+      entity.setDownloadComplete(state == IEntity.STATE_COMPLETE);
+      entity.setCurrentProgress(location);
+      entity.update();
     }
   }
 }
\ No newline at end of file
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 9432a0de..b324fd57 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
@@ -29,6 +29,19 @@ public abstract class AbsGroupEntity extends AbsEntity implements Parcelable {
    */
   private String groupName = "";
 
+  /**
+   * 任务地址相加的urlmd5
+   */
+  private String urlmd5 = "";
+
+  public String getUrlmd5() {
+    return urlmd5;
+  }
+
+  public void setUrlmd5(String urlmd5) {
+    this.urlmd5 = urlmd5;
+  }
+
   public String getGroupName() {
     return groupName;
   }
@@ -47,10 +60,12 @@ public abstract class AbsGroupEntity extends AbsEntity implements Parcelable {
   @Override public void writeToParcel(Parcel dest, int flags) {
     super.writeToParcel(dest, flags);
     dest.writeString(this.groupName);
+    dest.writeString(this.urlmd5);
   }
 
   protected AbsGroupEntity(Parcel in) {
     super(in);
     this.groupName = in.readString();
+    this.urlmd5 = in.readString();
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java
index 34834da5..c514577b 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java
@@ -15,65 +15,11 @@
  */
 package com.arialyy.aria.core.inf;
 
-import android.support.annotation.NonNull;
-import com.arialyy.aria.core.RequestEnum;
-import java.util.Map;
-import java.util.Set;
-
 /**
  * Created by AriaL on 2017/6/29.
  * 任务组超类
  */
-public abstract class AbsGroupTarget
-    implements ITarget {
-
-  protected TASK_ENTITY mTaskEntity;
-
-  @Override public void resume() {
-
-  }
-
-  @Override public void start() {
-
-  }
-
-  @Override public void stop() {
-
-  }
-
-  @Override public void cancel() {
-
-  }
-
-  @Override public long getSize() {
-    return 0;
-  }
-
-  @Override public String getConvertSize() {
-    return null;
-  }
-
-  @Override public long getCurrentProgress() {
-    return 0;
-  }
-
-  @Override public TARGET addHeader(@NonNull String key, @NonNull String header) {
-    mTaskEntity.headers.put(key, header);
-    return (TARGET) this;
-  }
-
-  @Override public TARGET addHeaders(Map headers) {
-    if (headers != null && headers.size() > 0) {
-      Set keys = headers.keySet();
-      for (String key : keys) {
-        mTaskEntity.headers.put(key, headers.get(key));
-      }
-    }
-    return (TARGET) this;
-  }
+public abstract class AbsGroupTarget
+    extends AbsTarget {
 
-  @Override public TARGET setRequestMode(RequestEnum requestEnum) {
-    mTaskEntity.requestEnum = requestEnum;
-    return (TARGET) this;
-  }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java
index c8fc1cc0..b8351713 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java
@@ -15,53 +15,19 @@
  */
 package com.arialyy.aria.core.inf;
 
-import android.support.annotation.NonNull;
 import android.text.TextUtils;
 import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.RequestEnum;
 import com.arialyy.aria.core.command.normal.NormalCmdFactory;
-import com.arialyy.aria.core.download.DownloadEntity;
-import com.arialyy.aria.core.upload.UploadEntity;
 import com.arialyy.aria.util.CommonUtil;
-import java.util.Map;
-import java.util.Set;
 
 /**
  * Created by lyy on 2017/2/28.
  */
-public abstract class AbsNormalTarget
-    implements ITarget {
+public abstract class AbsNormalTarget
+    extends AbsTarget {
   protected ENTITY mEntity;
   protected TASK_ENTITY mTaskEntity;
-  protected String mTargetName;
-
-  /**
-   * 设置扩展字段,用来保存你的其它数据,如果你的数据比较多,你可以把你的数据转换为JSON字符串,然后再存到Aria中
-   *
-   * @param str 扩展数据
-   */
-  public AbsNormalTarget setExtendField(String str) {
-    mEntity.setStr(str);
-    return this;
-  }
-
-  /**
-   * 获取存放的扩展字段
-   * 设置扩展字段{@link #setExtendField(String)}
-   */
-  public String getExtendField() {
-    return mEntity.getStr();
-  }
-
-  /**
-   * 获取任务状态
-   *
-   * @return {@link IEntity}
-   */
-  public int getTaskState() {
-    return mEntity.getState();
-  }
 
   /**
    * 将任务设置为最高优先级任务,最高优先级任务有以下特点:
@@ -74,7 +40,8 @@ public abstract class AbsNormalTarget headers) {
-    if (headers != null && headers.size() > 0) {
-      Set keys = headers.keySet();
-      for (String key : keys) {
-        mTaskEntity.headers.put(key, headers.get(key));
-      }
-    }
-    return (TARGET) this;
-  }
-
-  /**
-   * 设置请求类型
-   *
-   * @param requestEnum {@link RequestEnum}
-   */
-  public TARGET setRequestMode(RequestEnum requestEnum) {
-    mTaskEntity.requestEnum = requestEnum;
-    return (TARGET) this;
-  }
-
   /**
    * 添加任务
    */
-
   public void add() {
     AriaManager.getInstance(AriaManager.APP)
         .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE))
         .exe();
   }
 
-  /**
-   * 开始下载
-   */
-  @Override public void start() {
-    AriaManager.getInstance(AriaManager.APP)
-        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
-        .exe();
-  }
-
-  /**
-   * 停止下载
-   *
-   * @see #stop()
-   */
-  @Deprecated public void pause() {
-    stop();
-  }
-
-  @Override public void stop() {
-    AriaManager.getInstance(AriaManager.APP)
-        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP))
-        .exe();
-  }
-
-  /**
-   * 恢复下载
-   */
-  @Override public void resume() {
-    AriaManager.getInstance(AriaManager.APP)
-        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
-        .exe();
-  }
-
-  /**
-   * 取消下载
-   */
-  @Override public void cancel() {
-    AriaManager.getInstance(AriaManager.APP)
-        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL))
-        .exe();
-  }
-
   /**
    * 重新下载
    */
-  void reStart() {
+  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
new file mode 100644
index 00000000..1d96daba
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
@@ -0,0 +1,181 @@
+/*
+ * 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 android.util.Log;
+import com.arialyy.aria.core.AriaManager;
+import com.arialyy.aria.core.RequestEnum;
+import com.arialyy.aria.core.command.normal.NormalCmdFactory;
+import com.arialyy.aria.util.CommonUtil;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Created by AriaL on 2017/7/3.
+ */
+public abstract class AbsTarget
+    implements ITarget {
+  protected ENTITY mEntity;
+  protected TASK_ENTITY mTaskEntity;
+  protected String mTargetName;
+
+  /**
+   * 获取任务进度,如果任务存在,则返回当前进度
+   *
+   * @return 该任务进度
+   */
+  public long getCurrentProgress() {
+    return mEntity == null ? -1 : mEntity.getCurrentProgress();
+  }
+
+  /**
+   * 获取任务文件大小
+   *
+   * @return 文件大小
+   */
+  @Override public long getSize() {
+    return mEntity == null ? 0 : mEntity.getFileSize();
+  }
+
+  /**
+   * 获取单位转换后的文件大小
+   *
+   * @return 文件大小{@code xxx mb}
+   */
+  @Override public String getConvertSize() {
+    return mEntity == null ? "0b" : CommonUtil.formatFileSize(mEntity.getFileSize());
+  }
+
+  /**
+   * 设置扩展字段,用来保存你的其它数据,如果你的数据比较多,你可以把你的数据转换为JSON字符串,然后再存到Aria中
+   *
+   * @param str 扩展数据
+   */
+  public TARGET setExtendField(String str) {
+    mEntity.setStr(str);
+    return (TARGET) this;
+  }
+
+  /**
+   * 获取存放的扩展字段
+   * 设置扩展字段{@link #setExtendField(String)}
+   */
+  public String getExtendField() {
+    return mEntity.getStr();
+  }
+
+  /**
+   * 获取任务状态
+   *
+   * @return {@link IEntity}
+   */
+  public int getTaskState() {
+    return mEntity.getState();
+  }
+
+  /**
+   * 获取任务进度百分比
+   *
+   * @return 返回任务进度
+   */
+  @Override public int getPercent() {
+    if (mEntity == null) {
+      Log.e("AbsTarget", "下载管理器中没有该任务");
+      return 0;
+    }
+    if (mEntity.getFileSize() != 0) {
+      return (int) (mEntity.getCurrentProgress() * 100 / mEntity.getFileSize());
+    }
+    return 0;
+  }
+
+  /**
+   * 给url请求添加头部
+   *
+   * @param key 头部key
+   * @param header 头部value
+   */
+  public TARGET addHeader(@NonNull String key, @NonNull String header) {
+    mTaskEntity.headers.put(key, header);
+    return (TARGET) this;
+  }
+
+  /**
+   * 给url请求添加头部
+   */
+  public TARGET addHeaders(Map headers) {
+    if (headers != null && headers.size() > 0) {
+      Set keys = headers.keySet();
+      for (String key : keys) {
+        mTaskEntity.headers.put(key, headers.get(key));
+      }
+    }
+    return (TARGET) this;
+  }
+
+  /**
+   * 设置请求类型
+   *
+   * @param requestEnum {@link RequestEnum}
+   */
+  public TARGET setRequestMode(RequestEnum requestEnum) {
+    mTaskEntity.requestEnum = requestEnum;
+    return (TARGET) this;
+  }
+
+  /**
+   * 开始下载
+   */
+  @Override public void start() {
+    AriaManager.getInstance(AriaManager.APP)
+        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
+        .exe();
+  }
+
+  /**
+   * 停止下载
+   *
+   * @see #stop()
+   */
+  @Deprecated public void pause() {
+    stop();
+  }
+
+  @Override public void stop() {
+    AriaManager.getInstance(AriaManager.APP)
+        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP))
+        .exe();
+  }
+
+  /**
+   * 恢复下载
+   */
+  @Override public void resume() {
+    AriaManager.getInstance(AriaManager.APP)
+        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
+        .exe();
+  }
+
+  /**
+   * 取消下载
+   */
+  @Override public void cancel() {
+    AriaManager.getInstance(AriaManager.APP)
+        .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL))
+        .exe();
+  }
+}
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 41841d5b..34c54227 100644
--- a/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java
@@ -24,6 +24,7 @@ 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.exception.FileException;
+import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -76,6 +77,24 @@ public class CheckUtil {
     if (TextUtils.isEmpty(downloadUrl)) throw new IllegalArgumentException("下载链接不能为null");
   }
 
+  /**
+   * 检测下载链接组是否为null
+   */
+  public static void checkDownloadUrls(List urls) {
+    if (urls == null || urls.isEmpty()) {
+      throw new IllegalArgumentException("链接组不能为null");
+    }
+  }
+
+  /**
+   * 检查下载任务组保存路径
+   */
+  public static void checkDownloadPaths(List paths) {
+    if (paths == null || paths.isEmpty()) {
+      throw new IllegalArgumentException("链接保存路径不能为null");
+    }
+  }
+
   /**
    * 检测上传地址是否为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 d9407c60..443daf8d 100644
--- a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
@@ -52,6 +52,28 @@ import java.util.regex.Pattern;
 public class CommonUtil {
   private static final String TAG = "CommonUtil";
 
+  /**
+   * 根据下载任务组的url创建key
+   *
+   * @return urls 为 null 或者 size为0,返回""
+   */
+  public static String getMd5Code(List urls) {
+    if (urls == null || urls.size() < 1) return "";
+    String md5 = "";
+    StringBuilder sb = new StringBuilder();
+    for (String url : urls) {
+      sb.append(url);
+    }
+    try {
+      MessageDigest md = MessageDigest.getInstance("MD5");
+      md.update(sb.toString().getBytes());
+      md5 = new BigInteger(1, md.digest()).toString(16);
+    } catch (NoSuchAlgorithmException e) {
+      Log.e(TAG, e.getMessage());
+    }
+    return md5;
+  }
+
   /**
    * 删除上传任务的配置,包括
    *
diff --git a/app/src/main/assets/aria_config.xml b/app/src/main/assets/aria_config.xml
index 9972caa4..474752d0 100644
--- a/app/src/main/assets/aria_config.xml
+++ b/app/src/main/assets/aria_config.xml
@@ -7,9 +7,6 @@
     
     
 
-    
-    
-
     
     
 
@@ -40,8 +37,6 @@
   
 
   
-    
-    
 
     
     
diff --git a/aria/src/main/java/com/arialyy/aria/core/Configuration.java b/aria/src/main/java/com/arialyy/aria/core/Configuration.java
index 8adcb24a..ea4c9d27 100644
--- a/aria/src/main/java/com/arialyy/aria/core/Configuration.java
+++ b/aria/src/main/java/com/arialyy/aria/core/Configuration.java
@@ -42,10 +42,6 @@ class Configuration {
      */
     public int oldMaxTaskNum = 2;
 
-    /**
-     * 是否发送任务广播,true,发送
-     */
-    boolean isOpenBreadCast = false;
     /**
      * 任务队列最大任务数, 默认为2
      */
@@ -85,16 +81,6 @@ class Configuration {
       return this;
     }
 
-    public boolean isOpenBreadCast() {
-      return isOpenBreadCast;
-    }
-
-    public BaseConfig setOpenBreadCast(boolean openBreadCast) {
-      isOpenBreadCast = openBreadCast;
-      saveKey("isOpenBreadCast", openBreadCast + "");
-      return this;
-    }
-
     public int getMaxTaskNum() {
       return maxTaskNum;
     }
diff --git a/aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java b/aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java
index 88c30140..f48ab56b 100644
--- a/aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java
+++ b/aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java
@@ -16,12 +16,9 @@
 package com.arialyy.aria.core.upload;
 
 import android.content.Context;
-import android.content.Intent;
 import android.os.Handler;
 import android.util.Log;
-import com.arialyy.aria.core.Aria;
 import com.arialyy.aria.core.AriaManager;
-import com.arialyy.aria.core.download.DownloadEntity;
 import com.arialyy.aria.core.inf.AbsNormalTask;
 import com.arialyy.aria.core.inf.IEntity;
 import com.arialyy.aria.core.scheduler.DownloadSchedulers;
@@ -41,7 +38,7 @@ public class UploadTask extends AbsNormalTask {
 
   private UploadTask(UploadTaskEntity taskEntity, Handler outHandler) {
     mOutHandler = outHandler;
-    mEntity = taskEntity.uploadEntity;
+    mEntity = taskEntity.getEntity();
     mListener = new UListener(mOutHandler, this);
     mUtil = new UploadUtil(taskEntity, mListener);
   }
@@ -78,118 +75,99 @@ public class UploadTask extends AbsNormalTask {
       if (mOutHandler != null) {
         mOutHandler.obtainMessage(DownloadSchedulers.CANCEL, this).sendToTarget();
       }
-      //发送取消下载的广播
-      Intent intent = CommonUtil.createIntent(AriaManager.APP.getPackageName(), Aria.ACTION_CANCEL);
-      intent.putExtra(Aria.UPLOAD_ENTITY, mEntity);
-      AriaManager.APP.sendBroadcast(intent);
     }
   }
 
-  private static class UListener extends UploadListener {
+  private static class
+  UListener extends UploadListener {
     WeakReference outHandler;
     WeakReference task;
     long lastLen = 0;   //上一次发送长度
     long lastTime = 0;
     long INTERVAL_TIME = 1000;   //1m更新周期
     boolean isFirst = true;
-    UploadEntity uploadEntity;
-    Intent sendIntent;
-    boolean isOpenBroadCast = false;
+    UploadEntity entity;
     boolean isConvertSpeed = false;
     Context context;
 
     UListener(Handler outHandle, UploadTask task) {
       this.outHandler = new WeakReference<>(outHandle);
       this.task = new WeakReference<>(task);
-      uploadEntity = this.task.get().getEntity();
-      sendIntent = CommonUtil.createIntent(AriaManager.APP.getPackageName(), Aria.ACTION_RUNNING);
-      sendIntent.putExtra(Aria.UPLOAD_ENTITY, uploadEntity);
+      entity = this.task.get().getEntity();
       context = AriaManager.APP;
       final AriaManager manager = AriaManager.getInstance(context);
-      isOpenBroadCast = manager.getUploadConfig().isOpenBreadCast();
       isConvertSpeed = manager.getUploadConfig().isConvertSpeed();
     }
 
     @Override public void onPre() {
-      uploadEntity.setState(IEntity.STATE_PRE);
-      sendIntent(Aria.ACTION_PRE, -1);
       sendInState2Target(ISchedulers.PRE);
+      saveData(IEntity.STATE_PRE, -1);
     }
 
     @Override public void onPostPre(long fileSize) {
       super.onPostPre(fileSize);
-      uploadEntity.setFileSize(fileSize);
-      uploadEntity.setState(IEntity.STATE_POST_PRE);
-      sendIntent(Aria.ACTION_POST_PRE, 0);
+      entity.setFileSize(fileSize);
       sendInState2Target(ISchedulers.POST_PRE);
+      saveData(IEntity.STATE_POST_PRE, 0);
     }
 
     @Override public void onStart() {
-      uploadEntity.setState(IEntity.STATE_RUNNING);
-      sendIntent(Aria.ACTION_START, 0);
       sendInState2Target(ISchedulers.START);
+      saveData(IEntity.STATE_RUNNING, 0);
     }
 
     @Override public void onResume(long resumeLocation) {
-      uploadEntity.setState(DownloadEntity.STATE_RUNNING);
       sendInState2Target(DownloadSchedulers.RESUME);
-      sendIntent(Aria.ACTION_RESUME, resumeLocation);
+      saveData(IEntity.STATE_RUNNING, resumeLocation);
     }
 
     @Override public void onStop(long stopLocation) {
-      uploadEntity.setState(DownloadEntity.STATE_STOP);
       handleSpeed(0);
       sendInState2Target(DownloadSchedulers.STOP);
-      sendIntent(Aria.ACTION_STOP, stopLocation);
+      saveData(IEntity.STATE_STOP, stopLocation);
     }
 
     @Override public void onProgress(long currentLocation) {
       if (System.currentTimeMillis() - lastTime > INTERVAL_TIME) {
         long speed = currentLocation - lastLen;
-        sendIntent.putExtra(Aria.CURRENT_LOCATION, currentLocation);
-        sendIntent.putExtra(Aria.CURRENT_SPEED, speed);
         lastTime = System.currentTimeMillis();
         if (isFirst) {
           speed = 0;
           isFirst = false;
         }
         handleSpeed(speed);
-        uploadEntity.setCurrentProgress(currentLocation);
+        entity.setCurrentProgress(currentLocation);
         lastLen = currentLocation;
         sendInState2Target(DownloadSchedulers.RUNNING);
-        AriaManager.APP.sendBroadcast(sendIntent);
       }
     }
 
     @Override public void onCancel() {
-      uploadEntity.setState(DownloadEntity.STATE_CANCEL);
       handleSpeed(0);
       sendInState2Target(DownloadSchedulers.CANCEL);
-      sendIntent(Aria.ACTION_CANCEL, -1);
-      uploadEntity.deleteData();
+      saveData(IEntity.STATE_CANCEL, -1);
+      entity.deleteData();
     }
 
     @Override public void onComplete() {
-      uploadEntity.setState(DownloadEntity.STATE_COMPLETE);
-      uploadEntity.setComplete(true);
+      entity.setComplete(true);
       handleSpeed(0);
       sendInState2Target(DownloadSchedulers.COMPLETE);
-      sendIntent(Aria.ACTION_COMPLETE, uploadEntity.getFileSize());
+      saveData(IEntity.STATE_COMPLETE, entity.getFileSize());
     }
 
     @Override public void onFail() {
-      uploadEntity.setFailNum(uploadEntity.getFailNum() + 1);
-      uploadEntity.setState(DownloadEntity.STATE_FAIL);
+      entity.setFailNum(entity.getFailNum() + 1);
       handleSpeed(0);
       sendInState2Target(DownloadSchedulers.FAIL);
-      sendIntent(Aria.ACTION_FAIL, -1);
+      saveData(IEntity.STATE_FAIL, -1);
     }
 
     private void handleSpeed(long speed) {
       if (isConvertSpeed) {
-        uploadEntity.setConvertSpeed(CommonUtil.formatFileSize(speed) + "/s");
+        entity.setConvertSpeed(CommonUtil.formatFileSize(speed) + "/s");
       } else {
-        uploadEntity.setSpeed(speed);
+        entity.setSpeed(speed);
       }
     }
 
@@ -204,17 +182,11 @@ public class UploadTask extends AbsNormalTask {
       }
     }
 
-    private void sendIntent(String action, long location) {
-      uploadEntity.setComplete(action.equals(Aria.ACTION_COMPLETE));
-      uploadEntity.setCurrentProgress(location);
-      uploadEntity.update();
-      if (!isOpenBroadCast) return;
-      Intent intent = CommonUtil.createIntent(context.getPackageName(), action);
-      intent.putExtra(Aria.UPLOAD_ENTITY, uploadEntity);
-      if (location != -1) {
-        intent.putExtra(Aria.CURRENT_LOCATION, location);
-      }
-      context.sendBroadcast(intent);
+    private void saveData(int state, long location) {
+      entity.setState(state);
+      entity.setComplete(state == IEntity.STATE_COMPLETE);
+      entity.setCurrentProgress(location);
+      entity.update();
     }
   }
 

From fd7e7cc7f4cec13da1cfbf7b7415dd2509d018a8 Mon Sep 17 00:00:00 2001
From: AriaLyy <511455842@qq.com>
Date: Tue, 4 Jul 2017 19:40:53 +0800
Subject: [PATCH 17/34] =?UTF-8?q?orm=20=E9=87=8D=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../aria/core/download/DownloadEntity.java    |  43 ++-
 .../core/download/DownloadGroupEntity.java    |   2 +
 .../download/DownloadGroupTaskEntity.java     |   7 +
 .../aria/core/download/DownloadTarget.java    |   4 +-
 .../core/download/DownloadTaskEntity.java     |   7 +
 .../core/download/downloader/Downloader.java  |  54 ++--
 .../arialyy/aria/core/inf/AbsGroupEntity.java |   4 +-
 .../aria/core/inf/AbsNormalEntity.java        |   1 +
 .../aria/core/inf/AbsNormalTarget.java        |   2 -
 .../arialyy/aria/core/inf/AbsTaskEntity.java  |   9 +-
 .../aria/core/upload/UploadEntity.java        |   3 +-
 .../java/com/arialyy/aria/orm/DBConfig.java   |  10 +-
 .../java/com/arialyy/aria/orm/OneToMany.java  |  36 +++
 .../java/com/arialyy/aria/orm/OneToOne.java   |  38 +++
 .../aria/orm/{Id.java => Primary.java}        |   2 +-
 .../java/com/arialyy/aria/orm/SqlHelper.java  | 251 ++++++++++++++++--
 .../com/arialyy/aria/util/CommonUtil.java     |  54 ++++
 .../simple/download/DownloadModule.java       |  65 -----
 .../simple/download/SingleTaskActivity.java   |   1 -
 .../aria/core/upload/UploadTaskEntity.java    |   8 +-
 20 files changed, 463 insertions(+), 138 deletions(-)
 create mode 100644 Aria/src/main/java/com/arialyy/aria/orm/OneToMany.java
 create mode 100644 Aria/src/main/java/com/arialyy/aria/orm/OneToOne.java
 rename Aria/src/main/java/com/arialyy/aria/orm/{Id.java => Primary.java} (97%)

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 e1102037..340c91f1 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
@@ -19,24 +19,34 @@ package com.arialyy.aria.core.download;
 import android.os.Parcel;
 import android.os.Parcelable;
 import com.arialyy.aria.core.inf.AbsNormalEntity;
-import com.arialyy.aria.orm.Ignore;
+import com.arialyy.aria.orm.Primary;
 
 /**
  * Created by lyy on 2015/12/25.
  * 下载实体
- * !!! 注意:CREATOR要进行@Ignore注解
- * !!!并且需要Parcelable时需要手动填写rowID;
  */
 public class DownloadEntity extends AbsNormalEntity implements Parcelable {
-  private String downloadUrl = ""; //下载路径
+  @Primary private String downloadUrl = ""; //下载路径
   private String downloadPath = ""; //保存路径
   private boolean isDownloadComplete = false;   //是否下载完成
   private boolean isRedirect = false; //是否重定向
   private String redirectUrl = ""; //重定向链接
 
+  /**
+   * 所属任务组
+   */
+  private String groupName = "";
+
   public DownloadEntity() {
   }
 
+  public String getGroupName() {
+    return groupName;
+  }
+
+  public void setGroupName(String groupName) {
+    this.groupName = groupName;
+  }
 
   public String getDownloadUrl() {
     return downloadUrl;
@@ -95,6 +105,7 @@ public class DownloadEntity extends AbsNormalEntity implements Parcelable {
     dest.writeByte(this.isDownloadComplete ? (byte) 1 : (byte) 0);
     dest.writeByte(this.isRedirect ? (byte) 1 : (byte) 0);
     dest.writeString(this.redirectUrl);
+    dest.writeString(this.groupName);
   }
 
   protected DownloadEntity(Parcel in) {
@@ -104,9 +115,31 @@ public class DownloadEntity extends AbsNormalEntity implements Parcelable {
     this.isDownloadComplete = in.readByte() != 0;
     this.isRedirect = in.readByte() != 0;
     this.redirectUrl = in.readString();
+    this.groupName = in.readString();
+  }
+
+  @Override public String toString() {
+    return "DownloadEntity{"
+        + "downloadUrl='"
+        + downloadUrl
+        + '\''
+        + ", downloadPath='"
+        + downloadPath
+        + '\''
+        + ", isDownloadComplete="
+        + isDownloadComplete
+        + ", isRedirect="
+        + isRedirect
+        + ", redirectUrl='"
+        + redirectUrl
+        + '\''
+        + ", groupName='"
+        + groupName
+        + '\''
+        + '}';
   }
 
-  @Ignore public static final Creator CREATOR = new Creator() {
+  public static final Creator CREATOR = new Creator() {
     @Override public DownloadEntity createFromParcel(Parcel source) {
       return new DownloadEntity(source);
     }
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 4cfaa7a3..5b82ddfc 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
@@ -17,6 +17,7 @@ package com.arialyy.aria.core.download;
 
 import android.os.Parcel;
 import com.arialyy.aria.core.inf.AbsGroupEntity;
+import com.arialyy.aria.orm.OneToMany;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -26,6 +27,7 @@ import java.util.List;
  */
 public class DownloadGroupEntity extends AbsGroupEntity {
 
+  @OneToMany(table = DownloadEntity.class, key = "groupName")
   private List mChild = new LinkedList<>();
 
   public List getChild() {
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 94c7cd29..8ef08664 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,13 +16,20 @@
 package com.arialyy.aria.core.download;
 
 import com.arialyy.aria.core.inf.AbsTaskEntity;
+import com.arialyy.aria.orm.OneToOne;
 
 /**
  * Created by AriaL on 2017/7/1.
  */
 public class DownloadGroupTaskEntity extends AbsTaskEntity {
 
+  @OneToOne(table = DownloadGroupEntity.class, key = "groupName") public DownloadGroupEntity entity;
+
   public DownloadGroupTaskEntity(DownloadGroupEntity entity) {
     this.entity = entity;
   }
+
+  @Override public DownloadGroupEntity getEntity() {
+    return entity;
+  }
 }
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 914c1ff7..e9f4295a 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
@@ -29,8 +29,8 @@ public class DownloadTarget extends
     AbsNormalTarget {
 
   DownloadTarget(DownloadEntity entity, String targetName) {
-    this.mEntity = entity;
-    this.mTargetName = targetName;
+    mEntity = entity;
+    mTargetName = targetName;
     mTaskEntity = new DownloadTaskEntity(entity);
   }
 
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 70439cba..09e06d7e 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.AbsTaskEntity;
+import com.arialyy.aria.orm.OneToOne;
 
 /**
  * Created by lyy on 2017/1/23.
@@ -23,10 +24,16 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
  */
 public class DownloadTaskEntity extends AbsTaskEntity {
 
+  @OneToOne(table = DownloadEntity.class, key = "downloadUrl") public DownloadEntity entity;
+
   public DownloadTaskEntity() {
   }
 
   public DownloadTaskEntity(DownloadEntity entity) {
     this.entity = entity;
   }
+
+  @Override public DownloadEntity getEntity() {
+    return entity;
+  }
 }
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 dd2f2e40..ad127c1b 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
@@ -76,8 +76,35 @@ class Downloader implements Runnable, IDownloadUtil {
   }
 
   @Override public void run() {
+    startFlow();
+  }
+
+  /**
+   * 开始下载流程
+   */
+  private void startFlow(){
     checkTask();
-    startDownload();
+    mConstance.cleanState();
+    mConstance.isDownloading = true;
+    try {
+      if (!mTaskEntity.isSupportBP) {
+        mThreadNum = 1;
+        handleNoSupportBreakpointDownload();
+      } else {
+        mThreadNum = isNewTask ? (mEntity.getFileSize() <= SUB_LEN ? 1
+            : AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum())
+            : mRealThreadNum;
+        mFixedThreadPool = Executors.newFixedThreadPool(mThreadNum);
+        handleBreakpoint();
+      }
+    } catch (IOException e) {
+      failDownload("下载失败【downloadUrl:"
+          + mEntity.getDownloadUrl()
+          + "】\n【filePath:"
+          + mEntity.getDownloadPath()
+          + "】\n"
+          + CommonUtil.getPrintException(e));
+    }
   }
 
   @Override public long getFileSize() {
@@ -124,28 +151,11 @@ class Downloader implements Runnable, IDownloadUtil {
     }
   }
 
+  /**
+   * 直接调用的时候会自动启动线程执行
+   */
   @Override public void startDownload() {
-    mConstance.cleanState();
-    mConstance.isDownloading = true;
-    try {
-      if (!mTaskEntity.isSupportBP) {
-        mThreadNum = 1;
-        handleNoSupportBreakpointDownload();
-      } else {
-        mThreadNum = isNewTask ? (mEntity.getFileSize() <= SUB_LEN ? 1
-            : AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum())
-            : mRealThreadNum;
-        mFixedThreadPool = Executors.newFixedThreadPool(mThreadNum);
-        handleBreakpoint();
-      }
-    } catch (IOException e) {
-      failDownload("下载失败【downloadUrl:"
-          + mEntity.getDownloadUrl()
-          + "】\n【filePath:"
-          + mEntity.getDownloadPath()
-          + "】\n"
-          + CommonUtil.getPrintException(e));
-    }
+    new Thread(this).start();
   }
 
   @Override public void resumeDownload() {
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 b324fd57..6a708b98 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,8 +17,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.Primary;
 
 /**
  * Created by AriaL on 2017/6/3.
@@ -27,6 +26,7 @@ public abstract class AbsGroupEntity extends AbsEntity implements Parcelable {
   /**
    * 组名
    */
+  @Primary
   private String groupName = "";
 
   /**
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 4c89b6aa..d1425f7f 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
@@ -35,6 +35,7 @@ public abstract class AbsNormalEntity extends AbsEntity implements Parcelable {
    */
   private boolean isGroupChild = false;
 
+
   public boolean isGroupChild() {
     return isGroupChild;
   }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java
index b8351713..31de1c13 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java
@@ -26,8 +26,6 @@ import com.arialyy.aria.util.CommonUtil;
  */
 public abstract class AbsNormalTarget
     extends AbsTarget {
-  protected ENTITY mEntity;
-  protected TASK_ENTITY mTaskEntity;
 
   /**
    * 将任务设置为最高优先级任务,最高优先级任务有以下特点:
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 205eb388..26459feb 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
@@ -17,6 +17,7 @@ package com.arialyy.aria.core.inf;
 
 import com.arialyy.aria.core.RequestEnum;
 import com.arialyy.aria.orm.DbEntity;
+import com.arialyy.aria.orm.Ignore;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -25,8 +26,6 @@ import java.util.Map;
  */
 public abstract class AbsTaskEntity extends DbEntity {
 
-  public ENTITY entity;
-
   /**
    * Task实体对应的key
    */
@@ -50,7 +49,7 @@ public abstract class AbsTaskEntity extends DbEntity {
   /**
    * 用于判断删除任务时是否需要删除文件{@code true}删除
    */
-  public boolean removeFile = false;
+  @Ignore public boolean removeFile = false;
 
   /**
    * 是否支持断点, {@code true} 为支持断点
@@ -62,7 +61,5 @@ public abstract class AbsTaskEntity extends DbEntity {
    */
   public int code;
 
-  public ENTITY getEntity() {
-    return entity;
-  }
+  public abstract ENTITY getEntity();
 }
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 e9105255..39cc014f 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,13 +19,14 @@ import android.os.Parcel;
 import android.os.Parcelable;
 import com.arialyy.aria.core.inf.AbsNormalEntity;
 import com.arialyy.aria.orm.Ignore;
+import com.arialyy.aria.orm.Primary;
 
 /**
  * Created by lyy on 2017/2/9.
  * 上传文件实体
  */
 public class UploadEntity extends AbsNormalEntity implements Parcelable {
-
+  @Primary
   private String filePath;  //文件路径
   private boolean isComplete = false;
 
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 faf40925..ec9f92eb 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,11 @@ package com.arialyy.aria.orm;
 
 import android.text.TextUtils;
 import com.arialyy.aria.core.download.DownloadEntity;
+import com.arialyy.aria.core.download.DownloadGroupEntity;
+import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
+import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.upload.UploadEntity;
+import com.arialyy.aria.core.upload.UploadTaskEntity;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -28,7 +32,7 @@ import java.util.Map;
 public class DBConfig {
   static Map mapping = new HashMap<>();
   static String DB_NAME;
-  static int VERSION = 3;
+  static int VERSION = 6;
 
   static {
     if (TextUtils.isEmpty(DB_NAME)) {
@@ -41,6 +45,10 @@ public class DBConfig {
 
   static {
     mapping.put("DownloadEntity", DownloadEntity.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);
   }
 }
diff --git a/Aria/src/main/java/com/arialyy/aria/orm/OneToMany.java b/Aria/src/main/java/com/arialyy/aria/orm/OneToMany.java
new file mode 100644
index 00000000..8f529e1b
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/orm/OneToMany.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ * 一对多
+ */
+@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface OneToMany {
+  /**
+   * 关联的表
+   */
+  Class table();
+  /**
+   * 关联的主键
+   */
+  String key();
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/orm/OneToOne.java b/Aria/src/main/java/com/arialyy/aria/orm/OneToOne.java
new file mode 100644
index 00000000..7641fd55
--- /dev/null
+++ b/Aria/src/main/java/com/arialyy/aria/orm/OneToOne.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ * 一对一
+ */
+@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface OneToOne {
+
+  /**
+   * 关联的表
+   */
+  Class table();
+
+  /**
+   * 关联的主键
+   */
+  String key();
+}
diff --git a/Aria/src/main/java/com/arialyy/aria/orm/Id.java b/Aria/src/main/java/com/arialyy/aria/orm/Primary.java
similarity index 97%
rename from Aria/src/main/java/com/arialyy/aria/orm/Id.java
rename to Aria/src/main/java/com/arialyy/aria/orm/Primary.java
index a59b85d9..365f1713 100644
--- a/Aria/src/main/java/com/arialyy/aria/orm/Id.java
+++ b/Aria/src/main/java/com/arialyy/aria/orm/Primary.java
@@ -25,6 +25,6 @@ import java.lang.annotation.Target;
  * Created by lyy on 2015/11/2.
  * 表ID字段指定
  */
-@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Id {
+@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Primary {
   int value() default -1;
 }
\ No newline at end of file
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 4920bef0..46541a94 100644
--- a/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
+++ b/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
@@ -28,9 +28,13 @@ import com.arialyy.aria.util.CheckUtil;
 import com.arialyy.aria.util.CommonUtil;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -47,6 +51,10 @@ final class SqlHelper extends SQLiteOpenHelper {
   private static final int FIND_ALL_DATA = 5;
   private static final int DEL_DATA = 6;
 
+  private static final String MAP_FIELD = "map$$";
+  private static final String LIST_FIELD = "list$$";
+  private static final String GENERIC_FIELD = "Generic$$";
+
   private static volatile SqlHelper INSTANCE = null;
 
   static SqlHelper init(Context context) {
@@ -186,12 +194,26 @@ final class SqlHelper extends SQLiteOpenHelper {
     sql = String.format(sql, params);
     print(FIND_DATA, sql);
     Cursor cursor = db.rawQuery(sql, null);
-    List data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
+    List data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null;
     cursor.close();
     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);
+  }
+
   /**
    * 条件查寻数据
    */
@@ -215,7 +237,7 @@ final class SqlHelper extends SQLiteOpenHelper {
     }
     print(FIND_DATA, sb.toString());
     Cursor cursor = db.rawQuery(sb.toString(), null);
-    List data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
+    List data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null;
     cursor.close();
     close(db);
     return data;
@@ -230,7 +252,7 @@ final class SqlHelper extends SQLiteOpenHelper {
     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;
+    List data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null;
     cursor.close();
     close(db);
     return data;
@@ -273,11 +295,22 @@ final class SqlHelper extends SQLiteOpenHelper {
         }
         sb.append(i > 0 ? ", " : "");
         try {
-          Object value = field.get(dbEntity);
-          sb.append(field.getName())
-              .append("='")
-              .append(value == null ? "" : value.toString())
-              .append("'");
+          String value;
+          sb.append(field.getName()).append("='");
+          Type type = field.getType();
+          if (type == Map.class) {
+            value = map2Str((Map) field.get(dbEntity));
+          } else if (type == List.class) {
+            value = getListElementParams(field);
+          } else if (isOneToOne(field)) {
+            value = getOneToOneParams(field);
+          } else {
+            Object obj = field.get(dbEntity);
+            value = obj == null ? "" : obj.toString();
+          }
+
+          sb.append(value == null ? "" : value);
+          sb.append("'");
         } catch (IllegalAccessException e) {
           e.printStackTrace();
         }
@@ -307,24 +340,35 @@ final class SqlHelper extends SQLiteOpenHelper {
           continue;
         }
         sb.append(i > 0 ? ", " : "");
+        //sb.append(getFieldName(field.getType(), field));
         sb.append(field.getName());
         i++;
       }
       sb.append(") VALUES (");
       i = 0;
-      for (Field field : fields) {
-        field.setAccessible(true);
-        if (ignoreField(field)) {
-          continue;
-        }
-        sb.append(i > 0 ? ", " : "");
-        sb.append("'");
-        try {
-          sb.append(field.get(dbEntity)).append("'");
-        } catch (IllegalAccessException e) {
-          e.printStackTrace();
+      try {
+        for (Field field : fields) {
+          field.setAccessible(true);
+          if (ignoreField(field)) {
+            continue;
+          }
+          sb.append(i > 0 ? ", " : "");
+          sb.append("'");
+          Type type = field.getType();
+          if (type == Map.class) {
+            sb.append(map2Str((Map) field.get(dbEntity)));
+          } else if (type == List.class) {
+            sb.append(getListElementParams(field));
+          } else if (isOneToOne(field)) {
+            sb.append(getOneToOneParams(field));
+          } else {
+            sb.append(field.get(dbEntity));
+          }
+          sb.append("'");
+          i++;
         }
-        i++;
+      } catch (IllegalAccessException e) {
+        e.printStackTrace();
       }
       sb.append(")");
       print(INSERT_DATA, sb.toString());
@@ -333,6 +377,47 @@ final class SqlHelper extends SQLiteOpenHelper {
     close(db);
   }
 
+  /**
+   * 获取一对一参数
+   */
+  private static String getOneToOneParams(Field field) {
+    OneToOne oneToOne = field.getAnnotation(OneToOne.class);
+    if (oneToOne == null) {
+      throw new IllegalArgumentException("@OneToOne注解的对象必须要有@Primary注解的字段");
+    }
+    return oneToOne.table().getName() + "$$" + oneToOne.key();
+  }
+
+  /**
+   * 获取List一对多参数
+   *
+   * @param field list反射字段
+   */
+  private static String getListElementParams(Field field) {
+    OneToMany oneToMany = field.getAnnotation(OneToMany.class);
+    if (oneToMany == null) {
+      throw new IllegalArgumentException("List中元素必须被@OneToMany注解");
+    }
+    //关联的表名
+    String tableName = oneToMany.table().getName();
+    //关联的字段
+    String key = oneToMany.key();
+    return tableName + "$$" + key;
+  }
+
+  /**
+   * 查找class的主键字段
+   *
+   * @return 返回主键字段名
+   */
+  private static String getPrimaryName(Class clazz) {
+    List fields = CommonUtil.getAllFields(clazz);
+    for (Field field : fields) {
+      if (isPrimary(field)) return field.getName();
+    }
+    return null;
+  }
+
   /**
    * 查找表是否存在
    *
@@ -383,9 +468,13 @@ final class SqlHelper extends SQLiteOpenHelper {
         if (ignoreField(field)) {
           continue;
         }
-        sb.append(field.getName());
         Class type = field.getType();
-        if (type == String.class) {
+        sb.append(field.getName());
+        if (type == String.class
+            || type == Map.class
+            || type == List.class
+            || isOneToOne(field)
+            || type.isEnum()) {
           sb.append(" varchar");
         } else if (type == int.class || type == Integer.class) {
           sb.append(" interger");
@@ -404,6 +493,9 @@ final class SqlHelper extends SQLiteOpenHelper {
         } else {
           continue;
         }
+        if (isPrimary(field)) {
+          sb.append(" PRIMARY KEY");
+        }
         sb.append(",");
       }
       String str = sb.toString();
@@ -414,15 +506,32 @@ final class SqlHelper extends SQLiteOpenHelper {
     close(db);
   }
 
+  ///**
+  // * 通过字段类型和获取保存在数据库表字段名
+  // */
+  //private static String getFieldName(Class type, Field field) {
+  //  String fieldName;
+  //  if (type == Map.class) {
+  //    fieldName = MAP_FIELD + field.getName();
+  //  } else if (type == List.class) {
+  //    fieldName = LIST_FIELD + field.getName();
+  //  } else if (isGeneric(field)) {
+  //    fieldName = GENERIC_FIELD + field.getName();
+  //  } else {
+  //    fieldName = field.getName();
+  //  }
+  //  return fieldName;
+  //}
+
   /**
    * 打印数据库日志
    *
    * @param type {@link DbUtil}
    */
   static void print(int type, String sql) {
-    if (true) {
-      return;
-    }
+    //if (true) {
+    //  return;
+    //}
     String str = "";
     switch (type) {
       case CREATE_TABLE:
@@ -450,8 +559,8 @@ final class SqlHelper extends SQLiteOpenHelper {
   /**
    * 根据数据游标创建一个具体的对象
    */
-  static synchronized  List newInstanceEntity(Class clazz,
-      Cursor cursor) {
+  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) {
@@ -482,8 +591,24 @@ final class SqlHelper extends SQLiteOpenHelper {
               field.set(entity, new Date(cursor.getString(column)));
             } else if (type == byte[].class) {
               field.set(entity, cursor.getBlob(column));
-            } else {
-              continue;
+            } else if (type == Map.class) {
+              field.set(entity, str2Map(cursor.getString(column)));
+            } else if (type == List.class) {
+              //主键字段
+              String primaryKey = getPrimaryName(clazz);
+              if (TextUtils.isEmpty(primaryKey)) {
+                throw new IllegalArgumentException("List中的元素对象必须需要@Primary注解的字段");
+              }
+              //list字段保存的数据
+              String params = cursor.getString(column);
+              field.set(entity, findForeignData(db, primaryKey, params));
+            } else if (isOneToOne(field)) {
+              String primaryKey = getPrimaryName(clazz);
+              if (TextUtils.isEmpty(primaryKey)) {
+                throw new IllegalArgumentException("@OneToOne的注解对象必须需要@Primary注解的字段");
+              }
+              String params = cursor.getString(column);
+              field.set(entity, findForeignData(db, primaryKey, params).get(0));
             }
           }
           entity.rowID = cursor.getInt(cursor.getColumnIndex("rowid"));
@@ -499,6 +624,50 @@ final class SqlHelper extends SQLiteOpenHelper {
     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);
+  }
+
+  /**
+   * 字符串转Map,只支持
+   * 
+   *   {@code Map}
+   * 
+ */ + private static Map str2Map(String str) { + String[] element = str.split(","); + Map map = new HashMap<>(); + for (String data : element) { + String[] s = data.split("$"); + map.put(s[0], s[1]); + } + return map; + } + + /** + * Map转字符串,只支持 + *
+   *   {@code Map}
+   * 
+ */ + private static String map2Str(Map map) { + StringBuilder sb = new StringBuilder(); + Set keys = map.keySet(); + for (String key : keys) { + sb.append(key).append("$").append(map.get(key)).append(","); + } + String str = sb.toString(); + return TextUtils.isEmpty(str) ? str : str.substring(0, str.length() - 1); + } + private static void close(SQLiteDatabase db) { //if (db != null && db.isOpen()) db.close(); } @@ -523,4 +692,28 @@ final class SqlHelper extends SQLiteOpenHelper { || Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers); } + + /** + * 判断是否一对多注解 + */ + private static boolean isOneToMany(Field field) { + OneToMany oneToMany = field.getAnnotation(OneToMany.class); + return oneToMany != null; + } + + /** + * 判断是否是一对一注解 + */ + private static boolean isOneToOne(Field field) { + OneToOne oneToOne = field.getAnnotation(OneToOne.class); + return oneToOne != null; + } + + /** + * 判断是否是主键 + */ + private static boolean isPrimary(Field field) { + Primary pk = field.getAnnotation(Primary.class); + return pk != null; + } } \ No newline at end of file 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 443daf8d..bceff11e 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java @@ -45,6 +45,11 @@ import java.util.Collections; import java.util.List; import java.util.Properties; import java.util.regex.Pattern; +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; /** * Created by lyy on 2016/1/22. @@ -52,6 +57,55 @@ import java.util.regex.Pattern; public class CommonUtil { private static final String TAG = "CommonUtil"; + /** + * 实例化泛型的实际类型参数 + * + * @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 * diff --git a/app/src/main/java/com/arialyy/simple/download/DownloadModule.java b/app/src/main/java/com/arialyy/simple/download/DownloadModule.java index f4c2e831..56ad3738 100644 --- a/app/src/main/java/com/arialyy/simple/download/DownloadModule.java +++ b/app/src/main/java/com/arialyy/simple/download/DownloadModule.java @@ -92,69 +92,4 @@ public class DownloadModule extends BaseModule { return entity; } - /** - * 下载广播过滤器 - */ - public IntentFilter getDownloadFilter() { - IntentFilter filter = new IntentFilter(); - filter.addDataScheme(getContext().getPackageName()); - filter.addAction(Aria.ACTION_PRE); - filter.addAction(Aria.ACTION_POST_PRE); - filter.addAction(Aria.ACTION_RESUME); - filter.addAction(Aria.ACTION_START); - filter.addAction(Aria.ACTION_RUNNING); - filter.addAction(Aria.ACTION_STOP); - filter.addAction(Aria.ACTION_CANCEL); - filter.addAction(Aria.ACTION_COMPLETE); - filter.addAction(Aria.ACTION_FAIL); - return filter; - } - - /** - * 创建Receiver - */ - public BroadcastReceiver createReceiver(final Handler handler) { - - return new BroadcastReceiver() { - long len = 0; - - @Override public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - switch (action) { - case Aria.ACTION_POST_PRE: - DownloadEntity entity = intent.getParcelableExtra(Aria.DOWNLOAD_ENTITY); - len = entity.getFileSize(); - L.d(TAG, "download onPre"); - handler.obtainMessage(SingleTaskActivity.DOWNLOAD_PRE, len).sendToTarget(); - break; - case Aria.ACTION_START: - L.d(TAG, "download start"); - break; - case Aria.ACTION_RESUME: - L.d(TAG, "download resume"); - long location = intent.getLongExtra(Aria.CURRENT_LOCATION, 1); - handler.obtainMessage(SingleTaskActivity.DOWNLOAD_RESUME, location).sendToTarget(); - break; - case Aria.ACTION_RUNNING: - long current = intent.getLongExtra(Aria.CURRENT_LOCATION, 0); - int progress = len == 0 ? 0 : (int) ((current * 100) / len); - handler.obtainMessage(SingleTaskActivity.DOWNLOAD_RUNNING, progress).sendToTarget(); - break; - case Aria.ACTION_STOP: - L.d(TAG, "download stop"); - handler.sendEmptyMessage(SingleTaskActivity.DOWNLOAD_STOP); - break; - case Aria.ACTION_COMPLETE: - handler.sendEmptyMessage(SingleTaskActivity.DOWNLOAD_COMPLETE); - break; - case Aria.ACTION_CANCEL: - handler.sendEmptyMessage(SingleTaskActivity.DOWNLOAD_CANCEL); - break; - case Aria.ACTION_FAIL: - handler.sendEmptyMessage(SingleTaskActivity.DOWNLOAD_FAILE); - break; - } - } - }; - } } \ No newline at end of file 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 aecbb8cf..8deb1624 100644 --- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java @@ -246,7 +246,6 @@ public class SingleTaskActivity extends BaseActivity { setBtState(false); } mSize.setText(target.getConvertFileSize()); - Aria.get(this).getDownloadConfig().setOpenBreadCast(true); } public void onClick(View view) { 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 5200e761..48f17ee7 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 @@ -15,7 +15,9 @@ */ package com.arialyy.aria.core.upload; +import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.inf.AbsTaskEntity; +import com.arialyy.aria.orm.OneToOne; import java.util.HashMap; import java.util.Map; @@ -29,7 +31,8 @@ public class UploadTaskEntity extends AbsTaskEntity { public String contentType = "multipart/form-data"; //上传的文件类型 public String userAgent = "User-Agent"; public String charset = "utf-8"; - + @OneToOne(table = UploadEntity.class, key = "filePath") public UploadEntity entity; + /** * 文件上传表单 */ @@ -39,4 +42,7 @@ public class UploadTaskEntity extends AbsTaskEntity { this.entity = entity; } + @Override public UploadEntity getEntity() { + return entity; + } } From 5a223e4b0888b69f3ecaaa475383d0e937c60640 Mon Sep 17 00:00:00 2001 From: AriaLyy <511455842@qq.com> Date: Wed, 5 Jul 2017 10:57:58 +0800 Subject: [PATCH 18/34] =?UTF-8?q?orm=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/command/normal/ResumeAllCmd.java | 3 +- .../core/download/DownloadGroupTarget.java | 3 +- .../download/DownloadGroupTaskEntity.java | 4 -- .../aria/core/download/DownloadTarget.java | 3 +- .../core/download/DownloadTaskEntity.java | 4 -- .../downloader/DownloadGroupUtil.java | 3 +- .../download/downloader/FileInfoThread.java | 4 +- .../arialyy/aria/core/inf/AbsTaskEntity.java | 3 +- .../core/queue/DownloadGroupTaskQueue.java | 1 + .../aria/core/queue/DownloadTaskQueue.java | 1 + .../aria/core/queue/UploadTaskQueue.java | 2 +- .../aria/core/upload/UploadReceiver.java | 2 +- .../aria/core/upload/UploadTarget.java | 3 +- .../java/com/arialyy/aria/orm/DbEntity.java | 15 +++++++- .../java/com/arialyy/aria/orm/SqlHelper.java | 38 ++++++++++++------- .../aria/core/upload/UploadTaskEntity.java | 3 +- 16 files changed, 56 insertions(+), 36 deletions(-) diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java index 58b26bdc..2a019bb7 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java @@ -41,7 +41,8 @@ final class ResumeAllCmd extends AbsNormalCmd { private AbsTask createTask(DownloadEntity entity) { AbsTask task = mQueue.getTask(entity); if (task == null) { - DownloadTaskEntity taskEntity = new DownloadTaskEntity(entity); + DownloadTaskEntity taskEntity = new DownloadTaskEntity(); + taskEntity.entity = entity; task = mQueue.createTask(mTargetName, taskEntity); } else { Log.w(TAG, "添加命令执行失败,【该任务已经存在】"); 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 f76ee2f2..9983edad 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 @@ -32,7 +32,8 @@ public class DownloadGroupTarget this.mEntity = entity; this.mTargetName = targetName; this.mUrls = urls; - mTaskEntity = new DownloadGroupTaskEntity(entity); + mTaskEntity = new DownloadGroupTaskEntity(); + mTaskEntity.entity = entity; } /** 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 8ef08664..4987a1d0 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 @@ -25,10 +25,6 @@ public class DownloadGroupTaskEntity extends AbsTaskEntity @OneToOne(table = DownloadGroupEntity.class, key = "groupName") public DownloadGroupEntity entity; - public DownloadGroupTaskEntity(DownloadGroupEntity entity) { - this.entity = entity; - } - @Override public DownloadGroupEntity getEntity() { return entity; } 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 e9f4295a..e6bab790 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 @@ -31,7 +31,8 @@ public class DownloadTarget extends DownloadTarget(DownloadEntity entity, String targetName) { mEntity = entity; mTargetName = targetName; - mTaskEntity = new DownloadTaskEntity(entity); + mTaskEntity = new DownloadTaskEntity(); + mTaskEntity.entity = mEntity; } /** 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 09e06d7e..13d1c6fd 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 @@ -29,10 +29,6 @@ public class DownloadTaskEntity extends AbsTaskEntity { public DownloadTaskEntity() { } - public DownloadTaskEntity(DownloadEntity entity) { - this.entity = entity; - } - @Override public DownloadEntity getEntity() { return entity; } 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 01e3c6bb..7dbd2585 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 @@ -242,7 +242,8 @@ public class DownloadGroupUtil implements IDownloadUtil { if (taskEntity != null) { return taskEntity; } - taskEntity = new DownloadTaskEntity(entity); + taskEntity = new DownloadTaskEntity(); + taskEntity.entity = entity; taskEntity.headers = mTaskEntity.headers; taskEntity.requestEnum = mTaskEntity.requestEnum; taskEntity.redirectUrlKey = mTaskEntity.redirectUrlKey; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FileInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FileInfoThread.java index 71e33f78..d47a1d3b 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FileInfoThread.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FileInfoThread.java @@ -117,8 +117,8 @@ class FileInfoThread implements Runnable { if (onFileInfoListener != null) { onFileInfoListener.onComplete(mEntity.getDownloadUrl(), code); } - mEntity.update(); - mTaskEntity.update(); + mEntity.save(); + mTaskEntity.save(); } } 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 26459feb..ba341fdc 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 @@ -18,6 +18,7 @@ package com.arialyy.aria.core.inf; import com.arialyy.aria.core.RequestEnum; import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.Ignore; +import com.arialyy.aria.orm.Primary; import java.util.HashMap; import java.util.Map; @@ -29,7 +30,7 @@ public abstract class AbsTaskEntity extends DbEntity { /** * Task实体对应的key */ - public String key; + @Primary public String key = ""; /** * http 请求头 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 6699ef41..325284ed 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 @@ -53,6 +53,7 @@ public class DownloadGroupTaskQueue if (!TextUtils.isEmpty(targetName)) { task = (DownloadGroupTask) TaskFactory.getInstance() .createTask(targetName, entity, DownloadGroupSchedulers.getInstance()); + entity.key = entity.getEntity().getGroupName(); mCachePool.putTask(task); } else { Log.e(TAG, "target name 为 null!!"); diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java index 169a9839..7cf4d0ed 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java +++ b/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java @@ -118,6 +118,7 @@ public class DownloadTaskQueue if (!TextUtils.isEmpty(target)) { task = (DownloadTask) TaskFactory.getInstance() .createTask(target, entity, DownloadSchedulers.getInstance()); + entity.key = entity.getEntity().getDownloadUrl(); mCachePool.putTask(task); } else { Log.e(TAG, "target name 为 null!!"); diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java index 0d36f105..b58013f9 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java +++ b/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java @@ -54,12 +54,12 @@ public class UploadTaskQueue extends AbsTaskQueue { for (UploadEntity entity : allEntity) { if (entity.getState() == IEntity.STATE_RUNNING) { stopCmds.add( - CommonUtil.createCmd(targetName, new UploadTaskEntity(entity), NormalCmdFactory.TASK_STOP)); + CommonUtil.createCmd(targetName, new UploadTaskEntity(), NormalCmdFactory.TASK_STOP)); } } AriaManager.getInstance(AriaManager.APP).setCmds(stopCmds).exe(); 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 cdbde0e1..1e6e481b 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 @@ -27,7 +27,8 @@ public class UploadTarget extends AbsNormalTarget fields = CommonUtil.getAllFields(getClass()); List where = new ArrayList<>(); List values = new ArrayList<>(); for (Field field : fields) { @@ -165,7 +167,16 @@ public class DbEntity { continue; } where.add(field.getName()); - values.add(field.get(this) + ""); + Type type = field.getType(); + if (SqlHelper.isOneToOne(field)) { + values.add(SqlHelper.getOneToOneParams(field)); + } else if (type == List.class) { + values.add(SqlHelper.getListElementParams(field)); + } else if (type == Map.class) { + values.add(SqlHelper.map2Str((Map) field.get(this))); + } else { + values.add(field.get(this) + ""); + } } DbEntity entity = findData(getClass(), where.toArray(new String[where.size()]), values.toArray(new String[values.size()])); 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 46541a94..4eeaa338 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java @@ -51,10 +51,6 @@ final class SqlHelper extends SQLiteOpenHelper { private static final int FIND_ALL_DATA = 5; private static final int DEL_DATA = 6; - private static final String MAP_FIELD = "map$$"; - private static final String LIST_FIELD = "list$$"; - private static final String GENERIC_FIELD = "Generic$$"; - private static volatile SqlHelper INSTANCE = null; static SqlHelper init(Context context) { @@ -380,7 +376,7 @@ final class SqlHelper extends SQLiteOpenHelper { /** * 获取一对一参数 */ - private static String getOneToOneParams(Field field) { + static String getOneToOneParams(Field field) { OneToOne oneToOne = field.getAnnotation(OneToOne.class); if (oneToOne == null) { throw new IllegalArgumentException("@OneToOne注解的对象必须要有@Primary注解的字段"); @@ -393,7 +389,7 @@ final class SqlHelper extends SQLiteOpenHelper { * * @param field list反射字段 */ - private static String getListElementParams(Field field) { + static String getListElementParams(Field field) { OneToMany oneToMany = field.getAnnotation(OneToMany.class); if (oneToMany == null) { throw new IllegalArgumentException("List中元素必须被@OneToMany注解"); @@ -600,15 +596,26 @@ final class SqlHelper extends SQLiteOpenHelper { throw new IllegalArgumentException("List中的元素对象必须需要@Primary注解的字段"); } //list字段保存的数据 + int kc = cursor.getColumnIndex(primaryKey); String params = cursor.getString(column); + String primaryData = cursor.getString(kc); + if (TextUtils.isEmpty(primaryData)) continue; + List list = findForeignData(db, primaryData, params); + if (list == null) continue; field.set(entity, findForeignData(db, primaryKey, params)); } else if (isOneToOne(field)) { String primaryKey = getPrimaryName(clazz); if (TextUtils.isEmpty(primaryKey)) { throw new IllegalArgumentException("@OneToOne的注解对象必须需要@Primary注解的字段"); } + int kc = cursor.getColumnIndex(primaryKey); String params = cursor.getString(column); - field.set(entity, findForeignData(db, primaryKey, params).get(0)); + String primaryData = cursor.getString(kc); + if (TextUtils.isEmpty(primaryData) || primaryData.equalsIgnoreCase("null")) continue; + List list = findForeignData(db, primaryData, params); + if (list != null && list.size() > 1) { + field.set(entity, list.get(0)); + } } } entity.rowID = cursor.getInt(cursor.getColumnIndex("rowid")); @@ -632,7 +639,7 @@ final class SqlHelper extends SQLiteOpenHelper { */ private static List findForeignData(SQLiteDatabase db, String primary, String childParams) { - String[] params = childParams.split("$$"); + String[] params = childParams.split("\\$\\$"); return findData(db, params[0], params[1] + "=?", primary); } @@ -643,10 +650,13 @@ final class SqlHelper extends SQLiteOpenHelper { * */ private static Map str2Map(String str) { - String[] element = str.split(","); Map map = new HashMap<>(); + if (TextUtils.isEmpty(str)) { + return map; + } + String[] element = str.split(","); for (String data : element) { - String[] s = data.split("$"); + String[] s = data.split("\\$"); map.put(s[0], s[1]); } return map; @@ -658,7 +668,7 @@ final class SqlHelper extends SQLiteOpenHelper { * {@code Map} * */ - private static String map2Str(Map map) { + static String map2Str(Map map) { StringBuilder sb = new StringBuilder(); Set keys = map.keySet(); for (String key : keys) { @@ -696,7 +706,7 @@ final class SqlHelper extends SQLiteOpenHelper { /** * 判断是否一对多注解 */ - private static boolean isOneToMany(Field field) { + static boolean isOneToMany(Field field) { OneToMany oneToMany = field.getAnnotation(OneToMany.class); return oneToMany != null; } @@ -704,7 +714,7 @@ final class SqlHelper extends SQLiteOpenHelper { /** * 判断是否是一对一注解 */ - private static boolean isOneToOne(Field field) { + static boolean isOneToOne(Field field) { OneToOne oneToOne = field.getAnnotation(OneToOne.class); return oneToOne != null; } @@ -712,7 +722,7 @@ final class SqlHelper extends SQLiteOpenHelper { /** * 判断是否是主键 */ - private static boolean isPrimary(Field field) { + static boolean isPrimary(Field field) { Primary pk = field.getAnnotation(Primary.class); return pk != null; } 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 48f17ee7..93edfe96 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 @@ -38,8 +38,7 @@ public class UploadTaskEntity extends AbsTaskEntity { */ public Map formFields = new HashMap<>(); - public UploadTaskEntity(UploadEntity entity) { - this.entity = entity; + public UploadTaskEntity() { } @Override public UploadEntity getEntity() { From 5aeb8ec4bb01881388e090170e7cfb9200e1377e Mon Sep 17 00:00:00 2001 From: AriaLyy <511455842@qq.com> Date: Thu, 6 Jul 2017 11:14:15 +0800 Subject: [PATCH 19/34] .. --- .../aria/core/download/DownloadReceiver.java | 1 - .../aria/core/download/DownloadTask.java | 7 ++--- .../arialyy/aria/core/queue/AbsTaskQueue.java | 1 - .../aria/core/upload/UploadTarget.java | 3 +- app/build.gradle | 4 +-- .../simple/download/SingleTaskActivity.java | 4 +-- .../arialyy/aria/core/upload/UploadTask.java | 28 +++++++++---------- 7 files changed, 21 insertions(+), 27 deletions(-) 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 6aa171ca..130b75c3 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 @@ -17,7 +17,6 @@ package com.arialyy.aria.core.download; import android.support.annotation.NonNull; import com.arialyy.aria.core.AriaManager; -import com.arialyy.aria.core.inf.ICmd; import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IReceiver; import com.arialyy.aria.core.command.CmdFactory; 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 f72d68b2..dddad2d2 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 @@ -24,7 +24,6 @@ import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.inf.AbsTask; import com.arialyy.aria.core.inf.IEntity; -import com.arialyy.aria.core.scheduler.DownloadSchedulers; import com.arialyy.aria.core.scheduler.ISchedulers; import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CommonUtil; @@ -141,7 +140,7 @@ public class DownloadTask extends AbsTask { mEntity.setState(isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP); mEntity.save(); if (mOutHandler != null) { - mOutHandler.obtainMessage(DownloadSchedulers.STOP, this).sendToTarget(); + mOutHandler.obtainMessage(ISchedulers.STOP, this).sendToTarget(); } // 发送停止下载的广播 Intent intent = CommonUtil.createIntent(mContext.getPackageName(), Aria.ACTION_STOP); @@ -158,7 +157,7 @@ public class DownloadTask extends AbsTask { if (!mEntity.isDownloadComplete()) { if (!mUtil.isDownloading()) { if (mOutHandler != null) { - mOutHandler.obtainMessage(DownloadSchedulers.CANCEL, this).sendToTarget(); + mOutHandler.obtainMessage(ISchedulers.CANCEL, this).sendToTarget(); } //发送取消下载的广播 Intent intent = CommonUtil.createIntent(mContext.getPackageName(), Aria.ACTION_CANCEL); @@ -333,7 +332,7 @@ public class DownloadTask extends AbsTask { /** * 将任务状态发送给下载器 * - * @param state {@link DownloadSchedulers#START} + * @param state {@link ISchedulers#START} */ private void sendInState2Target(int state) { if (outHandler.get() != null) { 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 67f55038..faab3440 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 @@ -17,7 +17,6 @@ package com.arialyy.aria.core.queue; import android.util.Log; -import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.ITask; 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 1868d51c..f991f7f9 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 @@ -19,7 +19,6 @@ import android.support.annotation.NonNull; import com.arialyy.aria.core.RequestEnum; import com.arialyy.aria.core.inf.AbsTarget; import com.arialyy.aria.core.queue.UploadTaskQueue; -import com.arialyy.aria.orm.DbEntity; import java.util.Map; /** @@ -117,7 +116,7 @@ public class UploadTarget extends AbsTarget { return this; } - private UploadEntity getDownloadEntity() { + private UploadEntity getUploadEntity() { return entity; } diff --git a/app/build.gradle b/app/build.gradle index 58c03308..cb5f0bd7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -42,7 +42,7 @@ dependencies { compile 'com.squareup.okhttp3:okhttp:3.2.0' compile 'com.arialyy.frame:MVVM2:2.2.0' compile project(':Aria') -// compile 'com.arialyy.aria:aria-core:3.1.9' -// annotationProcessor 'com.arialyy.aria:aria-compiler:3.1.9' +// compile 'com.arialyy.aria:aria-core:3.2.0' +// annotationProcessor 'com.arialyy.aria:aria-compiler:3.2.0' } 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 76585966..ecef722d 100644 --- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java @@ -62,10 +62,10 @@ 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://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://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"; //不支持断点的链接 diff --git a/aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java b/aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java index ba799ca0..5aee834b 100644 --- a/aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java +++ b/aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java @@ -21,10 +21,8 @@ import android.os.Handler; import android.util.Log; import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.AriaManager; -import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.inf.AbsTask; import com.arialyy.aria.core.inf.IEntity; -import com.arialyy.aria.core.scheduler.DownloadSchedulers; import com.arialyy.aria.core.scheduler.ISchedulers; import com.arialyy.aria.util.CommonUtil; import java.lang.ref.WeakReference; @@ -77,7 +75,7 @@ public class UploadTask extends AbsTask { mUtil.cancel(); mEntity.deleteData(); if (mOutHandler != null) { - mOutHandler.obtainMessage(DownloadSchedulers.CANCEL, this).sendToTarget(); + mOutHandler.obtainMessage(ISchedulers.CANCEL, this).sendToTarget(); } //发送取消下载的广播 Intent intent = CommonUtil.createIntent(AriaManager.APP.getPackageName(), Aria.ACTION_CANCEL); @@ -132,15 +130,15 @@ public class UploadTask extends AbsTask { } @Override public void onResume(long resumeLocation) { - uploadEntity.setState(DownloadEntity.STATE_RUNNING); - sendInState2Target(DownloadSchedulers.RESUME); + uploadEntity.setState(IEntity.STATE_RUNNING); + sendInState2Target(ISchedulers.RESUME); sendIntent(Aria.ACTION_RESUME, resumeLocation); } @Override public void onStop(long stopLocation) { - uploadEntity.setState(DownloadEntity.STATE_STOP); + uploadEntity.setState(IEntity.STATE_STOP); handleSpeed(0); - sendInState2Target(DownloadSchedulers.STOP); + sendInState2Target(ISchedulers.STOP); sendIntent(Aria.ACTION_STOP, stopLocation); } @@ -157,32 +155,32 @@ public class UploadTask extends AbsTask { handleSpeed(speed); uploadEntity.setCurrentProgress(currentLocation); lastLen = currentLocation; - sendInState2Target(DownloadSchedulers.RUNNING); + sendInState2Target(ISchedulers.RUNNING); AriaManager.APP.sendBroadcast(sendIntent); } } @Override public void onCancel() { - uploadEntity.setState(DownloadEntity.STATE_CANCEL); + uploadEntity.setState(IEntity.STATE_CANCEL); handleSpeed(0); - sendInState2Target(DownloadSchedulers.CANCEL); + sendInState2Target(ISchedulers.CANCEL); sendIntent(Aria.ACTION_CANCEL, -1); uploadEntity.deleteData(); } @Override public void onComplete() { - uploadEntity.setState(DownloadEntity.STATE_COMPLETE); + uploadEntity.setState(IEntity.STATE_COMPLETE); uploadEntity.setComplete(true); handleSpeed(0); - sendInState2Target(DownloadSchedulers.COMPLETE); + sendInState2Target(ISchedulers.COMPLETE); sendIntent(Aria.ACTION_COMPLETE, uploadEntity.getFileSize()); } @Override public void onFail() { uploadEntity.setFailNum(uploadEntity.getFailNum() + 1); - uploadEntity.setState(DownloadEntity.STATE_FAIL); + uploadEntity.setState(IEntity.STATE_FAIL); handleSpeed(0); - sendInState2Target(DownloadSchedulers.FAIL); + sendInState2Target(ISchedulers.FAIL); sendIntent(Aria.ACTION_FAIL, -1); } @@ -197,7 +195,7 @@ public class UploadTask extends AbsTask { /** * 将任务状态发送给下载器 * - * @param state {@link DownloadSchedulers#START} + * @param state {@link ISchedulers#START} */ private void sendInState2Target(int state) { if (outHandler.get() != null) { From c2ab04b67b5deaa8a9117eb05abfdbff24698187 Mon Sep 17 00:00:00 2001 From: AriaLyy <511455842@qq.com> Date: Thu, 6 Jul 2017 15:48:27 +0800 Subject: [PATCH 20/34] https://github.com/AriaLyy/Aria/issues/66 --- .../core/command/normal/CancelAllCmd.java | 9 ++-- .../core/download/DownloadGroupTarget.java | 26 +++++++++-- .../aria/core/download/DownloadReceiver.java | 26 ++--------- .../aria/core/download/DownloadTarget.java | 43 ++++++++++++++++--- .../aria/core/download/DownloadTask.java | 5 ++- .../core/download/downloader/Downloader.java | 2 +- .../aria/core/upload/UploadReceiver.java | 30 +++---------- .../aria/core/upload/UploadTarget.java | 31 ++++++++++--- .../java/com/arialyy/aria/orm/DbEntity.java | 4 +- .../java/com/arialyy/aria/orm/DbUtil.java | 14 +++++- .../java/com/arialyy/aria/orm/SqlHelper.java | 2 +- .../com/arialyy/aria/util/CommonUtil.java | 22 ++++++---- .../simple/download/SingleTaskActivity.java | 9 ++-- 13 files changed, 137 insertions(+), 86 deletions(-) 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 f68b3bcc..bf3b5fb5 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 @@ -20,6 +20,7 @@ import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadTaskEntity; 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 com.arialyy.aria.util.CommonUtil; import java.util.List; @@ -49,8 +50,8 @@ final class CancelAllCmd extends AbsNormalCmd { * 处理上传的删除 */ private void handleUploadRemove() { - List allEntity = DbEntity.findAllData(UploadEntity.class); - for (UploadEntity entity : allEntity) { + List allEntity = DbEntity.findAllData(UploadTaskEntity.class); + for (UploadTaskEntity entity : allEntity) { CommonUtil.delUploadTaskConfig(mTaskEntity.removeFile, entity); } } @@ -59,8 +60,8 @@ final class CancelAllCmd extends AbsNormalCmd { * 处理下载的删除 */ private void handleDownloadRemove() { - List allEntity = DbEntity.findAllData(DownloadEntity.class); - for (DownloadEntity entity : allEntity) { + List allEntity = DbEntity.findAllData(DownloadTaskEntity.class); + for (DownloadTaskEntity entity : allEntity) { CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, entity); } } 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 9983edad..d9afa40e 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,9 @@ package com.arialyy.aria.core.download; import com.arialyy.aria.core.inf.AbsGroupTarget; import com.arialyy.aria.core.inf.IEntity; +import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.util.CheckUtil; +import com.arialyy.aria.util.CommonUtil; import java.io.File; import java.util.List; @@ -28,12 +30,28 @@ public class DownloadGroupTarget extends AbsGroupTarget { private List mUrls; - DownloadGroupTarget(DownloadGroupEntity entity, String targetName, List urls) { - this.mEntity = entity; + DownloadGroupTarget(List urls, String targetName) { this.mTargetName = targetName; this.mUrls = urls; - mTaskEntity = new DownloadGroupTaskEntity(); - mTaskEntity.entity = entity; + mTaskEntity = + DbEntity.findData(DownloadGroupTaskEntity.class, "key=?", CommonUtil.getMd5Code(urls)); + if (mTaskEntity == null) { + mTaskEntity = new DownloadGroupTaskEntity(); + mTaskEntity.entity = new DownloadGroupEntity(); + } + if (mTaskEntity.entity == null) { + mTaskEntity.entity = getDownloadGroupEntity(urls); + } + mEntity = mTaskEntity.entity; + } + + private DownloadGroupEntity getDownloadGroupEntity(List urls) { + DownloadGroupEntity entity = + DbEntity.findData(DownloadGroupEntity.class, "urlHash=?", CommonUtil.getMd5Code(urls)); + if (entity == null) { + entity = new DownloadGroupEntity(); + } + return entity; } /** 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 5b6589c6..260988bf 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 @@ -60,17 +60,7 @@ public class DownloadReceiver extends AbsReceiver { */ public DownloadTarget load(@NonNull String downloadUrl) { CheckUtil.checkDownloadUrl(downloadUrl); - DownloadEntity entity = - DownloadEntity.findData(DownloadEntity.class, "downloadUrl=?", downloadUrl); - if (entity == null) { - entity = new DownloadEntity(); - } - File file = new File(entity.getDownloadPath()); - if (!file.exists()) { - entity.setState(IEntity.STATE_WAIT); - } - entity.setDownloadUrl(downloadUrl); - return new DownloadTarget(entity, targetName); + return new DownloadTarget(downloadUrl, targetName); } /** @@ -78,13 +68,7 @@ public class DownloadReceiver extends AbsReceiver { */ public DownloadGroupTarget load(List urls) { CheckUtil.checkDownloadUrls(urls); - DownloadGroupEntity entity = - DbEntity.findData(DownloadGroupEntity.class, "urlHash=?", CommonUtil.getMd5Code(urls)); - - if (entity == null) { - entity = new DownloadGroupEntity(); - } - return new DownloadGroupTarget(entity, targetName, urls); + return new DownloadGroupTarget(urls, targetName); } /** @@ -179,10 +163,8 @@ public class DownloadReceiver extends AbsReceiver { */ @Override public void removeAllTask(boolean removeFile) { final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP); - AriaManager.getInstance(AriaManager.APP) - .setCmd(CommonUtil.createCmd(targetName, new DownloadTaskEntity(), - NormalCmdFactory.TASK_CANCEL_ALL)) - .exe(); + ariaManager.setCmd(CommonUtil.createCmd(targetName, new DownloadTaskEntity(), + NormalCmdFactory.TASK_CANCEL_ALL)).exe(); Set keys = ariaManager.getReceiver().keySet(); for (String key : keys) { 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 e6bab790..1fa76a8f 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 @@ -18,21 +18,52 @@ package com.arialyy.aria.core.download; import android.support.annotation.NonNull; import android.text.TextUtils; import com.arialyy.aria.core.inf.AbsNormalTarget; +import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.queue.DownloadTaskQueue; +import com.arialyy.aria.orm.DbEntity; import java.io.File; /** * Created by lyy on 2016/12/5. * https://github.com/AriaLyy/Aria */ -public class DownloadTarget extends - AbsNormalTarget { +public class DownloadTarget + extends AbsNormalTarget { DownloadTarget(DownloadEntity entity, String targetName) { - mEntity = entity; + this(entity.getDownloadUrl(), targetName); + } + + DownloadTarget(String url, String targetName) { mTargetName = targetName; - mTaskEntity = new DownloadTaskEntity(); - mTaskEntity.entity = mEntity; + mTaskEntity = DbEntity.findData(DownloadTaskEntity.class, "key=?", url); + if (mTaskEntity == null) { + mTaskEntity = new DownloadTaskEntity(); + mTaskEntity.entity = new DownloadEntity(); + } + if (mTaskEntity.entity == null) { + mTaskEntity.entity = getEntity(url); + } + mEntity = mTaskEntity.entity; + } + + /** + * 如果任务存在,但是下载实体不存在,则通过下载地址获取下载实体 + * + * @param downloadUrl 下载地址 + */ + private DownloadEntity getEntity(String downloadUrl) { + DownloadEntity entity = + DownloadEntity.findData(DownloadEntity.class, "downloadUrl=?", downloadUrl); + if (entity == null) { + entity = new DownloadEntity(); + } + File file = new File(entity.getDownloadPath()); + if (!file.exists()) { + entity.setState(IEntity.STATE_WAIT); + } + entity.setDownloadUrl(downloadUrl); + return entity; } /** @@ -56,7 +87,6 @@ public class DownloadTarget extends return this; } - /** * 下载任务是否存在 */ @@ -64,7 +94,6 @@ public class DownloadTarget extends return DownloadTaskQueue.getInstance().getTask(mEntity.getDownloadUrl()) != null; } - /** * 设置文件存储路径 */ 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 2e0dbccd..5c36b1d9 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 @@ -17,7 +17,6 @@ package com.arialyy.aria.core.download; import android.content.Context; -import android.content.Intent; import android.os.Handler; import android.util.Log; import com.arialyy.aria.core.AriaManager; @@ -138,7 +137,7 @@ public class DownloadTask extends AbsNormalTask { mUtil.stopDownload(); } else { mEntity.setState(isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP); - mEntity.save(); + mEntity.update(); if (mOutHandler != null) { mOutHandler.obtainMessage(ISchedulers.STOP, this).sendToTarget(); } @@ -184,6 +183,7 @@ public class DownloadTask extends AbsNormalTask { DownloadTask task = new DownloadTask(taskEntity, outHandler); task.setTargetName(targetName); taskEntity.getEntity().save(); + taskEntity.save(); return task; } } @@ -305,6 +305,7 @@ public class DownloadTask extends AbsNormalTask { entity.setDownloadComplete(state == IEntity.STATE_COMPLETE); entity.setCurrentProgress(location); entity.update(); + } } } \ No newline at end of file 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 ad127c1b..6fb08517 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 @@ -82,7 +82,7 @@ class Downloader implements Runnable, IDownloadUtil { /** * 开始下载流程 */ - private void startFlow(){ + private void startFlow() { checkTask(); mConstance.cleanState(); mConstance.isDownloading = true; 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 38ca3487..3d47e2ca 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 @@ -48,17 +48,7 @@ public class UploadReceiver extends AbsReceiver { */ public UploadTarget load(@NonNull String filePath) { CheckUtil.checkUploadPath(filePath); - UploadEntity entity = UploadEntity.findData(UploadEntity.class, "filePath=?", filePath); - if (entity == null) { - entity = new UploadEntity(); - } - String regex = "[/|\\\\|//]"; - Pattern p = Pattern.compile(regex); - String[] strs = p.split(filePath); - String fileName = strs[strs.length - 1]; - entity.setFileName(fileName); - entity.setFilePath(filePath); - return new UploadTarget(entity, targetName); + return new UploadTarget(filePath, targetName); } /** @@ -81,15 +71,10 @@ public class UploadReceiver extends AbsReceiver { } @Override public void stopAllTask() { - List allEntity = DbEntity.findAllData(UploadEntity.class); - List stopCmds = new ArrayList<>(); - for (UploadEntity entity : allEntity) { - if (entity.getState() == IEntity.STATE_RUNNING) { - stopCmds.add( - CommonUtil.createCmd(targetName, new UploadTaskEntity(), NormalCmdFactory.TASK_STOP)); - } - } - AriaManager.getInstance(AriaManager.APP).setCmds(stopCmds).exe(); + AriaManager.getInstance(AriaManager.APP) + .setCmd(NormalCmdFactory.getInstance() + .createCmd(targetName, new UploadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL)) + .exe(); } /** @@ -101,9 +86,8 @@ public class UploadReceiver extends AbsReceiver { @Override public void removeAllTask(boolean removeFile) { final AriaManager am = AriaManager.getInstance(AriaManager.APP); - AriaManager.getInstance(AriaManager.APP) - .setCmd( - CommonUtil.createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_CANCEL_ALL)) + am.setCmd(CommonUtil.createCmd(targetName, new DownloadTaskEntity(), + NormalCmdFactory.TASK_CANCEL_ALL)) .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 5e97d0cb..94d5ca07 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 @@ -18,17 +18,39 @@ package com.arialyy.aria.core.upload; import android.support.annotation.NonNull; import com.arialyy.aria.core.inf.AbsNormalTarget; import com.arialyy.aria.core.queue.UploadTaskQueue; +import com.arialyy.aria.orm.DbEntity; +import java.util.regex.Pattern; /** * Created by lyy on 2017/2/28. */ public class UploadTarget extends AbsNormalTarget { - UploadTarget(UploadEntity entity, String targetName) { - this.mEntity = entity; + UploadTarget(String filePath, String targetName) { this.mTargetName = targetName; - mTaskEntity = new UploadTaskEntity(); - mTaskEntity.entity = entity; + mTaskEntity = DbEntity.findData(UploadTaskEntity.class, "key=?", filePath); + if (mTaskEntity == null) { + mTaskEntity = new UploadTaskEntity(); + mTaskEntity.entity = new UploadEntity(); + } + if (mTaskEntity.entity == null) { + mTaskEntity.entity = getUploadEntity(filePath); + } + mEntity = mTaskEntity.entity; + } + + private UploadEntity getUploadEntity(String filePath) { + UploadEntity entity = UploadEntity.findData(UploadEntity.class, "filePath=?", filePath); + if (entity == null) { + entity = new UploadEntity(); + } + String regex = "[/|\\\\|//]"; + Pattern p = Pattern.compile(regex); + String[] strs = p.split(filePath); + String fileName = strs[strs.length - 1]; + entity.setFileName(fileName); + entity.setFilePath(filePath); + return entity; } /** @@ -91,5 +113,4 @@ public class UploadTarget extends AbsNormalTarget 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; + } + /** * 条件查寻数据 */ @@ -127,7 +139,7 @@ public class DbUtil { SqlHelper.createTable(mDb, clazz, tableName); } - private void checkDb(){ + private void checkDb() { if (mDb == null || !mDb.isOpen()) { mDb = mHelper.getReadableDatabase(); } 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 4eeaa338..65c4a961 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java @@ -613,7 +613,7 @@ final class SqlHelper extends SQLiteOpenHelper { String primaryData = cursor.getString(kc); if (TextUtils.isEmpty(primaryData) || primaryData.equalsIgnoreCase("null")) continue; List list = findForeignData(db, primaryData, params); - if (list != null && list.size() > 1) { + if (list != null && list.size() > 0) { field.set(entity, list.get(0)); } } 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 bceff11e..97edabe7 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java @@ -26,8 +26,10 @@ import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.command.normal.NormalCmdFactory; import com.arialyy.aria.core.command.normal.AbsNormalCmd; import com.arialyy.aria.core.download.DownloadEntity; +import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.upload.UploadEntity; +import com.arialyy.aria.core.upload.UploadTaskEntity; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; @@ -134,19 +136,21 @@ public class CommonUtil { * @param removeFile {@code true} 删除已经上传完成的任务,不仅删除上传记录,还会删除已经上传完成的文件,{@code false} * 如果文件已经上传完成,只删除上传记录 */ - public static void delUploadTaskConfig(boolean removeFile, UploadEntity entity) { + public static void delUploadTaskConfig(boolean removeFile, UploadTaskEntity tEntity) { + UploadEntity uEntity = tEntity.getEntity(); if (removeFile) { - File file = new File(entity.getFilePath()); + File file = new File(uEntity.getFilePath()); if (file.exists()) { file.delete(); } } File config = new File( - AriaManager.APP.getFilesDir().getPath() + "/temp/" + entity.getFileName() + ".properties"); + AriaManager.APP.getFilesDir().getPath() + "/temp/" + uEntity.getFileName() + ".properties"); if (config.exists()) { config.delete(); } - entity.deleteData(); + uEntity.deleteData(); + tEntity.deleteData(); } /** @@ -155,19 +159,21 @@ public class CommonUtil { * @param removeFile{@code true} 删除已经下载完成的任务,不仅删除下载记录,还会删除已经下载完成的文件,{@code false} * 如果文件已经下载完成,只删除下载记录 */ - public static void delDownloadTaskConfig(boolean removeFile, DownloadEntity entity) { + public static void delDownloadTaskConfig(boolean removeFile, DownloadTaskEntity tEntity) { + DownloadEntity dEntity = tEntity.getEntity(); if (removeFile) { - File file = new File(entity.getDownloadPath()); + File file = new File(dEntity.getDownloadPath()); if (file.exists()) { file.delete(); } } File config = new File( - AriaManager.APP.getFilesDir().getPath() + "/temp/" + entity.getFileName() + ".properties"); + AriaManager.APP.getFilesDir().getPath() + "/temp/" + dEntity.getFileName() + ".properties"); if (config.exists()) { config.delete(); } - entity.deleteData(); + dEntity.deleteData(); + tEntity.deleteData(); } /** 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 785e14a8..06a1c425 100644 --- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java @@ -62,10 +62,10 @@ 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://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://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"; //不支持断点的链接 @@ -209,10 +209,6 @@ public class SingleTaskActivity extends BaseActivity { @Download.onTaskCancel(DOWNLOAD_URL) void taskCancel(DownloadTask task) { mUpdateHandler.sendEmptyMessage(DOWNLOAD_CANCEL); L.d(TAG, "task__cancel"); - //Aria.download(this) - // .load(DOWNLOAD_URL) - // .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk") - // .add(); } @Download.onTaskFail(DOWNLOAD_URL) void taskFail(DownloadTask task) { @@ -255,6 +251,7 @@ public class SingleTaskActivity extends BaseActivity { if (text.equals("重新开始?") || text.equals("开始")) { Aria.download(this) .load(DOWNLOAD_URL) + .addHeader("key", "value") .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk") .start(); } else if (text.equals("恢复")) { From 5533742855eac3104c51d06653a3ce6b0f59c3d1 Mon Sep 17 00:00:00 2001 From: AriaLyy <511455842@qq.com> Date: Thu, 6 Jul 2017 17:48:11 +0800 Subject: [PATCH 21/34] .. --- .../core/download/DownloadGroupTarget.java | 36 ++++++-- .../downloader/DownloadGroupUtil.java | 2 +- .../core/download/downloader/Downloader.java | 2 +- .../arialyy/aria/core/inf/AbsGroupTarget.java | 11 ++- app/src/main/AndroidManifest.xml | 1 + .../java/com/arialyy/simple/MainActivity.java | 24 +++--- .../download/group/DownloadGroupActivity.java | 86 +++++++++++++++++++ .../simple/download/group/GroupModule.java | 47 ++++++++++ .../res/layout/activity_download_group.xml | 18 ++++ app/src/main/res/layout/activity_main.xml | 8 +- app/src/main/res/values/strings.xml | 14 +++ 11 files changed, 226 insertions(+), 23 deletions(-) create mode 100644 app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java create mode 100644 app/src/main/java/com/arialyy/simple/download/group/GroupModule.java create mode 100644 app/src/main/res/layout/activity_download_group.xml 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 d9afa40e..f8577e60 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 @@ -29,31 +29,57 @@ import java.util.List; public class DownloadGroupTarget extends AbsGroupTarget { private List mUrls; + private String mGroupName; DownloadGroupTarget(List urls, String targetName) { this.mTargetName = targetName; this.mUrls = urls; - mTaskEntity = - DbEntity.findData(DownloadGroupTaskEntity.class, "key=?", CommonUtil.getMd5Code(urls)); + mGroupName = CommonUtil.getMd5Code(urls); + mTaskEntity = DbEntity.findData(DownloadGroupTaskEntity.class, "key=?", mGroupName); if (mTaskEntity == null) { mTaskEntity = new DownloadGroupTaskEntity(); + mTaskEntity.key = mGroupName; mTaskEntity.entity = new DownloadGroupEntity(); } if (mTaskEntity.entity == null) { - mTaskEntity.entity = getDownloadGroupEntity(urls); + mTaskEntity.entity = getDownloadGroupEntity(); } mEntity = mTaskEntity.entity; } - private DownloadGroupEntity getDownloadGroupEntity(List urls) { + private DownloadGroupEntity getDownloadGroupEntity() { DownloadGroupEntity entity = - DbEntity.findData(DownloadGroupEntity.class, "urlHash=?", CommonUtil.getMd5Code(urls)); + DbEntity.findData(DownloadGroupEntity.class, "groupName=?", mGroupName); if (entity == null) { entity = new DownloadGroupEntity(); } return entity; } + /** + * 设置任务组的文件夹路径,在Aria中,任务组的所有子任务都会下载到以任务组组名的文件夹中。 + * 如:groupDirPath = "/mnt/sdcard/download/", groupName = "group_test" + *
+   *   {@code
+   *      + mnt
+   *        + sdcard
+   *          + download
+   *            + group_test
+   *              - task1.apk
+   *              - task2.apk
+   *              - task3.apk
+   *              ....
+   *
+   *   }
+   * 
+ * + * @param groupDirPath 任务组保存文件夹路径 + */ + public DownloadGroupTarget setDownloadPath(String groupDirPath) { + + return this; + } + /** * 设置保存路径组 */ 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 7dbd2585..2232722c 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 @@ -35,7 +35,7 @@ import java.util.concurrent.Executors; * 任务组下载工具 */ public class DownloadGroupUtil implements IDownloadUtil { - private static final String TAG = "DownloadGroupUtil"; + private final String TAG = "DownloadGroupUtil"; /** * 任务组所有任务总大小 */ 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 6fb08517..7d1eae99 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 @@ -134,7 +134,7 @@ class Downloader implements Runnable, IDownloadUtil { task.cancel(); } } - CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, mEntity); + CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, mTaskEntity); } @Override public void stopDownload() { diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java index c514577b..19bad7c7 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java @@ -19,7 +19,16 @@ package com.arialyy.aria.core.inf; * Created by AriaL on 2017/6/29. * 任务组超类 */ -public abstract class AbsGroupTarget +public abstract class AbsGroupTarget extends AbsTarget { + /** + * 设置任务组的组名,如果不设置任务组,Aria会自动将任务组的所有子任务的key相加,取md5码作为任务组组名 + * + * @param groupName 任务组组名 + */ + public TARGET setGroupName(String groupName) { + mEntity.setGroupName(groupName); + return (TARGET) this; + } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b91acce7..4443482d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -31,6 +31,7 @@ + diff --git a/app/src/main/java/com/arialyy/simple/MainActivity.java b/app/src/main/java/com/arialyy/simple/MainActivity.java index 7b315dab..92a733e0 100644 --- a/app/src/main/java/com/arialyy/simple/MainActivity.java +++ b/app/src/main/java/com/arialyy/simple/MainActivity.java @@ -18,11 +18,8 @@ package com.arialyy.simple; import android.content.Intent; import android.os.Bundle; -import android.support.v7.widget.Toolbar; import android.view.View; -import butterknife.Bind; import butterknife.OnClick; -import com.arialyy.aria.core.Aria; import com.arialyy.simple.base.BaseActivity; import com.arialyy.simple.databinding.ActivityMainBinding; import com.arialyy.simple.download.DownloadActivity; @@ -45,15 +42,20 @@ public class MainActivity extends BaseActivity { return R.layout.activity_main; } - @OnClick(R.id.download) public void downloadDemo() { - startActivity(new Intent(this, DownloadActivity.class)); - } - @OnClick(R.id.upload) public void uploadDemo() { - startActivity(new Intent(this, UploadActivity.class)); - } + @OnClick({R.id.download, R.id.upload, R.id.download_task_group}) + public void funcation(View view){ + switch (view.getId()){ + case R.id.download: + startActivity(new Intent(this, DownloadActivity.class)); + break; + case R.id.upload: + startActivity(new Intent(this, UploadActivity.class)); + break; + case R.id.download_task_group: + + break; + } - @OnClick(R.id.multi_test) public void mutliTest() { - startActivity(new Intent(this, TestMutilTaskSysDownload.class)); } } 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 new file mode 100644 index 00000000..b5968f45 --- /dev/null +++ b/app/src/main/java/com/arialyy/simple/download/group/DownloadGroupActivity.java @@ -0,0 +1,86 @@ +/* + * 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.simple.download.group; + +import android.os.Bundle; +import android.os.Environment; +import android.view.View; +import android.widget.Button; +import android.widget.RadioGroup; +import android.widget.TextView; +import butterknife.Bind; +import com.arialyy.aria.core.Aria; +import com.arialyy.aria.core.download.DownloadTask; +import com.arialyy.aria.core.scheduler.AbsSchedulerListener; +import com.arialyy.simple.R; +import com.arialyy.simple.base.BaseActivity; +import com.arialyy.simple.databinding.ActivityDownloadGroupBinding; +import com.arialyy.simple.widget.HorizontalProgressBarWithNumber; +import java.util.List; + +/** + * Created by Aria.Lao on 2017/7/6. + */ +public class DownloadGroupActivity extends BaseActivity { + + @Bind(R.id.progressBar) HorizontalProgressBarWithNumber mPb; + @Bind(R.id.start) Button mStart; + @Bind(R.id.stop) Button mStop; + @Bind(R.id.cancel) Button mCancel; + @Bind(R.id.size) TextView mSize; + @Bind(R.id.speed) TextView mSpeed; + List mUrls; + + @Override protected void init(Bundle savedInstanceState) { + super.init(savedInstanceState); + setTitle("任务组"); + mUrls = getModule(GroupModule.class).getUrls(); + } + + @Override protected int setLayoutId() { + return R.layout.activity_download_group; + } + + @Override protected void onResume() { + super.onResume(); + //Aria.download(this).addSchedulerListener(new AbsSchedulerListener() { + // + //}); + } + + //public void onClick(View view) { + // switch (view.getId()) { + // case R.id.start: + // String text = ((TextView) view).getText().toString(); + // if (text.equals("重新开始?") || text.equals("开始")) { + // Aria.download(this) + // .load(mUrls) + // .setDownloadPaths() + // .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk") + // .start(); + // } else if (text.equals("恢复")) { + // Aria.download(this).load(DOWNLOAD_URL).resume(); + // } + // break; + // case R.id.stop: + // Aria.download(this).load(DOWNLOAD_URL).pause(); + // break; + // case R.id.cancel: + // Aria.download(this).load(DOWNLOAD_URL).cancel(); + // break; + // } + //} +} diff --git a/app/src/main/java/com/arialyy/simple/download/group/GroupModule.java b/app/src/main/java/com/arialyy/simple/download/group/GroupModule.java new file mode 100644 index 00000000..7e15d112 --- /dev/null +++ b/app/src/main/java/com/arialyy/simple/download/group/GroupModule.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.arialyy.simple.download.group; + +import android.content.Context; +import com.arialyy.simple.R; +import com.arialyy.simple.base.BaseModule; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Created by Aria.Lao on 2017/7/6. + */ +public class GroupModule extends BaseModule { + public GroupModule(Context context) { + super(context); + } + + List getUrls() { + List urls = new ArrayList<>(); + String[] str = getContext().getResources().getStringArray(R.array.download_url); + Collections.addAll(urls, str); + return urls; + } + + //List convertPath(List urls){ + // List paths = new ArrayList<>(); + // + // for (String url : urls){ + // + // } + //} +} diff --git a/app/src/main/res/layout/activity_download_group.xml b/app/src/main/res/layout/activity_download_group.xml new file mode 100644 index 00000000..f7877e92 --- /dev/null +++ b/app/src/main/res/layout/activity_download_group.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 84e60c71..17407578 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -13,7 +13,7 @@ android:id="@+id/download" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="下载 demo" + android:text="下载" style="?buttonBarButtonStyle" /> @@ -21,15 +21,15 @@ android:id="@+id/upload" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="上传 demo" + android:text="上传" style="?buttonBarButtonStyle" />