diff --git a/downloadutil/src/main/java/com/arialyy/downloadutil/core/Task.java b/downloadutil/src/main/java/com/arialyy/downloadutil/core/Task.java index fcfd98c7..a97d22a6 100644 --- a/downloadutil/src/main/java/com/arialyy/downloadutil/core/Task.java +++ b/downloadutil/src/main/java/com/arialyy/downloadutil/core/Task.java @@ -2,13 +2,12 @@ package com.arialyy.downloadutil.core; import android.content.Context; import android.content.Intent; -import android.database.sqlite.SQLiteDatabase; import android.os.Handler; import android.util.Log; import com.arialyy.downloadutil.DownloadManager; import com.arialyy.downloadutil.entity.DownloadEntity; -import com.arialyy.downloadutil.inf.IDownloadListener; +import com.arialyy.downloadutil.util.IDownloadListener; import com.arialyy.downloadutil.util.DownLoadUtil; import java.net.HttpURLConnection; @@ -43,6 +42,10 @@ public class Task { } } + public DownloadEntity getDownloadEntity() { + return downloadEntity; + } + /** * 停止下载 */ diff --git a/downloadutil/src/main/java/com/arialyy/downloadutil/core/inf/IPool.java b/downloadutil/src/main/java/com/arialyy/downloadutil/core/inf/IPool.java index 5cb92b62..3e4aed3c 100644 --- a/downloadutil/src/main/java/com/arialyy/downloadutil/core/inf/IPool.java +++ b/downloadutil/src/main/java/com/arialyy/downloadutil/core/inf/IPool.java @@ -12,13 +12,20 @@ public interface IPool { * * @param task */ - public void putTask(Task task); + public boolean putTask(Task task); /** - * 通过下载链接获取下载任务 + * 按照队列原则取出下载任务 + * + * @return 返回null或者下载任务 + */ + public Task pollTask(); + + /** + * 通过下载链接获取下载任务,当任务不为空时,队列将删除该下载任务 * * @param downloadUrl 下载链接 - * @return 下载任务 + * @return 返回null或者下载任务 */ public Task getTask(String downloadUrl); diff --git a/downloadutil/src/main/java/com/arialyy/downloadutil/core/pool/CachePool.java b/downloadutil/src/main/java/com/arialyy/downloadutil/core/pool/CachePool.java index 2c5c5ea6..5f3d721a 100644 --- a/downloadutil/src/main/java/com/arialyy/downloadutil/core/pool/CachePool.java +++ b/downloadutil/src/main/java/com/arialyy/downloadutil/core/pool/CachePool.java @@ -1,27 +1,99 @@ package com.arialyy.downloadutil.core.pool; +import android.util.Log; + import com.arialyy.downloadutil.core.Task; import com.arialyy.downloadutil.core.inf.IPool; +import com.arialyy.downloadutil.util.Util; + +import java.util.HashMap; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.Queue; /** * Created by lyy on 2016/8/14. * 任务缓存池,所有下载任务最先缓存在这个池中 */ public class CachePool implements IPool { + private static final String TAG = "CachePool"; + private static final Object LOCK = new Object(); + private static volatile CachePool INSTANCE = null; + private Map mCacheArray; + private Queue mCacheQueue; + public static CachePool getInstance() { + if (INSTANCE == null) { + synchronized (LOCK) { + INSTANCE = new CachePool(); + } + } + return INSTANCE; + } + + private CachePool() { + mCacheQueue = new PriorityQueue<>(); + mCacheArray = new HashMap<>(); + } @Override - public synchronized void putTask(Task task) { + public boolean putTask(Task task) { + synchronized (LOCK) { + if (task == null) { + Log.e(TAG, "下载任务不能为空!!"); + return false; + } + String url = task.getDownloadEntity().getDownloadUrl(); + if (mCacheQueue.contains(task)) { + Log.e(TAG, "队列中已经包含了该任务,任务下载链接【" + url + "】"); + return false; + } else { + boolean s = mCacheQueue.offer(task); + Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】")); + if (s) { + mCacheArray.put(Util.keyToHashKey(url), task); + } + return s; + } + } + } + @Override + public Task pollTask() { + synchronized (LOCK) { + Task task = mCacheQueue.poll(); + if (task != null) { + String url = task.getDownloadEntity().getDownloadUrl(); + mCacheArray.remove(Util.keyToHashKey(url)); + } + return task; + } } @Override - public synchronized Task getTask(String downloadUrl) { - return null; + public Task getTask(String downloadUrl) { + synchronized (LOCK) { + String key = Util.keyToHashKey(downloadUrl); + Task task = mCacheArray.get(key); + if (task != null) { + mCacheArray.remove(key); + mCacheQueue.remove(task); + } + return task; + } } @Override - public synchronized boolean removeTask(Task task) { - return false; + public boolean removeTask(Task task) { + synchronized (LOCK) { + if (task == null) { + Log.e(TAG, "任务不能为空"); + return false; + } else { + String key = Util.keyToHashKey(task.getDownloadEntity().getDownloadUrl()); + mCacheArray.remove(key); + return mCacheQueue.remove(task); + } + } } } diff --git a/downloadutil/src/main/java/com/arialyy/downloadutil/core/pool/ExecutePool.java b/downloadutil/src/main/java/com/arialyy/downloadutil/core/pool/ExecutePool.java new file mode 100644 index 00000000..012d6efd --- /dev/null +++ b/downloadutil/src/main/java/com/arialyy/downloadutil/core/pool/ExecutePool.java @@ -0,0 +1,144 @@ +package com.arialyy.downloadutil.core.pool; + +import android.util.Log; + +import com.arialyy.downloadutil.core.Task; +import com.arialyy.downloadutil.core.inf.IPool; +import com.arialyy.downloadutil.util.Util; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * Created by lyy on 2016/8/15. + * 任务执行池,所有当前下载任务都该任务池中,默认下载大小为2 + */ +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 static volatile ExecutePool INSTANCE = null; + private static int SIZE = 2; + private ArrayBlockingQueue mExecuteQueue; + private Map mExecuteArray; + + public static ExecutePool getInstance() { + if (INSTANCE == null) { + synchronized (LOCK) { + INSTANCE = new ExecutePool(); + } + } + return INSTANCE; + } + + private ExecutePool() { + mExecuteQueue = new ArrayBlockingQueue<>(SIZE); + mExecuteArray = new HashMap<>(); + } + + @Override + public boolean putTask(Task task) { + synchronized (LOCK) { + if (task == null) { + Log.e(TAG, "下载任务不能为空!!"); + return false; + } + String url = task.getDownloadEntity().getDownloadUrl(); + if (mExecuteQueue.contains(task)) { + Log.e(TAG, "队列中已经包含了该任务,任务下载链接【" + url + "】"); + return false; + } else { + if (mExecuteQueue.size() >= SIZE) { + if (pollFirstTask()) { + return putNewTask(task); + } + } else { + return putNewTask(task); + } + } + } + return false; + } + + /** + * 添加新任务 + * + * @param newTask 新下载任务 + */ + private boolean putNewTask(Task newTask) { + String url = newTask.getDownloadEntity().getDownloadUrl(); + boolean s = mExecuteQueue.offer(newTask); + Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】")); + if (s) { + newTask.start(); + mExecuteArray.put(Util.keyToHashKey(url), newTask); + } + return s; + } + + /** + * 队列满时,将移除下载队列中的第一个任务 + */ + private boolean pollFirstTask() { + try { + Task oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS); + if (oldTask == null) { + Log.e(TAG, "移除任务失败"); + return false; + } + oldTask.stop(); + wait(200); + String key = Util.keyToHashKey(oldTask.getDownloadEntity().getDownloadUrl()); + mExecuteArray.remove(key); + } catch (InterruptedException e) { + e.printStackTrace(); + return false; + } + return true; + } + + @Override + public Task pollTask() { + synchronized (LOCK) { + Task task = mExecuteQueue.poll(); + if (task != null) { + task.stop(); + String url = task.getDownloadEntity().getDownloadUrl(); + mExecuteArray.remove(Util.keyToHashKey(url)); + } + return task; + } + } + + @Override + public Task getTask(String downloadUrl) { + synchronized (LOCK) { + String key = Util.keyToHashKey(downloadUrl); + Task task = mExecuteArray.get(key); + if (task != null) { + task.stop(); + mExecuteArray.remove(key); + mExecuteQueue.remove(task); + } + return task; + } + } + + @Override + public boolean removeTask(Task task) { + synchronized (LOCK) { + if (task == null) { + Log.e(TAG, "任务不能为空"); + return false; + } else { + task.stop(); + String key = Util.keyToHashKey(task.getDownloadEntity().getDownloadUrl()); + mExecuteArray.remove(key); + return mExecuteQueue.remove(task); + } + } + } + +} diff --git a/downloadutil/src/main/java/com/arialyy/downloadutil/util/DownLoadUtil.java b/downloadutil/src/main/java/com/arialyy/downloadutil/util/DownLoadUtil.java index 5e3edb94..9f3628bf 100644 --- a/downloadutil/src/main/java/com/arialyy/downloadutil/util/DownLoadUtil.java +++ b/downloadutil/src/main/java/com/arialyy/downloadutil/util/DownLoadUtil.java @@ -5,8 +5,6 @@ import android.support.annotation.NonNull; import android.util.Log; import android.util.SparseArray; -import com.arialyy.downloadutil.inf.IDownloadListener; - import java.io.File; import java.io.IOException; import java.io.InputStream; diff --git a/downloadutil/src/main/java/com/arialyy/downloadutil/inf/IDownloadListener.java b/downloadutil/src/main/java/com/arialyy/downloadutil/util/IDownloadListener.java similarity index 96% rename from downloadutil/src/main/java/com/arialyy/downloadutil/inf/IDownloadListener.java rename to downloadutil/src/main/java/com/arialyy/downloadutil/util/IDownloadListener.java index 4999a55f..cf9fab05 100644 --- a/downloadutil/src/main/java/com/arialyy/downloadutil/inf/IDownloadListener.java +++ b/downloadutil/src/main/java/com/arialyy/downloadutil/util/IDownloadListener.java @@ -1,4 +1,4 @@ -package com.arialyy.downloadutil.inf; +package com.arialyy.downloadutil.util; import java.net.HttpURLConnection; diff --git a/downloadutil/src/main/java/com/arialyy/downloadutil/util/Util.java b/downloadutil/src/main/java/com/arialyy/downloadutil/util/Util.java index 819f310f..ee06cc8d 100644 --- a/downloadutil/src/main/java/com/arialyy/downloadutil/util/Util.java +++ b/downloadutil/src/main/java/com/arialyy/downloadutil/util/Util.java @@ -10,6 +10,8 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.math.BigDecimal; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.Properties; /** @@ -18,6 +20,44 @@ import java.util.Properties; public class Util { private static final String TAG = "util"; + /** + * 将缓存的key转换为hash码 + * + * @param key 缓存的key + * @return 转换后的key的值, 系统便是通过该key来读写缓存 + */ + public static String keyToHashKey(String key) { + String cacheKey; + try { + final MessageDigest mDigest = MessageDigest.getInstance("MD5"); + mDigest.update(key.getBytes()); + cacheKey = bytesToHexString(mDigest.digest()); + } catch (NoSuchAlgorithmException e) { + cacheKey = String.valueOf(key.hashCode()); + } + return cacheKey; + } + + /** + * 将普通字符串转换为16位进制字符串 + * + * @param src + * @return + */ + public static String bytesToHexString(byte[] src) { + StringBuilder stringBuilder = new StringBuilder("0x"); + if (src == null || src.length <= 0) { + return null; + } + char[] buffer = new char[2]; + for (byte aSrc : src) { + buffer[0] = Character.forDigit((aSrc >>> 4) & 0x0F, 16); + buffer[1] = Character.forDigit(aSrc & 0x0F, 16); + stringBuilder.append(buffer); + } + return stringBuilder.toString(); + } + /** * 获取类里面的所在字段 */