From 0d59c7b42108d34304c99c742fa3b4a14362ec0e Mon Sep 17 00:00:00 2001 From: AriaLyy <511455842@qq.com> Date: Mon, 5 Jun 2017 18:17:31 +0800 Subject: [PATCH] bug fix --- .../com/arialyy/aria/core/AriaManager.java | 41 ++++++---- .../arialyy/aria/core/command/CmdFactory.java | 4 +- .../aria/core/command/HighestPriorityCmd.java | 2 +- .../aria/core/download/DownloadTarget.java | 2 +- .../aria/core/download/DownloadTask.java | 35 ++++++--- .../aria/core/download/DownloadUtil.java | 26 ++++--- .../aria/core/download/SingleThreadTask.java | 76 ++++++++++++------- .../com/arialyy/aria/core/inf/AbsTarget.java | 2 +- .../com/arialyy/aria/core/inf/AbsTask.java | 4 + .../java/com/arialyy/aria/core/inf/ITask.java | 6 ++ .../aria/core/queue/DownloadTaskQueue.java | 6 +- .../arialyy/aria/core/queue/TaskFactory.java | 4 +- .../aria/core/queue/UploadTaskQueue.java | 4 +- .../aria/core/queue/pool/CachePool.java | 34 +++++++-- .../aria/core/queue/pool/ExecutePool.java | 11 ++- .../aria/core/scheduler/AbsSchedulers.java | 23 ++++-- .../core/scheduler/DownloadSchedulers.java | 4 +- .../aria/core/scheduler/UploadSchedulers.java | 4 +- .../java/com/arialyy/aria/orm/DbUtil.java | 4 +- .../java/com/arialyy/aria/orm/SqlHelper.java | 4 +- README.md | 9 ++- app/src/main/assets/aria_config.xml | 2 +- .../download/HighestPriorityActivity.java | 4 +- .../multi_download/MultiDownloadActivity.java | 10 ++- 24 files changed, 212 insertions(+), 109 deletions(-) diff --git a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java index 3b2f54bf..7c14afa0 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java @@ -36,6 +36,7 @@ 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; @@ -55,7 +56,7 @@ import org.xml.sax.SAXException; private static final String TAG = "AriaManager"; private static final String DOWNLOAD = "_download"; private static final String UPLOAD = "_upload"; - private static final Object LOCK = new Object(); + public static final Object LOCK = new Object(); public static final String DOWNLOAD_TEMP_DIR = "/Aria/temp/download/"; public static final String UPLOAD_TEMP_DIR = "/Aria/temp/upload/"; @SuppressLint("StaticFieldLeak") private static volatile AriaManager INSTANCE = null; @@ -85,20 +86,6 @@ import org.xml.sax.SAXException; return mReceivers; } - /** - * 加载配置文件 - */ - private void loadConfig() { - try { - ConfigHelper helper = new ConfigHelper(); - SAXParserFactory factory = SAXParserFactory.newInstance(); - SAXParser parser = factory.newSAXParser(); - parser.parse(APP.getAssets().open("aria_config.xml"), helper); - } catch (ParserConfigurationException | IOException | SAXException e) { - Log.e(TAG, e.toString()); - } - } - /** * 如果需要在代码中修改下载配置,请使用以下方法 *
@@ -255,7 +242,13 @@ import org.xml.sax.SAXException;
     } else {
       try {
         String md5Code = CommonUtil.getFileMD5(xmlFile);
-        if (!CommonUtil.checkMD5(md5Code, APP.getAssets().open("aria_config.xml"))) {
+        File file = new File(APP.getFilesDir().getPath() + "temp.xml");
+        if (file.exists()) {
+          file.delete();
+        }
+        CommonUtil.createFileFormInputStream(APP.getAssets().open("aria_config.xml"),
+            file.getPath());
+        if (!CommonUtil.checkMD5(md5Code, file)) {
           loadConfig();
         }
       } catch (IOException e) {
@@ -271,6 +264,22 @@ import org.xml.sax.SAXException;
     }
   }
 
+  /**
+   * 加载配置文件
+   */
+  private void loadConfig() {
+    try {
+      ConfigHelper helper = new ConfigHelper();
+      SAXParserFactory factory = SAXParserFactory.newInstance();
+      SAXParser parser = factory.newSAXParser();
+      parser.parse(APP.getAssets().open("aria_config.xml"), helper);
+      CommonUtil.createFileFormInputStream(APP.getAssets().open("aria_config.xml"),
+          APP.getFilesDir().getPath() + Configuration.XML_FILE);
+    } catch (ParserConfigurationException | IOException | SAXException e) {
+      Log.e(TAG, e.toString());
+    }
+  }
+
   /**
    * 注册APP生命周期回调
    */
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 7be00923..5be974de 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
@@ -16,6 +16,7 @@
 
 package com.arialyy.aria.core.command;
 
