Android 多线程断点续传同时下载多个大文件
最近学习在Android环境中一些网络请求方面的知识,其中有一部分是关于网络下载方面的知识。在这里解析一下自己写的demo,总结一下自己所学的知识。下图为demo的效果图,仿照一些应用下载商城在ListView中列出加载项,然后可以可以下载和停止。
1.概述
这里有几个比较重要的类DownloadManager、DownloadService、DownloadTask、ThreadDAOImpl。主要的下载流程如下。
(1) DownloadManager 负责下载任务的调配,以及下载服务DownloadService的启动
(2) DownloadService 主获取下载文件的的一些信息,包括文件的名字、文件的长度等,并创建下载任务DownloadTask
(3) DownloadTask 是正式下载文件的类,首先查看数据库里有没保存过相应的断点,并从相应的断点开始下载,如果没有则将文件分段,并启动下载
(4) ThreadDAOImpl 数据库操作类,主要是保存线程下载的断点信息
2.多线程断点续传
当然这里最核心的部分就是多线程断点续传,原来不是很难,就是将要下载的文件分割成多个部分,每个部分使用的不同的线程同时下载。
2.1获取下载文件长度,设置本地文件
在DownloadService 设置下载文件的信息,如下一段代码:
class InitThread extends Thread {
// FileInfo fileInfo;
TaskInfo taskInfo;
public InitThread (TaskInfo taskInfo) {
this.taskInfo = taskInfo;
}
@Override
public void run() {
super.run();
Log.i(tag,"InitThread");
try {
URL url = new URL(taskInfo.getUrl());
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setConnectTimeout();
if(con.getResponseCode() == HttpURLConnection.HTTP_OK) {
int len = con.getContentLength(); <span style="color:#ff0000;">//文件的总长度</span>
taskInfo.setLenght(len);
if(len <= ) {
return;
}
…………此处省略部分
//start 设置下载文件
<span style="color:#ff6666;"> RandomAccessFile accessFile = new RandomAccessFile(new File(taskInfo.getFilePath(),taskInfo.getFileName()),"rwd");
accessFile.setLength(len); //设置文件长度</span>
accessFile.close();
//end 设置下载文件
…………此处省略部分
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.2 文件分段
接下的工作是分段下载
举个列子一个10M的文件,分成三份求整10/3 = 3,前面的一二份分别是3M,最后一份是4M。所以第一份从0~2.9,第二份是从3~5.9,第三份是从6~10,这里只是粗来的说明。接下来看代码,在DownloadTask中有如下有如下代码:
/**
* 启动下载
*/
public void downlaod() { …………此处省略部分
//start 数据库没有对应的线程信息,则创建相应的线程信息
if(threadInfoList.size() <=) {
<span style="color:#ff6666;">int block = mTaskInfo.getLenght()/mThreadCount; //将下载文件分段,每段的长度</span>
if(block > ) {
//start 根据线程数量分别建立线程信息
for(int i = ;i < mThreadCount;i++) {
ThreadInfo info = new ThreadInfo(i,mTaskInfo.getUrl(),i*block,(i+)*block-,);
if(i == mThreadCount -) {
<span style="color:#ff0000;"> info.setEnd(mTaskInfo.getLenght()); //分段最后一个,结束位置到文件总长度末尾</span>
}
threadInfoList.add(info); //加入列表
mThreadDao.insertThread(info); //向数据库插入线程信息
}
//end 根据线程数量分别建立线程信息
}else {
ThreadInfo info = new ThreadInfo(,mTaskInfo.getUrl(),,mTaskInfo.getLenght(),);
threadInfoList.add(info);
mThreadDao.insertThread(info);
}
}
//end 数据库中没有对应的线程信息,则创建相应的线程信息 …………此处省略部分
}
2.3下载线程
下面是主要的下载文件的线程
主要的是设置开始读取和结束的地方:
con.setRequestProperty("Range", "bytes=" + start + "-" + threadInfo.getEnd()); //设置读取文件的位置,和结束位置
写入本地文件的地方:
accessFile.seek(start); //设置开始写入的位置
/**
* 下载线程
*/
class DownloadThread extends Thread {
…………此处省略部分
@Override
public void run() {
…………此处省略部分
int start = threadInfo.getStart()+threadInfo.getFinished(); //读取文件的位置
//start 初始化下载链接
…………此处省略部分
con.setRequestProperty("Range", "bytes=" + start + "-" + threadInfo.getEnd()); //设置读取文件的位置,和结束位置
//end 初始化下载链接
//start 初始化下载到本地的文件
<span style="color:#ff0000;">accessFile = new RandomAccessFile(new File(mTaskInfo.getFilePath(), mTaskInfo.getFileName()),"rwd");
accessFile.seek(start); //设置开始写入的位置</span>
//end 初始化下载到本地的文件
…………此处省略部分
while((readLen = inputStream.read(buffer))!=-) {
<span style="background-color: rgb(255, 255, 255);"><span style="color:#ff0000;"> accessFile.write(buffer, , readLen);</span></span>
// Log.i(tag, "readLen = " + readLen);
finished += readLen;
threadInfo.setFinished(finished); //设置已经下载进度
if(System.currentTimeMillis() - time >) {
// Log.i(tag, "readLen = " + readLen);
notifyProgress(threadInfo.getId(), finished); //每隔2秒通知下载进度
time = System.currentTimeMillis();
}
//start 停止下载,保存进度
if(isPause) {
Log.i(tag,"pause name = "+mTaskInfo.getFileName());
notifyProgress(threadInfo.getId(), finished); //通知下载进度
mThreadDao.updateThread(threadInfo.getUrl(),threadInfo.getId(),finished); //更新数据库对应的线程信息
return;
}
//end 停止下载,保存进度
}
//end 读取输入流写入文件
…………此处省略部分 }
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
…………此处省略部分
}
super.run();
}
}
2.4保存断点
在上面的DownloadThread下载线程中保存断点信息,是使用数据库形式保存的。
mThreadDao.updateThread(threadInfo.getUrl(),threadInfo.getId(),finished); //更新数据库对应的线程信息
3其他辅助类
(1) 数据库操作类ThreadDAOImpl,断点信息的增、改、查、删。
(2) 回调接口OnDownload,下载进度以及下载完成
(3) 下载任务信息TaskInfo
(4) 线程信息ThreadInfo
4线程池
由于使用到多线程同时下载,这里在使用了线程池管理。在DownloadService类中创建并初始化线程池,按照CPU核心数量乘以2再加1设置线程池中线程的数量
mThreadPool = Executors.newFixedThreadPool(getNumberOfCPUCores()*2+1); //初始化线程
在下载时使用三个线程同时下载
DownloadTask task = new DownloadTask(DownloadService.this,info,mThreadPool,3); //建立下载任务,3个线程同时下载
由于线程池内的线程数量是有限的,当启动下载之后有空闲的线程会马上执行,如果没有就只能等待下载任务完成再下载。
Android 多线程断点续传同时下载多个大文件的更多相关文章
- android 多线程断点续传下载
今天跟大家一起分享下Android开发中比较难的一个环节,可能很多人看到这个标题就会感觉头很大,的确如果没有良好的编码能力和逻辑思维,这块是很难搞明白的,前面2次总结中已经为大家分享过有关技术的一些基 ...
- Android的断点续传的下载在线文件示例
Android的断点续传的下载在线文件示例 文件的结构如下: activity_main.xml: <LinearLayout xmlns:android="http://schema ...
- Android多线程断点续传下载
这个月接到一个项目.要写一个像360助手一样的对于软件管理的APP:当中.遇到了一个问题:多线程断点下载 这个 ,因为之前没有写过这方面的应用功能.所以.不免要自学了. 然后就在各个昂站上收索并整理了 ...
- Android多线程.断点续传下载
多线程,可断点续传的demo!最早写于2010.7! /** * @brief 主界面 * @author lixp */ public class HomeActivity exten ...
- Android应用开发之使用Socket进行大文件断点上传续传
http://www.linuxidc.com/Linux/2012-03/55567.htm http://blog.csdn.net/shimiso/article/details/8529633 ...
- Asp.Net 文件下载1——流下载(适用于大文件且防盗链)(转)
使用流防盗链下载大文件 直接上 Asp.net 后置代码好了 using System; using System.Data; using System.Configuration; using Sy ...
- android多线程断点续传下载文件
一.目标 1.多线程抢占服务器资源下载. 2.断点续传. 二.实现思路. 假设分为三个线程: 1.各个线程分别向服务器请求文件的不同部分. 这个涉及Http协议,可以在Header中使用Range参数 ...
- ajax下载小于500M大文件【原】
不推荐使用的FileReader 之前用FileReader读取下载文件,当文件超过1M浏览器就立即扑街了 // 文件下载 function download(blob, fileName) { va ...
- android 多线程
本章讲述在android开发中,多线程的应用.多线程能够处理耗时的操作并优化程序的性能.本章主要介绍知识点,AsyncTask,Java线程池,ThreadPoolExecutor线程池类.本章案例只 ...
随机推荐
- ArcGIS api for javascript——查询,然后单击显示信息窗口
描述 本例展示如何配置查询任务为示例的工作流程: 1.用户单击一个要素来加亮显示. 2.用户再一次单击要素来查看属性信息的 InfoWindow. 本例查询USA州,因此ESRI_StateCityH ...
- mysql生成随机时间
mysql> update test set create_time=concat('2013-10-01 ', floor(10+rand()*10),':',floor(10+rand()* ...
- Anatomy of an IIS7 configuration path
The concept of configuration paths is fundamental to managing and operating an IIS server, so I want ...
- zzuli--1812--sort(模拟水题)
1812: sort Time Limit: 1 Sec Memory Limit: 128 MB Submit: 158 Solved: 30 SubmitStatusWeb Board Des ...
- nginx大量TIME_WAIT的解决办法--转
原文地址:http://liuyieyer.iteye.com/blog/2214722?utm_source=tuicool&utm_medium=referral 由于网站使用nginx做 ...
- P1824 进击的奶牛
题目描述 Farmer John建造了一个有N(2<=N<=100,000)个隔间的牛棚,这些隔间分布在一条直线上,坐标是x1,...,xN (0<=xi<=1,000,000 ...
- display 表格模型值
display:inline-table 此元素会作为内联表格来显示(类似 <table>),表格前后没有换行符.display:inline-table 可以使文字和表格在同一行显示 d ...
- vuex 快速入门( 基于vue2.0,vue1.0未知可否)
1.原理概述 2.用户登录例子解析: 由上图可以看到: 1.组件的数据是username,我们把它以name放在state中: 2.更改name发生在mutations的回调里,事件名字是showUs ...
- 超好用的谷歌浏览器、Sublime Text、Phpstorm、油猴插件合集
原文:超好用的谷歌浏览器.Sublime Text.Phpstorm.油猴插件合集 - 『精品软件区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|破解软件|www.52pojie.c ...
- Spring MVC学习总结(5)——SpringMVC项目关于安全的一些配置与实现方式
目前越来越多的应用和网站,开始注重安全性的问题,关于我们的web项目的几个安全知识点,不得不讲解一下,这里我主要讲述关于tomcat如何支持HTTPS连接访问,RSA公钥和私钥的制作.这个对于我们整个 ...