首先声明一点: 这里的多线程下载 并不是指的 多个线程下载一个 文件,而是 每个线程 负责一个文件。真正的多线程 希望后面能给大家带来。

 -------------  欢迎 爱学习的小伙伴 加群  -------------

 -------------android交流群:230274309-------------

-------------一起分享,一起进步!  需要你们--------------

--------------  期待各位爱学习的小伙伴们 的到来--------------

本文是接着前面http://blog.csdn.net/u011733020/article/details/47016715继续写的。感兴趣的小伙伴 可以看前面的。

界面效果

2015/7/31改进

2015/7/31 日 先说 这次 改进了两点。

第一点 ,前面说过 项目 只适合学习,作为商用的话, 效率不高,是因为 当时  点击暂停 ,在点击下载 继续下载时候,如果文件前面下载部分较大,会比较慢, 因为  java 的 inputstream  的 skip(long  size) 跳过字节 这个方法 并不能按照你 想要跳过的字节,而是 跳过的 往往是比较小的,所以 要不断遍历,直到 返回满足 条件 ,比较耗时。打个比方, 文件大小 30M ,你下载了20M,你点了暂停 然后继续点下载,就要跳过这20M,但是你用skip 方法 可能每次跳过 4096 字节,这样 要跳过20M  的时间 就会很长。这样应该好理解。

第二点,原来 项目中, 你这一次下载没有完成,下次在下载是 删除掉原来的 从新 下载,这次 改成继续上次的地方 接着下载。

吐槽下,关于下载,我最近一周 一直在看 开源的download, 但是 无奈水平有限,收获甚微,往往是看到最后 脑袋短路。

这次改的方式比较简单,只改动了 项目中 DownloadManager 这个类。在来看下 DownloadManager  这个类 的run 方法,

