下载逻辑在android开发中可谓很常见,那么封装一个通用简洁的下载器时很有必要的。如果不想给工程引入一个很重的jar包那么可以直接复用下面的代码即可。
主要对外接口
构造函数 : public CommonDownloader(String saveDir, int timeoutMs)
开始下载接口: public void start(String saveFileName, String url)
停止下载接口: public void stop()
结构(十分简单)
下载主要由一个Handler和一个下载线程组成,Handler统一处理结果,下载线程负责将下载并将结果发送给Handler。
内部实现
public class CommonDownloader { /**patch save dir*/ private String mSaveDir; /**http request timeout*/ private int mTimeoutMs; /**download listener, see {@link OnDownloadListener}*/ private OnDownloadListener mDownloadListener; private Thread mDownloadThread; /**download control tag*/ private boolean isStop; /**UI event handler, see {@link DownloadHandler}*/ private DownloadHandler mDownloadHandler; /** * download event listener */ public interface OnDownloadListener { /**start download the callback*/ void onStarted(); /**download success the callback*/ void onSuccess(String file); /**download failed the callback*/ void onFailed(String errorMsg); } public CommonDownloader(String saveDir, int timeoutMs) { if (TextUtils.isEmpty(saveDir)) { throw new IllegalArgumentException("mSaveDir is empty! please reset."); } else { File file = new File(saveDir); if (!file.exists() || !file.isDirectory()) { if (!file.mkdirs()) { throw new IllegalArgumentException("failed to create file directory. > " + file.getAbsolutePath()); } } this.mSaveDir = saveDir; } this.mTimeoutMs = timeoutMs; mDownloadHandler = new DownloadHandler(this); } /** * start download * @param patchSaveFileName * @param url */ public void start(String patchSaveFileName, String url) { mDownloadHandler.sendEmptyMessage(DownloadHandler.STATUS_START); if (TextUtils.isEmpty(patchSaveFileName)) { Message message = Message.obtain(); message.what = DownloadHandler.STATUS_FAILED; message.obj = "patchSaveFileName is empty! please reset."; mDownloadHandler.sendMessage(message); return; } File file = new File(mSaveDir, patchSaveFileName); if (file.exists() && file.isFile()) { if (!file.delete()) { Message message = Message.obtain(); message.what = DownloadHandler.STATUS_FAILED; message.obj = "try deleted this file failed. >" + file.getAbsolutePath(); mDownloadHandler.sendMessage(message); return; } } try { if (!file.createNewFile()) { Message message = Message.obtain(); message.what = DownloadHandler.STATUS_FAILED; message.obj = "failed to create the patch file. >" + file.getAbsolutePath(); mDownloadHandler.sendMessage(message); return; } } catch (IOException e) { Message message = Message.obtain(); message.what = DownloadHandler.STATUS_FAILED; message.obj = e.getMessage(); mDownloadHandler.sendMessage(message); Log.e(e); return; } stop(); mDownloadThread = new Thread(new DownloadTask(url, patchSaveFileName, file)); mDownloadThread.start(); } /** * stop download */ public void stop() { isStop = true; if (mDownloadThread != null) { try { mDownloadThread.join(3000); } catch (InterruptedException e) { Log.w(e.getMessage()); } } } /** * set the download listener * @param mDownloadListener */ public void setmDownloadListener(OnDownloadListener mDownloadListener) { this.mDownloadListener = mDownloadListener; } /** * create file output stream * @param patchSaveFileName * @return */ private OutputStream createOutputStream(String patchSaveFileName) { FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(new File(mSaveDir, patchSaveFileName)); } catch (FileNotFoundException e) { Message message = Message.obtain(); message.what = DownloadHandler.STATUS_FAILED; message.obj = e.getMessage(); mDownloadHandler.sendMessage(message); Log.e(e); } return fileOutputStream; } /** * download task */ private class DownloadTask implements Runnable { private String urlAddress; private String patchSaveFileName; private File downloadFile; private DownloadTask(String urlAddress, String patchSaveFileName, File downloadFile) { this.urlAddress = urlAddress; this.patchSaveFileName = patchSaveFileName; this.downloadFile = downloadFile; } @Override public void run() { isStop = false; HttpURLConnection connection = null; InputStream inputStream = null; OutputStream outputStream = null; try { URL url = new URL(urlAddress); connection = (HttpURLConnection)url.openConnection(); connection.setConnectTimeout(mTimeoutMs); connection.setReadTimeout(mTimeoutMs); connection.setUseCaches(false); connection.setDoInput(true); connection.setRequestProperty("Accept-Encoding", "identity"); connection.setRequestMethod("GET"); inputStream = connection.getInputStream(); byte[] buffer = new byte[100 * 1024]; int length; outputStream = createOutputStream(patchSaveFileName); if(outputStream == null) return; while (!isStop && (length = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, length); } if (!isStop) { Message message = Message.obtain(); message.what = DownloadHandler.STATUS_SUCCESS; message.obj = downloadFile.getAbsolutePath(); mDownloadHandler.sendMessage(message); } else { Message message = Message.obtain(); message.what = DownloadHandler.STATUS_FAILED; message.obj = "the patch download has been canceled!"; mDownloadHandler.sendMessage(message); } } catch (MalformedURLException e) { Message message = Message.obtain(); message.what = DownloadHandler.STATUS_FAILED; message.obj = e.getMessage(); mDownloadHandler.sendMessage(message); Log.e(e); } catch (IOException e) { Message message = Message.obtain(); message.what = DownloadHandler.STATUS_FAILED; message.obj = e.getMessage(); mDownloadHandler.sendMessage(message); Log.e(e); } catch (Exception ex) { Message message = Message.obtain(); message.what = DownloadHandler.STATUS_FAILED; message.obj = ex.getMessage(); mDownloadHandler.sendMessage(message); Log.e(ex); } finally { if (connection != null) { connection.disconnect(); } if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { Log.e(e); } } if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { Log.e(e); } } } } } /** * download event handler */ private static class DownloadHandler extends Handler { private static final int STATUS_START = 0x01; private static final int STATUS_SUCCESS = 0x02; private static final int STATUS_FAILED = 0x03; private WeakReference<CommonDownloader> weakReference; private DownloadHandler(CommonDownloader patchDownloader) { super(Looper.getMainLooper()); weakReference = new WeakReference<CommonDownloader>(patchDownloader); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); int status = msg.what; CommonDownloader patchDownloader = weakReference.get(); switch (status) { case STATUS_START: if(patchDownloader != null && patchDownloader.mDownloadListener != null) { patchDownloader.mDownloadListener.onStarted(); } break; case STATUS_SUCCESS: if(patchDownloader != null && patchDownloader.mDownloadListener != null) { patchDownloader.mDownloadListener.onSuccess((String)msg.obj); } break; case STATUS_FAILED: if (patchDownloader != null && patchDownloader.mDownloadListener != null) { patchDownloader.mDownloadListener.onFailed((String)msg.obj); } break; default: break; } } } }
细节分析:
1. Hanlder中弱引用的使用:
当下载器已经被回收时,Listener也不会再收到回调结果
可以参考这篇关于Activity中Handler防止内存泄漏的方法: https://blog.csdn.net/u010134087/article/details/53610654
2. 停止下载的方法:
首先将标记为 isStop 置为true,这样下载就不再进行(DownloadThread里面写数据时进行了判断),同时调用join方法等待线程停止。 (join方法含义可以参考:https://www.cnblogs.com/NeilZhang/p/8781897.html)
原文出处:https://www.cnblogs.com/NeilZhang/p/9600859.html
共同學習,寫下你的評論
評論加載中...
作者其他優(yōu)質(zhì)文章