Android 断点续传实现原理

2024-06-16 10:04

本文主要是介绍Android 断点续传实现原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

下载原理
在介绍断点续传之前,我们先说说下载的原理。代码示例用 OkHttp 作为示例。

下载核心思路是把 responseBody 写入文件,核心代码如下:

但是这种做法有个明显的问题,假如手机在下载文件的时候下载了80%,某些原因断网了,如果不支持断点续传,那就只有被迫重头开始下载。但是如果有断点续传的加持,就只需要下载最后 20% 的资源,避免重新下载。

断点续传原理
1、java.io.RandomAccessFile
断点续传/下载需要使用到 java.io.RandomAccessFile 类,RandomAccessFile 的实例支持读取和写入随机访问文件,它也可以 seek(long pos) 设置从此文件的开头开始测量的文件指针偏移量,在该位置进行下一次读取或写入操作。简单点说就是可以通过 seek(long pos)方法跳过pos字节开始写入字节。

如何创建一个 RandomAccessFile ?

//rw:支持可读可写
val file = RandomAccessFile(file, "rw")

假如我有一段文本要写入文件,但是需要从文件的第100个字节开始写,那么需要调用 seek(long pos ) 方法跳过前 100 个字节, 具体实现如下:

val file = RandomAccessFile(file, "rw")
file.seek(100)
file.writeBytes(.....)

所以,我们可以把 responseBody 写入文件的实现改成如下实现:

2、请求响应码及Header
正常情况下,我们下载一个文件,响应码是 200

responseBody 返回的是整个文件的内容。如何才能返回部分内容?
在实现分块请求之前,首先要判断服务器是否支持分块返回,标志是 Access-Ranges ,值为 bytes 就代表服务器支持分块返回,也就是支持断点续传。

所以,我们可以封装一个方法,来判断服务是否支持断点续传

在确定了服务器支持分块传输后,我们就可以在请求资源的时候,添加 header 请求 Range 字段,来指定请求实体的范围。它的范围取值是在 0-Content-Length 之间,使用 - 分割。

例如已经下载了 1000 bytes 的资源内容,想接着继续下载之后的资源内容,只要在 HTTP 请求头部,增加 Range:bytes=1000- 就可以了。

Range 还有几种不同的方式来限定范围,可以根据需要灵活定制:

500-1000:指定开始和结束的范围。
500- :指定开始区间,一直传递到结束。这个就比较适用于断点续传、或者在线播放等等。
-500:无开始区间,只意思是需要最后 500 bytes 的内容实体。
100-300,1000-3000:指定多个范围,这种方式使用的场景很少,了解一下就好了。
具体举例如下:

通过抓包我们发现,添加了 Range 后,请求响应码变成了 206


并且添加 Range 后,响应的 responseBody 就不再是整个文件的内容了,而是一个片段,我们只需要把这个片段的数据直接写入文件就可以。

注意事项,如何计算 Range 请求头的开始值,一般取用缓存文件的长度值,如下

val start = targetFile.length()

3、处理请求资源发生改变的问题
在现实的场景中,服务器中的文件是会有发生变化的情况的,那么我们发起续传的请求肯定是失败的

那么为了处理这种服务器文件资源发生改变的问题,在 RFC2616 中定义了 Last-Modified和 Etag 来判断续传文件资源是否发生改变。

Last-Modified:记录 Http 页面最后修改时间的 Http 头部参数,Last-Modified 是由服务端发送给客户端的
Etag:作为文件的唯一标志,这个标志可以是文件的 hash 值或者是一个版本
我们封装一个方法用来获取这两个值

if-Range:用于判断实体是否发生改变,如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。一般格式:

If-Range: Etag | HTTP-Date

If-Range 可以使用 Etag 或者 Last-Modified 返回的值。当没有 ETage 却有 Last-modified 时,可以把 Last-modified 作为 If-Range 字段的值。实现举例如下:

关于 Etag 、Last-Modified 注意事项:

当第一次请求资源的时候,获取 Etag/Last-Modified 值,并且保存到本地
当下一次需要断点续传的时候,把 Etag/Last-Modified 值取出,添加到请求头 If-Range 字段
4、文件可复用判断
在文件下载完成后,如果又发起了一次下载请求,那么此时不应该重复下载的。需要做可复用判断,思路如下

1、获取目前已下载文件的大小
2、获取文件url 获取服务器文件大小
3、如果已下载大小等于服务器文件大小,则复用已下载的文件
举例如下:

//获取已下载文件长度
val downloadLength = targetFile.length()
//获取服务器文件长度
val contentLength = responseBody.contentLength()
//两者长度对比
if(downloadLength == contentLength){//复用已下载文件,不再重复下载
} 



原文链接:https://blog.csdn.net/zhaoyanjun6/article/details/120956134

这篇关于Android 断点续传实现原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1066151

相关文章

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

redis中使用lua脚本的原理与基本使用详解

《redis中使用lua脚本的原理与基本使用详解》在Redis中使用Lua脚本可以实现原子性操作、减少网络开销以及提高执行效率,下面小编就来和大家详细介绍一下在redis中使用lua脚本的原理... 目录Redis 执行 Lua 脚本的原理基本使用方法使用EVAL命令执行 Lua 脚本使用EVALSHA命令

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

Python位移操作和位运算的实现示例

《Python位移操作和位运算的实现示例》本文主要介绍了Python位移操作和位运算的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 位移操作1.1 左移操作 (<<)1.2 右移操作 (>>)注意事项:2. 位运算2.1

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依