+import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.inf.AbsTaskEntity;
 
 /**
@@ -50,7 +51,6 @@ public class CmdFactory {
 
   public static final int TASK_SINGLE = 0x126;
 
-  private static final Object LOCK = new Object();
   private static volatile CmdFactory INSTANCE = null;
 
   private CmdFactory() {
@@ -59,7 +59,7 @@ public class CmdFactory {
 
   public static CmdFactory getInstance() {
     if (INSTANCE == null) {
-      synchronized (LOCK) {
+      synchronized (AriaManager.LOCK) {
         INSTANCE = new CmdFactory();
       }
     }
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 7a3147b2..74999611 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
@@ -26,7 +26,7 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
  * 2、最高优先级任务会一直存在,直到用户手动暂停或任务完成
  * 3、任务调度器不会暂停最高优先级任务
  * 4、用户手动暂停或任务完成后,第二次重新执行该任务,该命令将失效
- * 5、如果下载队列中已经满了,则会停止队尾的任务
+ * 5、如果下载队列中已经满了,则会停止队尾的任务,当高优先级任务完成后,该队尾任务将自动执行
  * 6、把任务设置为最高优先级任务后,将自动执行任务,不需要重新调用start()启动任务
  */
 final class HighestPriorityCmd extends AbsCmd {
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 44bc443c..05e6c2d9 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
@@ -50,7 +50,7 @@ public class DownloadTarget extends AbsTarget {
   private IDownloadListener mListener;
   private Handler mOutHandler;
   private IDownloadUtil mUtil;
+  private boolean isWait = false;
 
   private DownloadTask(DownloadTaskEntity taskEntity, Handler outHandler) {
     mEntity = taskEntity.downloadEntity;
@@ -78,15 +80,23 @@ public class DownloadTask extends AbsTask {
     return mEntity;
   }
 
+  /**
+   * 暂停任务,并让任务处于等待状态
+   */
+  @Override public void stopAndWait() {
+    super.stopAndWait();
+    stop(true);
+  }
 
   /**
    * 开始下载
    */
   @Override public void start() {
+    isWait = false;
     if (mUtil.isDownloading()) {
       Log.d(TAG, "任务正在下载");
     } else {
-      if (mListener == null) {
+      if (mListener == null || isWait) {
         mListener = new DListener(mContext, this, mOutHandler);
       }
       mUtil.startDownload();
@@ -97,10 +107,15 @@ public class DownloadTask extends AbsTask {
    * 停止下载
    */
   @Override public void stop() {
+    stop(false);
+  }
+
+  private void stop(boolean isWait) {
+    this.isWait = isWait;
     if (mUtil.isDownloading()) {
       mUtil.stopDownload();
     } else {
-      mEntity.setState(DownloadEntity.STATE_STOP);
+      mEntity.setState(isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP);
       mEntity.save();
       if (mOutHandler != null) {
         mOutHandler.obtainMessage(DownloadSchedulers.STOP, this).sendToTarget();
@@ -201,7 +216,7 @@ public class DownloadTask extends AbsTask {
 
     @Override public void onPre() {
       super.onPre();
-      downloadEntity.setState(DownloadEntity.STATE_PRE);
+      downloadEntity.setState(IEntity.STATE_PRE);
       sendInState2Target(ISchedulers.PRE);
       sendIntent(Aria.ACTION_PRE, -1);
     }
@@ -209,21 +224,21 @@ public class DownloadTask extends AbsTask {
     @Override public void onPostPre(long fileSize) {
       super.onPostPre(fileSize);
       downloadEntity.setFileSize(fileSize);
-      downloadEntity.setState(DownloadEntity.STATE_POST_PRE);
+      downloadEntity.setState(IEntity.STATE_POST_PRE);
       sendInState2Target(ISchedulers.POST_PRE);
       sendIntent(Aria.ACTION_POST_PRE, -1);
     }
 
     @Override public void onResume(long resumeLocation) {
       super.onResume(resumeLocation);
-      downloadEntity.setState(DownloadEntity.STATE_RUNNING);
+      downloadEntity.setState(IEntity.STATE_RUNNING);
       sendInState2Target(ISchedulers.RESUME);
       sendIntent(Aria.ACTION_RESUME, resumeLocation);
     }
 
     @Override public void onStart(long startLocation) {
       super.onStart(startLocation);
-      downloadEntity.setState(DownloadEntity.STATE_RUNNING);
+      downloadEntity.setState(IEntity.STATE_RUNNING);
       sendInState2Target(ISchedulers.START);
       sendIntent(Aria.ACTION_START, startLocation);
     }
@@ -249,7 +264,7 @@ public class DownloadTask extends AbsTask {
 
     @Override public void onStop(long stopLocation) {
       super.onStop(stopLocation);
-      downloadEntity.setState(DownloadEntity.STATE_STOP);
+      downloadEntity.setState(task.isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP);
       handleSpeed(0);
       sendInState2Target(ISchedulers.STOP);
       sendIntent(Aria.ACTION_STOP, stopLocation);
@@ -257,7 +272,7 @@ public class DownloadTask extends AbsTask {
 
     @Override public void onCancel() {
       super.onCancel();
-      downloadEntity.setState(DownloadEntity.STATE_CANCEL);
+      downloadEntity.setState(IEntity.STATE_CANCEL);
       handleSpeed(0);
       sendInState2Target(ISchedulers.CANCEL);
       sendIntent(Aria.ACTION_CANCEL, -1);
@@ -266,7 +281,7 @@ public class DownloadTask extends AbsTask {
 
     @Override public void onComplete() {
       super.onComplete();
-      downloadEntity.setState(DownloadEntity.STATE_COMPLETE);
+      downloadEntity.setState(IEntity.STATE_COMPLETE);
       downloadEntity.setDownloadComplete(true);
       handleSpeed(0);
       sendInState2Target(ISchedulers.COMPLETE);
@@ -276,7 +291,7 @@ public class DownloadTask extends AbsTask {
     @Override public void onFail() {
       super.onFail();
       downloadEntity.setFailNum(downloadEntity.getFailNum() + 1);
-      downloadEntity.setState(DownloadEntity.STATE_FAIL);
+      downloadEntity.setState(IEntity.STATE_FAIL);
       handleSpeed(0);
       sendInState2Target(ISchedulers.FAIL);
       sendIntent(Aria.ACTION_FAIL, -1);
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 7580849e..0dfda502 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
@@ -66,7 +66,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
     mDownloadTaskEntity = entity;
     mListener = downloadListener;
     // 线程下载数改变后,新的下载才会生效
-    mFixedThreadPool = Executors.newFixedThreadPool(Integer.MAX_VALUE);
+    //mFixedThreadPool = Executors.newFixedThreadPool(Integer.MAX_VALUE);
     CONSTANCE = new DownloadStateConstance();
     init();
   }
@@ -75,8 +75,10 @@ class DownloadUtil implements IDownloadUtil, Runnable {
     mConnectTimeOut = AriaManager.getInstance(mContext).getDownloadConfig().getConnectTimeOut();
     mDownloadFile = new File(mDownloadTaskEntity.downloadEntity.getDownloadPath());
     //读取已完成的线程数
-    mConfigFile = new File(
-        mContext.getFilesDir().getPath() + AriaManager.DOWNLOAD_TEMP_DIR + mDownloadFile.getName() + ".properties");
+    mConfigFile = new File(mContext.getFilesDir().getPath()
+        + AriaManager.DOWNLOAD_TEMP_DIR
+        + mDownloadFile.getName()
+        + ".properties");
     try {
       if (!mConfigFile.exists()) { //记录文件被删除,则重新下载
         handleNewTask();
@@ -111,7 +113,9 @@ class DownloadUtil implements IDownloadUtil, Runnable {
   @Override public void cancelDownload() {
     CONSTANCE.isCancel = true;
     CONSTANCE.isDownloading = false;
-    mFixedThreadPool.shutdown();
+    if (mFixedThreadPool != null) {
+      mFixedThreadPool.shutdown();
+    }
     for (int i = 0; i < THREAD_NUM; i++) {
       SingleThreadTask task = (SingleThreadTask) mTask.get(i);
       if (task != null) {
@@ -126,7 +130,9 @@ class DownloadUtil implements IDownloadUtil, Runnable {
   @Override public void stopDownload() {
     CONSTANCE.isStop = true;
     CONSTANCE.isDownloading = false;
-    mFixedThreadPool.shutdown();
+    if (mFixedThreadPool != null) {
+      mFixedThreadPool.shutdown();
+    }
     for (int i = 0; i < THREAD_NUM; i++) {
       SingleThreadTask task = (SingleThreadTask) mTask.get(i);
       if (task != null) {
@@ -304,7 +310,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
       if (!isNewTask && record != null && Long.parseLong(record + "") > 0) {
         Long r = Long.parseLong(record + "");
         CONSTANCE.CURRENT_LOCATION += r - startL;
-        Log.d(TAG, "++++++++++ 线程_" + i + "_恢复下载 ++++++++++");
+        Log.d(TAG, "任务【" + mDownloadEntity.getFileName() + "】线程__" + i + "__恢复下载");
         mListener.onChildResume(r);
         startL = r;
         recordL[rl] = i;
@@ -374,7 +380,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
           num++;
         }
       }
-      if (num == 0){
+      if (num == 0) {
         handleNewTask();
         return pro;
       }
@@ -386,9 +392,10 @@ class DownloadUtil implements IDownloadUtil, Runnable {
             continue;
           }
           handleNewTask();
-          break;
+          return pro;
         }
       }
+      isNewTask = false;
     }
     return pro;
   }
@@ -452,10 +459,11 @@ class DownloadUtil implements IDownloadUtil, Runnable {
     } 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.isShutdown()) {
+      if (task != null) {
         mFixedThreadPool.execute(task);
       }
     }
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 267b7926..973a956f 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
@@ -15,6 +15,7 @@
  */
 package com.arialyy.aria.core.download;
 
+import android.text.TextUtils;
 import android.util.Log;
 import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.util.BufferedRandomAccessFile;
@@ -36,7 +37,6 @@ final class SingleThreadTask implements Runnable {
   private DownloadUtil.ConfigEntity mConfigEntity;
   private String mConfigFPath;
   private long mChildCurrentLocation = 0;
-  private static final Object LOCK = new Object();
   private int mBufSize;
   private IDownloadListener mListener;
   private DownloadStateConstance CONSTANCE;
@@ -62,9 +62,11 @@ final class SingleThreadTask implements Runnable {
       URL url = new URL(mConfigEntity.DOWNLOAD_URL);
       conn = ConnectionHelp.handleConnection(url);
       if (mConfigEntity.isSupportBreakpoint) {
-        Log.d(TAG, "线程_"
+        Log.d(TAG, "任务【"
+            + mConfigEntity.TEMP_FILE.getName()
+            + "】线程__"
             + mConfigEntity.THREAD_ID
-            + "_正在下载【开始位置 : "
+            + "__开始下载【开始位置 : "
             + mConfigEntity.START_LOCATION
             + ",结束位置:"
             + mConfigEntity.END_LOCATION
@@ -112,9 +114,12 @@ final class SingleThreadTask implements Runnable {
       }
       //支持断点的处理
       if (mConfigEntity.isSupportBreakpoint) {
-        Log.i(TAG,
-            "任务【" + mConfigEntity.TEMP_FILE.getName() + "】线程【" + mConfigEntity.THREAD_ID + "】下载完毕");
-        writeConfig(1);
+        Log.i(TAG, "任务【"
+            + mConfigEntity.TEMP_FILE.getName()
+            + "】线程__"
+            + mConfigEntity.THREAD_ID
+            + "__下载完毕");
+        writeConfig(true, 1);
         mListener.onChildComplete(mConfigEntity.END_LOCATION);
         CONSTANCE.COMPLETE_THREAD_NUM++;
         if (CONSTANCE.isComplete()) {
@@ -143,22 +148,24 @@ final class SingleThreadTask implements Runnable {
    * 停止下载
    */
   protected void stop() {
-    synchronized (LOCK) {
+    synchronized (AriaManager.LOCK) {
       try {
         if (mConfigEntity.isSupportBreakpoint) {
           CONSTANCE.STOP_NUM++;
-          Log.d(TAG, "thread_"
+          Log.d(TAG, "任务【"
+              + mConfigEntity.TEMP_FILE.getName()
+              + "】thread__"
               + mConfigEntity.THREAD_ID
-              + "_stop, stop location ==> "
+              + "__停止, stop location ==> "
               + mChildCurrentLocation);
-          writeConfig(mChildCurrentLocation);
+          writeConfig(false, mChildCurrentLocation);
           if (CONSTANCE.isStop()) {
-            Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++");
+            Log.d(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】已停止");
             CONSTANCE.isDownloading = false;
             mListener.onStop(CONSTANCE.CURRENT_LOCATION);
           }
         } else {
-          Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++");
+          Log.d(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】已停止");
           CONSTANCE.isDownloading = false;
           mListener.onStop(CONSTANCE.CURRENT_LOCATION);
         }
@@ -172,7 +179,7 @@ final class SingleThreadTask implements Runnable {
    * 下载中
    */
   private void progress(long len) {
-    synchronized (LOCK) {
+    synchronized (AriaManager.LOCK) {
       mChildCurrentLocation += len;
       CONSTANCE.CURRENT_LOCATION += len;
       mListener.onProgress(CONSTANCE.CURRENT_LOCATION);
@@ -183,10 +190,14 @@ final class SingleThreadTask implements Runnable {
    * 取消下载
    */
   protected void cancel() {
-    synchronized (LOCK) {
+    synchronized (AriaManager.LOCK) {
       if (mConfigEntity.isSupportBreakpoint) {
         CONSTANCE.CANCEL_NUM++;
-        Log.d(TAG, "++++++++++ thread_" + mConfigEntity.THREAD_ID + "_cancel ++++++++++");
+        Log.d(TAG, "任务【"
+            + mConfigEntity.TEMP_FILE.getName()
+            + "】thread__"
+            + mConfigEntity.THREAD_ID
+            + "__取消下载");
         if (CONSTANCE.isCancel()) {
           File configFile = new File(mConfigFPath);
           if (configFile.exists()) {
@@ -195,12 +206,12 @@ final class SingleThreadTask implements Runnable {
           if (mConfigEntity.TEMP_FILE.exists()) {
             mConfigEntity.TEMP_FILE.delete();
           }
-          Log.d(TAG, "++++++++++++++++ onCancel +++++++++++++++++");
+          Log.d(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】已取消");
           CONSTANCE.isDownloading = false;
           mListener.onCancel();
         }
       } else {
-        Log.d(TAG, "++++++++++++++++ onCancel +++++++++++++++++");
+        Log.d(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】已取消");
         CONSTANCE.isDownloading = false;
         mListener.onCancel();
       }
@@ -211,7 +222,7 @@ final class SingleThreadTask implements Runnable {
    * 下载失败
    */
   private void failDownload(long currentLocation, String msg, Exception ex) {
-    synchronized (LOCK) {
+    synchronized (AriaManager.LOCK) {
       try {
         CONSTANCE.FAIL_NUM++;
         CONSTANCE.isDownloading = false;
@@ -220,13 +231,13 @@ final class SingleThreadTask implements Runnable {
           Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex));
         }
         if (mConfigEntity.isSupportBreakpoint) {
-          writeConfig(currentLocation);
+          writeConfig(false, currentLocation);
           if (CONSTANCE.isFail()) {
-            Log.d(TAG, "++++++++++++++++ onFail +++++++++++++++++");
+            Log.e(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】下载失败");
             mListener.onFail();
           }
         } else {
-          Log.d(TAG, "++++++++++++++++ onFail +++++++++++++++++");
+          Log.e(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】下载失败");
           mListener.onFail();
         }
       } catch (IOException e) {
@@ -238,13 +249,22 @@ final class SingleThreadTask implements Runnable {
   /**
    * 将记录写入到配置文件
    */
-  private void writeConfig(long record) throws IOException {
-    if (record > 0) {
-      String key = mConfigEntity.TEMP_FILE.getName() + "_record_" + mConfigEntity.THREAD_ID;
-      File configFile = new File(mConfigFPath);
-      Properties pro = CommonUtil.loadConfig(configFile);
-      pro.setProperty(key, String.valueOf(record));
-      CommonUtil.saveConfig(configFile, pro);
+  private void writeConfig(boolean isComplete, long record) throws IOException {
+    synchronized (AriaManager.LOCK) {
+      String key = null, value = null;
+      if (0 < record && record < mConfigEntity.END_LOCATION) {
+        key = mConfigEntity.TEMP_FILE.getName() + "_record_" + mConfigEntity.THREAD_ID;
+        value = String.valueOf(record);
+      } else if (record >= mConfigEntity.END_LOCATION || isComplete) {
+        key = mConfigEntity.TEMP_FILE.getName() + "_state_" + mConfigEntity.THREAD_ID;
+        value = "1";
+      }
+      if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
+        File configFile = new File(mConfigFPath);
+        Properties pro = CommonUtil.loadConfig(configFile);
+        pro.setProperty(key, value);
+        CommonUtil.saveConfig(configFile, pro);
+      }
     }
   }
 }
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 779a178c..7edcb91e 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
@@ -53,7 +53,7 @@ public abstract class AbsTarget
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 8d1aeca8..c8b4efa2 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
@@ -21,6 +21,11 @@ package com.arialyy.aria.core.inf;
 
 public interface ITask {
 
+  /**
+   * 暂停任务,并让任务处于等待状态
+   */
+  public void stopAndWait();
+
   /**
    * 设置任务为最高优先级任务,在下载队列中,有且只有一个最高优先级任务
    */
@@ -88,6 +93,7 @@ public interface ITask {
 
   /**
    * 获取单位转换后的进度
+   *
    * @return 返回 3mb
    */
   public String getConvertCurrentProgress();
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 0a8aa594..1dfe99de 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
@@ -37,11 +37,10 @@ public class DownloadTaskQueue
     extends AbsTaskQueue {
   private static final String TAG = "DownloadTaskQueue";
   private static volatile DownloadTaskQueue INSTANCE = null;
-  private static final Object LOCK = new Object();
 
   public static DownloadTaskQueue getInstance() {
     if (INSTANCE == null) {
-      synchronized (LOCK) {
+      synchronized (AriaManager.LOCK) {
         INSTANCE = new DownloadTaskQueue();
       }
     }
@@ -77,7 +76,8 @@ public class DownloadTaskQueue
         DownloadTask oldTsk = mExecutePool.pollTask();
         if (oldTsk != null && oldTsk.isRunning()) {
           if (i == maxSize - 1) {
-            oldTsk.stop();
+            oldTsk.stopAndWait();
+            mCachePool.putTaskToFirst(oldTsk);
             break;
           }
           tempTasks.add(oldTsk);
diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/TaskFactory.java b/Aria/src/main/java/com/arialyy/aria/core/queue/TaskFactory.java
index acd44dd5..ed67ec95 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/queue/TaskFactory.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/queue/TaskFactory.java
@@ -16,6 +16,7 @@
 
 package com.arialyy.aria.core.queue;
 
+import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.download.DownloadTask;
 import com.arialyy.aria.core.download.DownloadTaskEntity;
 import com.arialyy.aria.core.inf.ITask;
@@ -32,7 +33,6 @@ import com.arialyy.aria.core.upload.UploadTaskEntity;
 public class TaskFactory {
   private static final String TAG = "TaskFactory";
 
-  private static final Object LOCK = new Object();
   private static volatile TaskFactory INSTANCE = null;
 
   private TaskFactory() {
@@ -41,7 +41,7 @@ public class TaskFactory {
 
   public static TaskFactory getInstance() {
     if (INSTANCE == null) {
-      synchronized (LOCK) {
+      synchronized (AriaManager.LOCK) {
         INSTANCE = new TaskFactory();
       }
     }
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 011f0d48..2b56ac84 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
@@ -18,6 +18,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.scheduler.UploadSchedulers;
 import com.arialyy.aria.core.upload.UploadEntity;
@@ -31,11 +32,10 @@ import com.arialyy.aria.core.upload.UploadTaskEntity;
 public class UploadTaskQueue extends AbsTaskQueue {
   private static final String TAG = "UploadTaskQueue";
   private static volatile UploadTaskQueue INSTANCE = null;
-  private static final Object LOCK = new Object();
 
   public static UploadTaskQueue getInstance() {
     if (INSTANCE == null) {
-      synchronized (LOCK) {
+      synchronized (AriaManager.LOCK) {
         INSTANCE = new UploadTaskQueue();
       }
     }
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/CachePool.java
index fb46b434..586839a9 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/CachePool.java
@@ -18,10 +18,13 @@ package com.arialyy.aria.core.queue.pool;
 
 import android.text.TextUtils;
 import android.util.Log;
+import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.inf.ITask;
 import com.arialyy.aria.util.CommonUtil;
 import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 
@@ -31,7 +34,6 @@ import java.util.concurrent.TimeUnit;
  */
 public class CachePool implements IPool {
   private static final String TAG = "CachePool";
-  private static final Object LOCK = new Object();
   private static final int MAX_NUM = Integer.MAX_VALUE;  //最大下载任务数
   private static final long TIME_OUT = 1000;
   private Map mCacheMap;
@@ -49,8 +51,28 @@ public class CachePool implements IPool {
     return mCacheMap;
   }
 
+  /**
+   * 将任务放在队首
+   */
+  public boolean putTaskToFirst(TASK task) {
+    if (mCacheQueue.isEmpty()) {
+      return putTask(task);
+    } else {
+      Set temps = new LinkedHashSet<>();
+      temps.add(task);
+      for (int i = 0, len = size(); i < len; i++) {
+        TASK temp = pollTask();
+        temps.add(temp);
+      }
+      for (TASK t : temps) {
+        putTask(t);
+      }
+      return true;
+    }
+  }
+
   @Override public boolean putTask(TASK task) {
-    synchronized (LOCK) {
+    synchronized (AriaManager.LOCK) {
       if (task == null) {
         Log.e(TAG, "下载任务不能为空!!");
         return false;
@@ -71,7 +93,7 @@ public class CachePool implements IPool {
   }
 
   @Override public TASK pollTask() {
-    synchronized (LOCK) {
+    synchronized (AriaManager.LOCK) {
       try {
         TASK task = null;
         task = mCacheQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
@@ -88,7 +110,7 @@ public class CachePool implements IPool {
   }
 
   @Override public TASK getTask(String downloadUrl) {
-    synchronized (LOCK) {
+    synchronized (AriaManager.LOCK) {
       if (TextUtils.isEmpty(downloadUrl)) {
         Log.e(TAG, "请传入有效的下载链接");
         return null;
@@ -99,7 +121,7 @@ public class CachePool implements IPool {
   }
 
   @Override public boolean removeTask(TASK task) {
-    synchronized (LOCK) {
+    synchronized (AriaManager.LOCK) {
       if (task == null) {
         Log.e(TAG, "任务不能为空");
         return false;
@@ -112,7 +134,7 @@ public class CachePool implements IPool {
   }
 
   @Override public boolean removeTask(String downloadUrl) {
-    synchronized (LOCK) {
+    synchronized (AriaManager.LOCK) {
       if (TextUtils.isEmpty(downloadUrl)) {
         Log.e(TAG, "请传入有效的下载链接");
         return false;
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 0ae398c1..4f9691af 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
@@ -33,7 +33,6 @@ import java.util.concurrent.TimeUnit;
  */
 public class ExecutePool implements IPool {
   private static final String TAG = "ExecutePool";
-  private static final Object LOCK = new Object();
   private static final long TIME_OUT = 1000;
   private ArrayBlockingQueue mExecuteQueue;
   private Map mExecuteMap;
@@ -57,7 +56,7 @@ public class ExecutePool implements IPool {
   }
 
   @Override public boolean putTask(TASK task) {
-    synchronized (LOCK) {
+    synchronized (AriaManager.LOCK) {
       if (task == null) {
         Log.e(TAG, "任务不能为空!!");
         return false;
@@ -141,7 +140,7 @@ public class ExecutePool implements IPool {
   }
 
   @Override public TASK pollTask() {
-    synchronized (LOCK) {
+    synchronized (AriaManager.LOCK) {
       try {
         TASK task = null;
         task = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
@@ -158,7 +157,7 @@ public class ExecutePool implements IPool {
   }
 
   @Override public TASK getTask(String downloadUrl) {
-    synchronized (LOCK) {
+    synchronized (AriaManager.LOCK) {
       if (TextUtils.isEmpty(downloadUrl)) {
         Log.e(TAG, "请传入有效的任务key");
         return null;
@@ -169,7 +168,7 @@ public class ExecutePool implements IPool {
   }
 
   @Override public boolean removeTask(TASK task) {
-    synchronized (LOCK) {
+    synchronized (AriaManager.LOCK) {
       if (task == null) {
         Log.e(TAG, "任务不能为空");
         return false;
@@ -182,7 +181,7 @@ public class ExecutePool implements IPool {
   }
 
   @Override public boolean removeTask(String downloadUrl) {
-    synchronized (LOCK) {
+    synchronized (AriaManager.LOCK) {
       if (TextUtils.isEmpty(downloadUrl)) {
         Log.e(TAG, "请传入有效的任务key");
         return false;
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 f8f26021..4fee513f 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
@@ -19,11 +19,13 @@ import android.os.CountDownTimer;
 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.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;
 import java.util.Map;
 import java.util.Set;
@@ -65,6 +67,9 @@ public abstract class AbsSchedulers {
 
   private static final String TAG = "DownloadSchedulers";
-  private static final Object LOCK = new Object();
   private static volatile DownloadSchedulers INSTANCE = null;
 
   private DownloadSchedulers() {
@@ -38,7 +38,7 @@ public class DownloadSchedulers
 
   public static DownloadSchedulers getInstance() {
     if (INSTANCE == null) {
-      synchronized (LOCK) {
+      synchronized (AriaManager.LOCK) {
         INSTANCE = new DownloadSchedulers();
       }
     }
diff --git a/Aria/src/main/java/com/arialyy/aria/core/scheduler/UploadSchedulers.java b/Aria/src/main/java/com/arialyy/aria/core/scheduler/UploadSchedulers.java
index 5401bc1a..37a6e3d0 100644
--- a/Aria/src/main/java/com/arialyy/aria/core/scheduler/UploadSchedulers.java
+++ b/Aria/src/main/java/com/arialyy/aria/core/scheduler/UploadSchedulers.java
@@ -15,6 +15,7 @@
  */
 package com.arialyy.aria.core.scheduler;
 
+import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.core.queue.UploadTaskQueue;
 import com.arialyy.aria.core.upload.UploadEntity;
 import com.arialyy.aria.core.upload.UploadTask;
@@ -27,7 +28,6 @@ import com.arialyy.aria.core.upload.UploadTaskEntity;
 public class UploadSchedulers
     extends AbsSchedulers {
   private static final String TAG = "UploadSchedulers";
-  private static final Object LOCK = new Object();
   private static volatile UploadSchedulers INSTANCE = null;
 
   private UploadSchedulers() {
@@ -36,7 +36,7 @@ public class UploadSchedulers
 
   public static UploadSchedulers getInstance() {
     if (INSTANCE == null) {
-      synchronized (LOCK) {
+      synchronized (AriaManager.LOCK) {
         INSTANCE = new UploadSchedulers();
       }
     }
diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DbUtil.java b/Aria/src/main/java/com/arialyy/aria/orm/DbUtil.java
index b24cbd15..e02fd7d4 100644
--- a/Aria/src/main/java/com/arialyy/aria/orm/DbUtil.java
+++ b/Aria/src/main/java/com/arialyy/aria/orm/DbUtil.java
@@ -22,6 +22,7 @@ import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.support.annotation.NonNull;
 import android.util.Log;
+import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.util.CheckUtil;
 import com.arialyy.aria.util.CommonUtil;
 import java.util.List;
@@ -32,7 +33,6 @@ import java.util.List;
  */
 public class DbUtil {
   private static final String TAG = "DbUtil";
-  private static final Object LOCK = new Object();
   private volatile static DbUtil INSTANCE = null;
   private int ROW_ID = 7;
   private SQLiteDatabase mDb;
@@ -48,7 +48,7 @@ public class DbUtil {
 
   public static DbUtil init(Context context) {
     if (context instanceof Application) {
-      synchronized (LOCK) {
+      synchronized (AriaManager.LOCK) {
         if (INSTANCE == null) {
           INSTANCE = new DbUtil(context);
         }
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 f3f82bde..784900b1 100644
--- a/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
+++ b/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
@@ -23,6 +23,7 @@ import android.database.sqlite.SQLiteOpenHelper;
 import android.support.annotation.NonNull;
 import android.text.TextUtils;
 import android.util.Log;
+import com.arialyy.aria.core.AriaManager;
 import com.arialyy.aria.util.CheckUtil;
 import com.arialyy.aria.util.CommonUtil;
 import java.lang.reflect.Field;
@@ -47,11 +48,10 @@ final class SqlHelper extends SQLiteOpenHelper {
   private static final int DEL_DATA = 6;
 
   private static volatile SqlHelper INSTANCE = null;
-  private static final Object LOCK = new Object();
 
   static SqlHelper init(Context context) {
     if (INSTANCE == null) {
-      synchronized (LOCK) {
+      synchronized (AriaManager.LOCK) {
         INSTANCE = new SqlHelper(context.getApplicationContext());
         checkTable(INSTANCE.getWritableDatabase());
       }
diff --git a/README.md b/README.md
index a9e2a00f..25396481 100644
--- a/README.md
+++ b/README.md
@@ -159,7 +159,7 @@ compile 'com.arialyy.aria:Aria:3.1.4'
     
 
     
-    
+    
 
   
 
@@ -226,6 +226,11 @@ Aria.download(this).removeAllTask();
   int percent = task.getPercent();
 }
 ```
+* 设置高优先级任务
+如果你希望优先下载某一个任务,你可以
+``` java
+Aria.download(this).load(DOWNLOAD_URL).setDownloadPath(PATH).setHighestPriority();
+```
 
 **tips:为了防止内存泄露的情况,事件类需要使用staic进行修饰**
 
@@ -272,8 +277,8 @@ Aria.download(this).removeAllTask();
 
 
 ## 开发日志
+  + v_3.1.5 优化代码结构,增加优先下载任务功能。
   + v_3.1.4 修复快速切换,暂停、恢复功能时,概率性出现的重新下载问题,添加onPre()回调,onPre()用于请求地址之前执行界面UI更新操作。
-  + v_3.1.2 优化代码结构
   + v_3.1.0 添加Aria配置文件,优化代码
   + v_3.0.3 修复暂停后删除任务,闪退问题,添加删除记录的api
   + v_3.0.2 支持30x重定向链接下载
diff --git a/app/src/main/assets/aria_config.xml b/app/src/main/assets/aria_config.xml
index 0c860dd8..01c497ee 100644
--- a/app/src/main/assets/aria_config.xml
+++ b/app/src/main/assets/aria_config.xml
@@ -17,7 +17,7 @@
     
 
     
-    
+    
 
     
     
diff --git a/app/src/main/java/com/arialyy/simple/download/HighestPriorityActivity.java b/app/src/main/java/com/arialyy/simple/download/HighestPriorityActivity.java
index 38b365e5..aee06f79 100644
--- a/app/src/main/java/com/arialyy/simple/download/HighestPriorityActivity.java
+++ b/app/src/main/java/com/arialyy/simple/download/HighestPriorityActivity.java
@@ -79,7 +79,7 @@ public class HighestPriorityActivity extends BaseActivity {
   @Bind(R.id.list) RecyclerView mList;
   private DownloadAdapter mAdapter;
+  private List mData = new ArrayList<>();
 
   @Override protected int setLayoutId() {
     return R.layout.activity_multi_download;
@@ -43,7 +47,11 @@ public class MultiDownloadActivity extends BaseActivity temps = Aria.download(this).getTaskList();
+    if (temps != null && !temps.isEmpty()) {
+      mData.addAll(temps);
+    }
+    mAdapter = new DownloadAdapter(this, mData);
     mList.setLayoutManager(new LinearLayoutManager(this));
     mList.setAdapter(mAdapter);
   }