Android实现多线程断点续传

文件在下载的过程中,手动暂停或异常时,下载被中断,此时如果需要恢复下载,又不想重新下载的话,那么就需要实现断点续传了,断点续传的意思就是,恢复下载时,文件从被中断的位置继续下载,而无需重新将文件重新下载,最大的好处便是节省时间以及网络产生的流量了。要实现文件下载的断点续传,就必须首先需要明白Http断点续传的原理。

Http请求头Range是断点续传的核心。

什么是Range

当用户在听一首歌的时候,如果听到一半(网络下载了一半),网络断掉了,用户需要继续听的时候,文件服务器不支持断点的话,则用户需要重新下载这个文件。而Range支持的话,客户端应该记录了之前已经读取的文件范围,网络恢复之后,则向服务器发送读取剩余Range的请求,服务端只需要发送客户端请求的那部分内容,而不用整个文件发送回客户端,以此节省网络带宽。

HTTP1.1规范的Range的约定

服务端通过请求头Range:bytes=start-end来判断是否做Range请求,如果这个值存在并且有效,将返回206的响应码给客户端,告知这个请求支持断点续传。Range指定的是一个闭合区间范围(也可以是多个区间范围,不需要连续),Range请求头的格式规范如下:

Range: bytes = start-end,start2-end2,start3-end3,...,startN-endN

start-end 是一个闭合区间,即包含start到end的部分,所以下一个请求应该以end+1开头

例如:

Range: bytes=0-100 (0到100字节的数据)
Range: bytes=40- (40字节以后的数据)
Range: bytes=-500(最后一个500字节的数据)
Range: bytes=0-0,-1 (第一个和最后一个字节)
Range: bytes=500-600,800-999 (同时指定两个范围)

响应头

Content-Range:bytes 0-100/3103

服务器响应了前(0-100)个字节的数据,该资源一共有(3103)个字节大小。

Content-Length:101

表示这次请求,服务器响应了101个字节数据,我们通常也通过Content-Length去获取整个资源文件的大小,作为分段下载的基础

以HttpUrlConnection为例


URL url = new URL(fileUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(10 * 1000);
connection.setRequestProperty("Accept-Ranges", "bytes");
connection.setRequestProperty("Connection", "Keep-Alive");

//加上这个头部,则可以防止出现getContentLength()为-1的问题
connection.setRequestProperty("Accept-Encoding", "identity");
//必须加这个头部,否则无法返回正常支持断点续传的响应码206,这里取值范围是从第一个字节到结束,所以是请求的是整个资源文件
connection.setRequestProperty("Range", "bytes=0-");
connection.connect();

//假如此请求支持断点续传的方式将返回206响应码,否则资源请求成功的时候返回正常的200
int code = connection.getResponseCode() ;
//获取本次服务器响应的字节长度
long fileLength = connection.getContentLength();

实现多线程断点续传的基本思路

RandomAccessFile

多线程如何操作同一个文件,分段写入呢?了解一下RandomAccessFile

RandomAccessFile类的主要功能是完成随机读取功能,可以读取指定位置的内容。
之前的File类只是针对文件本身进行操作的,而如果要想对文件内容进行操作,则可以使用RandomAccessFile类,此类属于随机读取类,可以随机读取一个文件中指定位置的数据

构造方法

public RandomAccessFile(File file, String mode)throws FileNotFoundException 
public RandomAccessFile(String name, String mode) throws FileNotFoundException

mode 文件的打开模式
r:读模式
w:只写
rw:读写,如果使用此模式,如果此文件不存在,则会自动创建。

指定读写的位置

randomAccessFile.seek(startIndex);

HTTP请求头Range

首先,访问服务器资源,获取资源文件的长度,即ContentLength,然后将ContentLength进行划分,假设ContentLength=1000,开辟4个线程去分段下载,每段下载250个字节,那么每个线程的Range请求头部应该为

Thread1 Range:bytes=0-249
Thread2 Range:bytes=250-499
Thread3 Range:bytes=500-749
Thread4 Range:bytes=750-999

区间范围由自己定义即可,不一定非要按等分

当每个线程开始分段下载,访问RandomAccessFile的开始位置就应该是首字节的位置,如Thread2应该如下设置

//Thread2
randomAccessFile.seek(250);

手动停止或出现中断时,应该保存上次写入的最后一个字节位置,以作为下一次请求的开始。以上面作为例子,假设线程Thread2中断时,写入的最后一个字节的位置为350,那么恢复下载的时候,Thread2请求头就应该为

Range:bytes=351-499

此时Thread2访问RandomAccessFile的开始位置应该是351,即

//Thread2
randomAccessFile.seek(351);

最佳实践

Android断点续传下载器JarvisDownloader

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容

  • 前言 安卓技术学习图谱(持续更新中,欢迎关注)https://github.com/Sakuragi/androi...
    AIl_Blue阅读 2,658评论 0 27
  • Android多线程断点续传下载 原理 其实断点续传的原理很简单,从字面上理解,所谓断点续传就是从停止的地方重新下...
    压抑的内心阅读 662评论 0 0
  • 一、为什么要使用多线程,多线程真的能提高效率吗? 1.1为什么要使用多线程 多线程编程的目的,就是"最大限度地利用...
    程序员学园阅读 867评论 0 6
  • 来了 来了 褪去青涩 披上一抹浓郁的情 鸟儿唱出了夏的火热 知了声声呼唤 是夏的热,是生命的匆匆 那片云,送来了静...
    五月的罂粟阅读 121评论 0 1
  • **SF问答精选**《一》:如何引入第三方插件,调用自定义方法 **SF问答精选**《二》使用第三方库问题,swi...
    极乐叔阅读 162评论 0 0