android 多线程下载 断点续传
2024-09-20 11:15:45
来源:网易云课堂Android极客班第八次作业练习
练习内容: 多线程 asyncTask handler
多线程下载的原理
首先获取到目标文件的大小,然后在磁盘上申请一块空间用于保存目标文件,接着把目标文件分割成n份,分别创建线程下载.
获取目标文件的大小
//使用目标文件的下载链接作为发起网络请求
mUrl = new URL("http://download.sj.qq.com/upload/connAssitantDownload/upload/MobileAssistant_1.apk");
//注意不是URLConnection, URLConnection是抽象类,HttpURLConnection是它的子类
HttpURLConnection urlConnection = (HttpURLConnection) mUrl.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setConnectTimeout(5000);
//获取目标文件的大小
mContentLength = urlConnection.getContentLength();
在磁盘上申请一块空间,用于保存目标文件,这里用到了RandomAccessFile类,该类的seek()方法能够非常方便的对文件进行指定位置的定位.
mFile = new File(Environment.getExternalStorageDirectory(), getFileName(params[0]));
if (mFile.exists()) {//如果文件已经存在,删除
mFile.delete();
}
RandomAccessFile randomFile = new RandomAccessFile(mFile, "rw");
//设置文件大小
randomFile.setLength(mContentLength);
分割文件,分别创建线程进行下载(只需要关注非注释内容)
int blockSize = mContentLength / 3;
for (int i = 0; i < 3; i++) {
int begin = i * blockSize;
int end = (i + 1) * blockSize - 1;
if (i == 2) {
end = mContentLength;
}
//HashMap<String, Integer> map = new HashMap<>();
//map.put("begin", begin);
//map.put("end", end);
//map.put("finished", 0);
//threadList.add(map);
//new Thread
new Thread(new DownloadThread(i, begin, end, mFile, mUrl)).start();
}
断点续传的原理
在每个线程进行下载的过程中,每次写入文件的时候,记录已经下载了多少内容,重新开始下载时,从上次结束的位置继续下载.
数据结构
使用HashMap存储该线程下载文件的起始位置,结束位置和已完成大小,并使用一个ArrayList存储各线程数据
private List<HashMap<String, Integer>> threadList = new ArrayList<>();
HashMap<String, Integer> map = new HashMap<>();
map.put("begin", begin);//开始位置
map.put("end", end);//结束位置
map.put("finished", 0);//已完成
发起网络请求时,指定起止位置
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
//指定起止位置
urlConnection.setRequestProperty("Range", "bytes=" + begin + "-" + end);
下载时更新map中的finished字段的值
while ((len = is.read(buf)) != -1 && isDownloading) {
randomFile.write(buf, 0, len);
updateProgress(len);
//更新map中的finished字段的值
map.put("finished", map.get("finished") + len);
}
再次开始下载时,更新每个线程的开始位置(即实例化DownloadThread类时所需要的第二个参数)
for (int i = 0; i < threadList.size(); i++) {
HashMap<String, Integer> map = threadList.get(i);
new Thread(new DownloadThread(i, map.get("begin") + map.get("finished"), map.get("end"), mFile, mUrl)).start();
}
更新ui的操作
自定义handler
public static class DownloadHandler extends android.os.Handler {
public final WeakReference<MainActivity> mActivity;
public DownloadHandler(MainActivity activity) {
mActivity = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
MainActivity activity = mActivity.get();
switch (msg.what) {
case 0:
int progress = (int) msg.obj;
activity.getProgressBar().setProgress(progress);
if (progress == 100) {
// Toast.makeText(activity, "下载成功",Toast.LENGTH_SHORT).show();
activity.getDownloadButton().setText("下载成功");
}
}
}
}
更新UI的方法
//使用synchronized
synchronized private void updateProgress(int len) {
total += len;
int temp = total * 100 / mContentLength;
mDownloadHandler.obtainMessage(0, temp).sendToTarget();
}
完整代码github地址:https://github.com/zhangbz/MultithreadingDownloadDemo
最新文章
- appium 处理动态控件
- gulp详细入门教程-gulp demo download
- 玩转正则之highlight高亮
- Nginx配置优化的几个参数
- [linux] 更改目录显示颜色
- spring框架面试相关问题
- loadView在App启动时到底都干了些什么?
- Java String.split()
- 【BZOJ】【1492】【NOI207】货币兑换Cash
- Hibernate的CRUD
- android studio 报错,google后无果
- c++ 如何获取系统时间 - zjnig711的信息仓库 - 博客频道 - CSDN.NET
- ArcGIS 10.1 发布使用ArcEngine自定义的GP服务
- html tip实现
- Ubuntu下安装Pycharm出现unsupported major.minor version 52.0
- 坚持:学习Java后台的第一阶段,我学习了那些知识
- python测试开发django-26.表单提交之post登录案例
- 计蒜客 30996 - Lpl and Energy-saving Lamps - [线段树][2018ICPC南京网络预赛G题]
- Cocos2d-x 粒子编辑器 Particle Studio 争做 Windows Particle Designer 源代码
- Mac 下解压NDK .bin文件