下载逻辑在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
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦

