android --多线程下载
多线程下载文件的过程是:
(1)首先获得下载文件的长度,然后设置本地文件的长度。
HttpURLConnection.getContentLength();//获取下载文件的长度
RandomAccessFile file = new RandomAccessFile("QQSetup.exe","rwd");
file.setLength(filesize);//设置本地文件的长度
(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。
如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如下图所示。
例如10M大小,使用3个线程来下载,
线程下载的数据长度 (10%3 == 0 ? 10/3:10/3+1) ,第1,2个线程下载长度是4M,第三个线程下载长度为2M
下载开始位置:线程id*每条线程下载的数据长度 = ?
下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?
(3)使用Http的Range头字段指定每条线程从文件的什么位置开始下载,下载到什么位置为止,
如:指定从文件的2M位置开始下载,下载到位置(4M-1byte)为止
代码如下:HttpURLConnection.setRequestProperty("Range", "bytes=2097152-4194303");
(4)保存文件,使用RandomAccessFile类指定每条线程从本地文件的什么位置开始写入数据。
RandomAccessFile threadfile = new RandomAccessFile("QQWubiSetup.exe ","rwd");
threadfile.seek(2097152);//从文件的什么位置开始写入数据
/** *多线程下载,UI更新类 *@author young * */
public class MultiThreadDownload extends Thread{ private static final String TAG = "MultiThreadDownload"; /**每一个线程需要下载的大小 */ private int blockSize; /*** 线程数量<br> 默认为5个线程下载*/ private int threadNum = 5; /*** 文件大小 */ private int fileSize; /** * 已经下载多少 */ private int downloadSize; /**文件的url,线程编号,文件名称*/ private String UrlStr,ThreadNo,fileName; /***保存的路径*/ private String savePath; /**下载的百分比*/ private int downloadPercent = 0; /**下载的 平均速度*/ private int downloadSpeed = 0; /**下载用的时间*/ private int usedTime = 0; /**当前时间*/ private long curTime; /**是否已经下载完成*/ private boolean completed = false; private Handler handler ; /** * 下载的构造函数 * @param url 请求下载的URL * @param handler UI更新使用 * @param savePath 保存文件的路径 */ public MultiThreadDownload(Handler handler,String url,String savePath) { this.handler = handler; this.UrlStr = url; this.savePath = savePath; Log.e(TAG, toString()); } @Override public void run() { FileDownloadThread[] fds = new FileDownloadThread[threadNum];//设置线程数量 try { URL url = new URL(UrlStr); URLConnection conn = url.openConnection(); fileSize = conn.getContentLength(); this.fileName = FileUtil.getFileName(UrlStr); //只创建一个文件,saveFile下载内容 File saveFile = new File(savePath+"/"+fileName); Log.e(TAG, "文件一共:"+fileSize+" savePath "+savePath+" fileName "+fileName); RandomAccessFile accessFile = new RandomAccessFile(saveFile,"rwd"); //设置本地文件的长度和下载文件相同 accessFile.setLength(fileSize); accessFile.close(); //Handler更新UI,发送消息 sendMsg(FileUtil.startDownloadMeg); //每块线程下载数据 blockSize = ((fileSize%threadNum)==0)?(fileSize/threadNum):(fileSize/threadNum+1); Log.e(TAG, "每个线程分别下载 :"+blockSize); for (int i = 0; i < threadNum; i++) { int curThreadEndPosition = (i+1)!=threadNum ? ((i+1)*blockSize-1) : fileSize; FileDownloadThread fdt = new FileDownloadThread(url, saveFile, i*blockSize, curThreadEndPosition); fdt.setName("thread"+i); fdt.start(); fds[i]=fdt; } /** * 获取数据,更新UI,直到所有下载线程都下载完成。 */ boolean finished = false; //开始时间,放在循环外,求解的usedTime就是总时间 long startTime = System.currentTimeMillis(); while(!finished) { downloadSize = 0; finished = true; for (int i = 0; i < fds.length; i++) { downloadSize+= fds[i].getDownloadSize(); if(!fds[i].isFinished()) { finished = false; } } downloadPercent = (downloadSize*100)/fileSize; curTime = System.currentTimeMillis(); System.out.println("curTime = "+curTime+" downloadSize = "+downloadSize+" usedTime "+(int) ((curTime-startTime)/1000)); usedTime = (int) ((curTime-startTime)/1000); if(usedTime==0)usedTime = 1; downloadSpeed = (downloadSize/usedTime)/1024; sleep(1000);/*1秒钟刷新一次界面*/ sendMsg(FileUtil.updateDownloadMeg); } Log.e(TAG, "下载完成"); completed = true; sendMsg(FileUtil.endDownloadMeg); } catch (Exception e) { Log.e(TAG, "multi file error Exception "+e.getMessage()); e.printStackTrace(); } super.run(); } /** * 得到文件的大小 * @return */ public int getFileSize() { return this.fileSize; } /** * 得到已经下载的数量 * @return */ public int getDownloadSize() { return this.downloadSize; } /** * 获取下载百分比 * @return */ public int getDownloadPercent(){ return this.downloadPercent; } /** * 获取下载速度 * @return */ public int getDownloadSpeed(){ return this.downloadSpeed; } /** * 修改默认线程数 * @param threadNum */ public void setThreadNum(int threadNum){ this.threadNum = threadNum; } /** * 分块下载完成的标志 * @return */ public boolean isCompleted(){ return this.completed; } @Override public String toString() { return "MultiThreadDownload [threadNum=" + threadNum + ", fileSize=" + fileSize + ", UrlStr=" + UrlStr + ", ThreadNo=" + ThreadNo + ", savePath=" + savePath + "]"; } /** * 发送消息,用户提示 * */ private void sendMsg(int what) { Message msg = new Message(); msg.what = what; handler.sendMessage(msg); }
public class FileDownloadThread extends Thread{ private static final String TAG = "FileDownloadThread"; /**缓冲区 */ private static final int BUFF_SIZE = 1024; /**需要下载的URL*/ private URL url; /**缓存的FIle*/ private File file; /**开始位置*/ private int startPosition; /**结束位置*/ private int endPosition; /**当前位置*/ private int curPosition; /**完成*/ private boolean finished = false; /**已经下载多少*/ private int downloadSize = 0; /*** * 分块文件下载,可以创建多线程模式 * @param url 下载的URL * @param file 下载的文件 * @param startPosition 开始位置 * @param endPosition 结束位置 */ public FileDownloadThread(URL url, File file, int startPosition, int endPosition) { this.url = url; this.file = file; this.startPosition = startPosition; this.curPosition = startPosition; this.endPosition = endPosition; Log.e(TAG, toString()); } @Override public void run() { BufferedInputStream bis = null; RandomAccessFile rAccessFile = null; byte[] buf = new byte[BUFF_SIZE]; URLConnection conn = null; try { conn = url.openConnection(); conn.setConnectTimeout(10000);//设置超时 conn.setReadTimeout(10000); conn.setAllowUserInteraction(true); System.out.println(this.getName()+" startPosition "+startPosition+" endPosition "+endPosition); conn.setRequestProperty("Range", "bytes="+(startPosition)+"-"+endPosition); //取剩余未下载的 rAccessFile = new RandomAccessFile(file,"rwd");//读写 //设置从什么位置开始写入数据 rAccessFile.seek(startPosition); bis = new BufferedInputStream(conn.getInputStream(), BUFF_SIZE); while(curPosition<endPosition) //当前位置小于结束位置 继续下载 { int len = bis.read(buf,0,BUFF_SIZE); if(len==-1) //下载完成 { break; } rAccessFile.write(buf,0,len); curPosition = curPosition +len; if(curPosition > endPosition) { //如果下载多了,则减去多余部分 System.out.println(" curPosition > endPosition !!!!"); int extraLen = curPosition-endPosition; downloadSize += (len-extraLen+1); }else{ downloadSize+=len; } } this.finished = true; //当前阶段下载完成 Log.e(TAG, "当前"+this.getName()+"下载完成"); } catch (Exception e) { Log.e(TAG, "download error Exception "+e.getMessage()); e.printStackTrace(); }finally{ //关闭流 FileUtil.closeInputStream(bis); try { rAccessFile.close(); } catch (IOException e) { // TODO Auto-generated catch block Log.e("AccessFile", "AccessFile IOException "+e.getMessage()); } } super.run(); } /** * 是否完成当前段下载完成 * @return */ public boolean isFinished() { return finished; } /** * 已经下载多少 * @return */ public int getDownloadSize() { return downloadSize; } @Override public String toString() { return "FileDownloadThread [url=" + url + ", file=" + file + ", startPosition=" + startPosition + ", endPosition=" + endPosition + ", curPosition=" + curPosition + ", finished=" + finished + ", downloadSize=" + downloadSize + "]"; }
多线程下载是分段下载,创建保存一个文件,子线程分别通过RandomAccessFile类进行写入操作。
示例源码:demo下载
转载于:https://www.cnblogs.com/chaoyu/p/6436884.html
android --多线程下载相关推荐
- android 多线程下载,断点续传,线程池
android 多线程下载,断点续传,线程池 你可以在这里看到这个demo的源码: https://github.com/onlynight/MultiThreadDownloader 效果图 这张效 ...
- 更好的Android多线程下载框架
/*** 作者:Pich* 原文链接:http://me.woblog.cn/* QQ群:129961195* Github:https://github.com/lifengsofts*/ 概述 为 ...
- Android多线程下载断点续传
先上图看卡结果: GITHUB:Android多线程下载断点续传 下载杵这儿 如图所示点击下载就开始下载,点击停止就会停止再次点击下载就会接着下载了. 设计思路是这样的: 首先通过广播将下载信息传递给 ...
- Android -- 多线程下载
因为Android应用程序是java写的,基本上很多java写的程序都可以直接照搬到Android上面,移植性非常Good.这里讲一下多线程下载,就是每个线程都下载自己的那部分,那么就需要平均分配分割 ...
- android多线程下载原理,安卓多线程断点续传下载功能(靠谱第三方组件,原理demo)...
一,原生的DownloadManager 从Android 2.3(API level 9)开始,Android以Service的方式提供了全局的DownloadManager来系统级地优化处理长时间 ...
- *Android 多线程下载 仿下载助手(改进版)
首先声明一点: 这里的多线程下载 并不是指的 多个线程下载一个 文件,而是 每个线程 负责一个文件.真正的多线程 希望后面能给大家带来. ------------- 欢迎 爱学习的小伙伴 加群 ...
- android多线程下载程序卡死,android 多线程下载与断点续传
多线程下载: 下载速度更快,服务器对每个线程平分资源,故线程越多,得到的资源越多,下载速度越快. 断点续传: 下载中断,再次下载时从上一次下载结束的位置开始下载,防止重复下载 下载结束后 代码: pa ...
- android多线程下载3
今天跟大家一起分享下android开发中比较难的一个环节,可能很多人看到这个标题就会感觉头很大,的确如果没有良好的编码能力和逻辑思维,这块是很难搞明白的,前面2次总结中已经为大家分享过有关技术的一些基 ...
- Android 多线程下载文件原理霸气解析介绍 -----文件的下载(3)
1.首先我们先创建好下载的位置–根据url创建文件. /*** <p>Title: FlieStorageManager</p >* <p>Description: ...
- Android 多线程下载以及断点续传
多线程下载 在日常开发中,我们不可避免的会接到类似这样的需求,下载一个比较大的素材文件或者安装包文件,以此实现APP的自动更新,APP内的素材替换等.由于一般此类文件都比较大,一般会在50M以上,如果 ...
最新文章
- git常用命令(二)
- Visual Studio 2013开发 mini-filter driver step by step (3) - 查看运行结果
- c# treeView 取消选择事件
- java例程练习(布局管理器[FlowLayout])
- Spring MVC原理学习之how is return type handled
- 为什么用java开发app_安卓开发为什么选择用Java语言
- too many connections的一个实践
- texshop 使用技巧
- 小程序入门学习04--数据绑定、条件渲染、列表渲染
- 启动失败_启动失败了?
- Qt Creator 自动补齐变慢的解决
- 工具使用-----Jmeter-脚本的录制
- 主键和外键举例_mysql 基础篇之主键和外键
- 单片机喇叭如何响出报警声音 C语言程序,单片机报警器声音产生的方法(报警声音)...
- 穿孔发光字/外露发光字制作流程步骤
- 差分信号,差分对和耦合(一)——基本概念介绍
- [网络安全自学篇] 八十二.WHUCTF之隐写和逆向类解题思路WP(文字解密、图片解密、佛语解码、冰蝎流量分析、逆向分析)
- 普陀寺里的穿白T恤的奥特曼 2012年9月8日
- python3 教程 下载图片资源
- H5组件Canvas画电子印章
热门文章
- MODULE_DEVICE_TABLE【转】
- Kickstart+HTTP+DHCP+TFTP全自动批量安装部署Linux系统
- SilverLight 条码 扫描枪 MVVM(转载)
- 恢复出厂设置后itms注册失败_手机恢复出厂设置后,与新手机的区别已被确认,望大家相互转告!...
- python ** 运算符_Python语法基础(2)运算符
- Linux下SVN 命令操作手册
- Struts2 xml配置
- 通过SharedPreferences方式存储复杂数据
- 同一个tomcat部署多个项目导致启动失败
- Spring Cloud-honghu Cloud分布式微服务云系统--云架构代码结构构建