@Overridepublic void run() {info.setDownloadState(STATE_DOWNLOADING);// 先改变下载状态notifyDownloadStateChanged(info);File file = new File(info.getPath());// 获取下载文件HttpResult httpResult = null;InputStream stream = null;if (info.getCurrentSize() == 0 || !file.exists()|| file.length() != info.getCurrentSize()) {// 如果文件不存在,或者进度为0,或者进度和文件长度不相符,就需要重新下载info.setCurrentSize(0);file.delete();}httpResult = HttpHelper.download(info.getUrl());if (httpResult == null|| (stream = httpResult.getInputStream()) == null) {info.setDownloadState(STATE_ERROR);// 没有下载内容返回,修改为错误状态notifyDownloadStateChanged(info);} else {try {skipBytesFromStream(stream, info.getCurrentSize());} catch (Exception e1) {e1.printStackTrace();}FileOutputStream fos = null;try {fos = new FileOutputStream(file, true);int count = -1;byte[] buffer = new byte[1024];while (((count = stream.read(buffer)) != -1)&& info.getDownloadState() == STATE_DOWNLOADING) {// 每次读取到数据后,都需要判断是否为下载状态,如果不是,下载需要终止,如果是,则刷新进度fos.write(buffer, 0, count);fos.flush();info.setCurrentSize(info.getCurrentSize() + count);notifyDownloadProgressed(info);// 刷新进度}} catch (Exception e) {info.setDownloadState(STATE_ERROR);notifyDownloadStateChanged(info);info.setCurrentSize(0);file.delete();} finally {IOUtils.close(fos);if (httpResult != null) {httpResult.close();}}
// 判断进度是否和app总长度相等if (info.getCurrentSize() == info.getAppSize()) {info.setDownloadState(STATE_DOWNLOADED);notifyDownloadStateChanged(info);} else if (info.getDownloadState() == STATE_PAUSED) {// 判断状态notifyDownloadStateChanged(info);} else {info.setDownloadState(STATE_ERROR);notifyDownloadStateChanged(info);info.setCurrentSize(0);// 错误状态需要删除文件file.delete();}}mTaskMap.remove(info.getId());}

从服务器 返回的数据流  stream  最终是在 HttpHelper 这个类中

HttpResponse response = httpClient.execute(requestBase, httpContext);//访问网络

通过  httpclient 去联网请求的  。

我没有试过 httpclient    addHeader("Range", "bytes=" + begin + "-" + end); 可不可以进行继续下载。

而是改成了 通过 httpurlconnection 去请求数据

现在  的run() 方法 是这样的。

@Overridepublic void run() {info.setDownloadState(STATE_DOWNLOADING);// 先改变下载状态notifyDownloadStateChanged(info);File file = new File(info.getPath());// 获取下载文件/**********************************************************/
//          try {try {URL url = new URL(info.getUrl());HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(30000);conn.setReadTimeout(30000);if (!file.exists()) {info.setCurrentSize(0);file.delete();} else if (file.length() > info.getAppSize()) {info.setCurrentSize(0);file.delete();} else if (file.length() == info.getAppSize()) {} else if (file.length() < info.getAppSize()) {info.setCurrentSize(file.length());}if (info.getCurrentSize() == 0 || !file.exists() || file.length() != info.getCurrentSize()) {// 如果文件不存在,或者进度为0,或者进度和文件长度不相符,就需要重新下载info.setCurrentSize(0);file.delete();} else if (file.length() == info.getCurrentSize() && file.length() < info.getAppSize()) {conn.setRequestProperty("Range", "bytes=" + info.getCurrentSize() + "-" + info.getAppSize());}int code = conn.getResponseCode();RandomAccessFile raf = new RandomAccessFile(file, "rw");InputStream is = conn.getInputStream();byte[] buffer = new byte[1024 * 8];int len = -1;int total = 0;// 当前线程下载的总的数据的长度if (code == 200) {} else if (code == 206) {raf.seek(file.length());}while (((len = is.read(buffer)) != -1) && (info.getDownloadState() == STATE_DOWNLOADING)) { // 下载数据的过程。raf.write(buffer, 0, len);total += len;// 需要记录当前的数据。info.setCurrentSize(info.getCurrentSize() + len);notifyDownloadProgressed(info);// 刷新进度}is.close();raf.close();} catch (MalformedURLException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ProtocolException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}/*************************对于各种情况,需要删除下载任务,从新下载的 请自己改动代码*****************************/// 判断进度是否和app总长度相等
//          } catch (Exception e) {
//              System.out.println(e.toString());
//              info.setDownloadState(STATE_ERROR);
//              info.setCurrentSize(0);
//              file.delete();
//              e.printStackTrace();
//          }if (info.getCurrentSize() == info.getAppSize()) {info.setDownloadState(STATE_DOWNLOADED);notifyDownloadStateChanged(info);} else if (info.getDownloadState() == STATE_PAUSED) {// 判断状态notifyDownloadStateChanged(info);} else {info.setDownloadState(STATE_ERROR);notifyDownloadStateChanged(info);info.setCurrentSize(0);// 错误状态需要删除文件file.delete();}/**********************************************************/mTaskMap.remove(info.getId());}

先判断 文件存不存在,以及大小是否满足条件, 在这里做判断

if (info.getCurrentSize() == 0 || !file.exists() || file.length() != info.getCurrentSize()) {// 如果文件不存在,或者进度为0,或者进度和文件长度不相符,就需要重新下载info.setCurrentSize(0);file.delete();} else if (file.length() == info.getCurrentSize() && file.length() < info.getAppSize()) {conn.setRequestProperty("Range", "bytes=" + info.getCurrentSize() + "-" + info.getAppSize());}

如果 文件当前大小为0,或者文件不存在,或者长度不等于当前长度,则重新下载,否则 设置 Range

下面 判断 code  正常情况下code =200 表示成功,如果 设置了Range  那么 code 返回 206 表示正常。这个时候 我们通过RandomAccessFile

RandomAccessFile  这个  类实现了 RandomAccessFile implements DataInput, DataOutput, 就是一个既可以读 也可以写的类。

RandomAccessFile 这个类来 处理 跳过多少字节, 前面 我说过 inpuStream.skeep() 方法 不准确,但是  RandomAccessFile  这个类是可以的。

RandomAccessFile raf = new RandomAccessFile(file, "rw");InputStream is = conn.getInputStream();byte[] buffer = new byte[1024 * 8];int len = -1;int total = 0;// 当前线程下载的总的数据的长度if (code == 200) {} else if (code == 206) {raf.seek(file.length());}

通过 seek 方法 跳过 这些字节。

然后

while (((len = is.read(buffer)) != -1) && (info.getDownloadState() == STATE_DOWNLOADING)) { // 下载数据的过程。raf.write(buffer, 0, len);total += len;// 需要记录当前的数据。info.setCurrentSize(info.getCurrentSize() + len);notifyDownloadProgressed(info);// 刷新进度}is.close();raf.close();

很普通的代码,把数据写出去。不断刷新当前进度, 最后关闭流。

这样就可以保证 快速的 暂停 继续下载, 并且  本次下载 没有完成,点了暂停, 下次进应用,继续下载的时候 会接着上一次下载,但是断网,或者你自己把网关掉 ,下次在恢复网络,或者 在点下载,我并没有处理,有需要的就自己处理下吧,应该是捕获异常 seckouttimeException,然后保存数据。自己动手试下就知道了。

本次就到这里。 关于多个线程 分段下载一个文件, 等我有时间 在整理。

共勉

*Android 多线程下载 仿下载助手(改进版)相关推荐

  1. android实现多任务多线程支持断点下载的下载软件

    运行效果图: 多任务多线程下载并不麻烦,只要思路清晰,逻辑清晰正确,是很好实现的.我最后遇到的纠结问题是数据库的操作上,我是拿数据库来存储下载信息的,所以在数据库的关闭上遇到了麻烦.上面那个版本是建立 ...

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

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

  3. android 多线程断点续传下载

    今天跟大家一起分享下android开发中比较难的一个环节,可能很多人看到这个标题就会感觉头很大,的确如果没有良好的编码能力和逻辑思维,这块是很难搞明白的,前面2次总结中已经为大家分享过有关技术的一些基 ...

  4. Android -- 多线程下载

    因为Android应用程序是java写的,基本上很多java写的程序都可以直接照搬到Android上面,移植性非常Good.这里讲一下多线程下载,就是每个线程都下载自己的那部分,那么就需要平均分配分割 ...

  5. android 多线程下载,断点续传,线程池

    android 多线程下载,断点续传,线程池 你可以在这里看到这个demo的源码: https://github.com/onlynight/MultiThreadDownloader 效果图 这张效 ...

  6. android多线程下载原理,安卓多线程断点续传下载功能(靠谱第三方组件,原理demo)...

    一,原生的DownloadManager 从Android 2.3(API level 9)开始,Android以Service的方式提供了全局的DownloadManager来系统级地优化处理长时间 ...

  7. android 多线程断点续传下载 三

    android 多线程断点续传下载 三 转载于:https://www.cnblogs.com/zhujiabin/p/5660093.html

  8. Android多线程断点续传下载原理及实现,移动开发工程师简历

    RandomAccessFile 文件写入 下面再讲讲文件写入问题,由于我们是多线程下载,因此文件并不是每次都是从前往后一个个字节写入的,随时可能在文件的任何一个地方写入数据.因此我们需要能够在文件的 ...

  9. android多线程下载程序卡死,android 多线程下载与断点续传

    多线程下载: 下载速度更快,服务器对每个线程平分资源,故线程越多,得到的资源越多,下载速度越快. 断点续传: 下载中断,再次下载时从上一次下载结束的位置开始下载,防止重复下载 下载结束后 代码: pa ...

最新文章

  1. 117.滑动窗口协议
  2. 启用系统登录失败处理功能
  3. Makefile中三个自动变量$^,$@,$
  4. 教程 | 如何利用C++搭建个人专属的TensorFlow
  5. java盒图_java合成图片
  6. u盘安装linux系统自动关机,将u盘拔出后电脑自动关机怎么解决【解决方法】
  7. JSON对象中的JSONObject和JSONArray以及与Map、String、数组的转化
  8. mie散射理论方程_散射,原子分子散射
  9. 基类和派生类的构造函数,隐式调用与显式调用
  10. linux进程管理相关概念
  11. 区块链支付平台技术的应用
  12. HDU 1398 Square Coins
  13. 2008-05-23
  14. Python学习-第3课(函数作用域、列表集合字典元祖)
  15. poj 3074 Sudoku
  16. [摘]ASP.Net标准控件(Label控件)
  17. 如何才能找到好用的ip软件呢,或者下载ip软件
  18. 【C语言】Linux 文件读写
  19. 那些油管上高质量的学习编程的频道 之一
  20. 零基础想要做好人物角色模型,先了解人体的构造!快来康康

热门文章

  1. SQL查询JSON格式的字段值 JSON_UNQUOTE与JSON_EXTRACT 去除SQL中双引号
  2. IPHONE黑解教程
  3. Babel 学习日记(0)
  4. C语言二维数求矩阵每行的最大值与最小值
  5. 嵌入式系统python开发_嵌组词_嵌的拼音含义_组词造句解释_嵌字的组词
  6. 使用chrome设置代理,果然还是linux 方便呢。想安装一个chrome的插件,通过命令设置代理。
  7. 游戏图片文件和声音文件的隐藏
  8. 掌握这个技能,再也不用为面试发愁了
  9. 7-45 连年 7-69 求婚
  10. 在ubuntu18.04上安装vmware