来源:网易云课堂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

android 多线程下载 断点续传的更多相关文章

  1. android程序---->android多线程下载(一)

    多线程下载是加快下载速度的一种方式,通过开启多个线程去执行一个任务,可以使任务的执行速度变快.多线程的任务下载时常都会使用得到断点续传下载,就是我们在一次下载未结束时退出下载,第二次下载时会接着第一次 ...

  2. android程序---->android多线程下载(二)

    上篇我们讲到了android中下载的断点续传问题,今天我们开始学习下载的多线程问题.本次的多线程源码下载:androdi中多线程下载的实现代码.有关断点续传的问题,请参见博客:android程序--- ...

  3. Andoid 更好的Android多线程下载框架

    概述 为什么是更好的Android多线程下载框架呢,原因你懂的,广告法嘛! 本篇我们我们就来聊聊多线程下载框架,先聊聊我们框架的特点: 多线程 多任务 断点续传 支持大文件 可以自定义下载数据库 高度 ...

  4. 更好的Android多线程下载框架

    /** * 作者:Pich * 原文链接:http://me.woblog.cn/ * QQ群:129961195 * Github:https://github.com/lifengsofts */ ...

  5. 无废话Android之smartimageview使用、android多线程下载、显式意图激活另外一个activity,检查网络是否可用定位到网络的位置、隐式意图激活另外一个activity、隐式意图的配置,自定义隐式意图、在不同activity之间数据传递(5)

    1.smartimageview使用 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&q ...

  6. Android 多线程下载,断点续传,线程池

    你可以在这里看到这个demo的源码: https://github.com/onlynight/MultiThreadDownloader 效果图 这张效果图是同时开启三个下载任务,限制下载线程数量的 ...

  7. Java--使用多线程下载,断点续传技术原理(RandomAccessFile)

    一.基础知识 1.什么是线程?什么是进程?它们之间的关系? 可以参考之前的一篇文章:java核心知识点学习----并发和并行的区别,进程和线程的区别,如何创建线程和线程的四种状态,什么是线程计时器 简 ...

  8. *Android 多线程下载 仿下载助手

    今天带来一个多线程下载的 样例.先看一下效果.点击 下载 開始下载,同一时候显示下载进度.完成下载,变成程 安装,点击安装 提示 安装应用. 界面效果 线程池 ThreadPoolExecutor , ...

  9. Android多线程下载大文件解析

    1.多线程介绍 用过迅雷的同学都知道.迅雷有个功能叫做多线程.另一个叫离线下载,我们这里重点介绍一下多线程下载.多线程,顾名思义就是非常多歌线程同一时候在执行,为什么要提出多线程这个概念呢?由于有时候 ...

随机推荐

  1. ES6笔记(6)-- Set、Map结构和Iterator迭代器

    系列文章 -- ES6笔记系列 搞ES6的人也是够无聊,把JS弄得越来越像Java.C++,连Iterator迭代器.Set集合.Map结构都出来了,不知道说什么好... 一.简单使用 1. iter ...

  2. MVC5中,加载分部视图,常见的方式

    首先,新建一个MVC类型的Web项目: 然后在Model文件夹下定义一个Student实体: public class Student { public int ID { get; set; } pu ...

  3. VUE2.0不可忽视的很多变化

    今天使用webpack-sample初始一个vue-cli项目,在app.vue文件中添加了个钩子函数ready,可是ready内的事件一直不执行,检查了webpack文件和package.json也 ...

  4. 显示XML文档时排序数据

    先看XML文档: 也可拷贝下面代码另存为XMl文档: <stepList> <steps> <step> <order>1</order> ...

  5. 前端代码标准最佳实践:CSS

    前端工程师对写标准的前端代码的重视程度很高.这些最佳标准实践并不是那个权威组织发布的,而是由大量的前端工程师们在实践过程中的经验总结,目的在于提高代码的可读性,可维护性和性能.那么接着上一篇,我们再来 ...

  6. 分享一个递归无限级拼接Json的方法---ExtJs的TreePanel和TreeGrid均适用(Ef,Lambda,Linq,IQueryable,List)

    话不多说,先上实体类,如果你不是codefirst,就把它当成数据表结构. 下面是底层BaseDal获取数据的方法  (如果你没有Base类,直接写在你的DAL层和BLL层) 下面是BaseServi ...

  7. 为什么我不建议你做APP?

    最近迷上了新产品的可行性分析和推演. 有几个朋友也准备跳入创业火坑了,找到我说帮忙做做产品分析和可行性讨论,欣然应允. 我一向厌恶纯凭感觉拍脑袋的方式,所以对于我不了解的行业,都会从行业背景.现状痛点 ...

  8. jquery.tagthis和jquery.autocomplete一起实现标签

    目的 jquery.tagthis:http://www.dangribbin.co/jquery-tag-this/demo/ 使用tagthis控件实现标签的输入提醒功能,每个标签具有id和tex ...

  9. cefglue埋坑记录

    很少写博客,写的不好,请多多包含,主要是记录工作中的一些问题,和园子里朋友一起讨论学习. 写埋坑记录之前,我先介绍下为什么会使用这个webkit内核的浏览器组件,我是wpf项目使用富文本编辑器,话说w ...

  10. Csharp: Create Excel Workbook or word from a Template File using aspose.Word 14.5 and aspose.Cell 8.1

    winform: /// <summary> /// /// </summary> /// <param name="sender"></ ...