/* ShengDao Android Client, DownloadManager Copyright (c) 2014 ShengDao Tech Company Limited */ package cn.rongcloud.im.server.network.download; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Environment; import android.text.TextUtils; import android.util.Log; import java.io.File; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Queue; import cn.rongcloud.im.server.network.http.AsyncHttpClient; import cn.rongcloud.im.server.network.http.AsyncHttpResponseHandler; import cn.rongcloud.im.server.network.http.BreakpointHttpResponseHandler; /** * [下载器管理类,支持并发、暂停、继续、删除任务操作以及断点续传] * DownloadManager downloadMgr = DownloadManager.getInstance(); downloadMgr.setDownLoadCallback(new DownLoadCallback(){ @Override public void onLoading(String url, int bytesWritten, int totalSize) { super.onLoading(url, bytesWritten, totalSize); } @Override public void onSuccess(String url) { super.onSuccess(url); } @Override public void onFailure(String url, String strMsg) { super.onFailure(url, strMsg); } }); //添加下载任务 downloadMgr.addHandler(url); * * @author huxinwu * @version 1.0 * @date 2014-3-12 * **/ public class DownloadManager extends Thread { private final String tag = DownloadManager.class.getSimpleName(); private static final int MAX_HANDLER_COUNT = 20; private static final int MAX_DOWNLOAD_THREAD_COUNT = 5; private static DownloadManager instance; private HandlerQueue mhandlerQueue; private List<AsyncHttpResponseHandler> mDownloadinghandlers; private List<AsyncHttpResponseHandler> mPausinghandlers; private AsyncHttpClient asyncHttpClient; private Boolean isRunning = false; private DownLoadCallback mDownLoadCallback; private String rootPath = ""; /** * 得到DownloadManager实例 * @return */ public static DownloadManager getInstance() { return getInstance(""); } /** * 得到DownloadManager实例 * @param rootPath * @return */ public static DownloadManager getInstance(String rootPath) { if (instance == null) { synchronized (DownloadManager.class) { if (instance == null) { instance = new DownloadManager(rootPath); } } } return instance; } /** * 构造方法 * @param rootPath */ private DownloadManager(String rootPath) { if (TextUtils.isEmpty(rootPath)) { rootPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/download/"; } this.rootPath = rootPath; mhandlerQueue = new HandlerQueue(); mDownloadinghandlers = new ArrayList<AsyncHttpResponseHandler>(); mPausinghandlers = new ArrayList<AsyncHttpResponseHandler>(); asyncHttpClient = AsyncHttpClient.getInstance(); if (!TextUtils.isEmpty(rootPath)) { File rootFile = new File(rootPath); if (!rootFile.exists()) { rootFile.mkdir(); } } } /** * 得到下载文件的根目录 * @return */ public String getRootPath() { return rootPath; } /** * 设置下载回调监听事件 * @param downLoadCallback */ public void setDownLoadCallback(DownLoadCallback downLoadCallback) { this.mDownLoadCallback = downLoadCallback; } /** * 开始下载 */ private void startManage() { isRunning = true; this.start(); if (mDownLoadCallback != null) { mDownLoadCallback.sendStartMessage(); } } /** * 关闭 */ @SuppressWarnings("deprecation") public void close() { isRunning = false; pauseAllHandler(); if (mDownLoadCallback != null) { mDownLoadCallback.sendStopMessage(); } this.stop(); } /** * 判断线程是否运行 * @return */ public boolean isRunning() { return isRunning; } @Override public void run() { while (isRunning) { BreakpointHttpResponseHandler handler = (BreakpointHttpResponseHandler) mhandlerQueue.poll(); if (handler != null) { mDownloadinghandlers.add(handler); handler.setInterrupt(false); asyncHttpClient.get(handler.getUrl(), handler); } } } /** * 浏览器下载 * @param context * @param uriString 下载资源地址 */ public void addHandler(Context context, String uriString) { if (TextUtils.isEmpty(uriString)) { throw new IllegalArgumentException("addHandler uriString is not null."); } Uri uri = Uri.parse(uriString); Intent intent = new Intent(Intent.ACTION_VIEW, uri); context.startActivity(intent); } /** * 添加一个任务 * @param url */ public void addHandler(String url) { if (getTotalhandlerCount() >= MAX_HANDLER_COUNT) { if (mDownLoadCallback != null) { mDownLoadCallback.sendFailureMessage(url, "任务列表已满"); } return; } if (TextUtils.isEmpty(url) || hasHandler(url)) { Log.e(tag, "addHandler url is not null."); return; } broadcastAddHandler(url); mhandlerQueue.offer(newAsyncHttpResponseHandler(url)); if (!isAlive()) { startManage(); } } /** * 发送添加广播 * @param url */ private void broadcastAddHandler(String url) { broadcastAddHandler(url, false); } /** * 发送添加广播 * @param url * @param isInterrupt */ private void broadcastAddHandler(String url, boolean isInterrupt) { if (mDownLoadCallback != null) { mDownLoadCallback.sendAddMessage(url, isInterrupt); } } public void reBroadcastAddAllhandler() { BreakpointHttpResponseHandler handler = null; for (int i = 0; i < mDownloadinghandlers.size(); i++) { handler = (BreakpointHttpResponseHandler) mDownloadinghandlers.get(i); broadcastAddHandler(handler.getUrl(), handler.isInterrupt()); } for (int i = 0; i < mhandlerQueue.size(); i++) { handler = (BreakpointHttpResponseHandler) mhandlerQueue.get(i); broadcastAddHandler(handler.getUrl()); } for (int i = 0; i < mPausinghandlers.size(); i++) { handler = (BreakpointHttpResponseHandler) mPausinghandlers.get(i); broadcastAddHandler(handler.getUrl()); } } public boolean hasHandler(String url) { BreakpointHttpResponseHandler handler; for (int i = 0; i < mDownloadinghandlers.size(); i++) { handler = (BreakpointHttpResponseHandler) mDownloadinghandlers.get(i); if (handler.getUrl().equals(url)) { return true; } } for (int i = 0; i < mhandlerQueue.size(); i++) { handler = (BreakpointHttpResponseHandler) mhandlerQueue.get(i); if (handler.getUrl().equals(url)) { return true; } } return false; } public int getTotalhandlerCount() { return mhandlerQueue.size() + mDownloadinghandlers.size() + mPausinghandlers.size(); } /** * 根据url删除下载任务 * @param url */ public synchronized void deleteHandler(String url) { BreakpointHttpResponseHandler handler = null; for (int i = 0; i < mDownloadinghandlers.size(); i++) { handler = (BreakpointHttpResponseHandler) mDownloadinghandlers.get(i); if (handler != null && handler.getUrl().equals(url)) { File file = handler.getTargetFile(); if (file.exists()) { file.delete(); } File tempFile = handler.getTempFile(); if (tempFile.exists()) { tempFile.delete(); } handler.setInterrupt(true); completehandler(handler); return; } } for (int i = 0; i < mhandlerQueue.size(); i++) { handler = (BreakpointHttpResponseHandler) mhandlerQueue.get(i); if (handler != null && handler.getUrl().equals(url)) { mhandlerQueue.remove(handler); } } for (int i = 0; i < mPausinghandlers.size(); i++) { handler = (BreakpointHttpResponseHandler) mPausinghandlers.get(i); if (handler != null && handler.getUrl().equals(url)) { mPausinghandlers.remove(handler); } } } /** * 继续下载 * @param url */ public synchronized void continueHandler(String url) { BreakpointHttpResponseHandler handler = null; for (int i = 0; i < mPausinghandlers.size(); i++) { handler = (BreakpointHttpResponseHandler) mPausinghandlers.get(i); if (handler != null && handler.getUrl().equals(url)) { mPausinghandlers.remove(handler); mhandlerQueue.offer(handler); } } } /** * 根据Url暂停下载任务 * @param url */ public synchronized void pauseHandler(String url) { BreakpointHttpResponseHandler handler; for (int i = 0; i < mDownloadinghandlers.size(); i++) { handler = (BreakpointHttpResponseHandler) mDownloadinghandlers.get(i); if (handler != null && handler.getUrl().equals(url)) { pausehandler(handler); } } } /** * 暂停所有下载任务 */ public synchronized void pauseAllHandler() { AsyncHttpResponseHandler handler = null; for (int i = 0; i < mhandlerQueue.size(); i++) { handler = mhandlerQueue.get(i); mhandlerQueue.remove(handler); mPausinghandlers.add(handler); } for (int i = 0; i < mDownloadinghandlers.size(); i++) { handler = mDownloadinghandlers.get(i); if (handler != null) { pausehandler(handler); } } } /** * 暂停下载handler * @param handler */ private synchronized void pausehandler(AsyncHttpResponseHandler handler) { BreakpointHttpResponseHandler fileHttpResponseHandler = (BreakpointHttpResponseHandler) handler; if (handler != null) { fileHttpResponseHandler.setInterrupt(true); // move to pausing list String url = fileHttpResponseHandler.getUrl(); mDownloadinghandlers.remove(handler); handler = newAsyncHttpResponseHandler(url); mPausinghandlers.add(handler); } } /** * 完成下载任务 * @param handler */ private synchronized void completehandler(AsyncHttpResponseHandler handler) { if (mDownloadinghandlers.contains(handler)) { mDownloadinghandlers.remove(handler); if (mDownLoadCallback != null) { mDownLoadCallback.sendFinishMessage(((BreakpointHttpResponseHandler) handler).getUrl()); } } } /** * 构造一个BreakpointHttpResponseHandler * @param url * @return */ private AsyncHttpResponseHandler newAsyncHttpResponseHandler(String url) { BreakpointHttpResponseHandler handler = new BreakpointHttpResponseHandler(url, rootPath) { @Override public void onProgress(int bytesWritten, int totalSize) { super.onProgress(bytesWritten, totalSize); if (mDownLoadCallback != null) { mDownLoadCallback.sendLoadMessage(getUrl(), bytesWritten, totalSize); } } @Override public void onSuccess(File file) { if (mDownLoadCallback != null) { mDownLoadCallback.sendSuccessMessage(getUrl(), file.getPath()); } } public void onFinish() { completehandler(this); } public void onStart() { if (mDownLoadCallback != null) { mDownLoadCallback.onStart(); } } @Override public void onFailure(Throwable error) { String message = ""; if (error != null) { message = error.getMessage(); } if (mDownLoadCallback != null) { mDownLoadCallback.sendFailureMessage(getUrl(), message); } } }; return handler; } /** * [A brief description] * * @author huxinwu * @version 1.0 * @date 2014-3-13 * **/ private class HandlerQueue { private Queue<AsyncHttpResponseHandler> handlerQueue; public HandlerQueue() { handlerQueue = new LinkedList<AsyncHttpResponseHandler>(); } public void offer(AsyncHttpResponseHandler handler) { handlerQueue.offer(handler); } public AsyncHttpResponseHandler get(int position) { if (position >= size()) { return null; } return ((LinkedList<AsyncHttpResponseHandler>) handlerQueue).get(position); } public AsyncHttpResponseHandler poll() { AsyncHttpResponseHandler handler = null; while (mDownloadinghandlers.size() >= MAX_DOWNLOAD_THREAD_COUNT || (handler = handlerQueue.poll()) == null) { try { Thread.sleep(1000); // sleep } catch (InterruptedException e) { e.printStackTrace(); } } return handler; } @SuppressWarnings("unused") public boolean remove(int position) { return handlerQueue.remove(get(position)); } public boolean remove(AsyncHttpResponseHandler handler) { return handlerQueue.remove(handler); } public int size() { return handlerQueue.size(); } } }