app架构升级,Android多线程断点续传下载原理及实现_app 下载断点续传-程序员宅基地

技术标签: 程序员  经验分享  android  移动开发  

这段时间看了看工作室的工具库的下载组件,发现其存在一些问题:

1.下载核心逻辑有 bug,在暂停下载或下载失败等情况时有概率无法顺利完成下载。
2.虽然原来的设计是采用多线程断点续传的设计,但打了一下日志发现其实下载任务都是在同一个线程下串行执行,并没有起到加快下载速度的作用。

考虑到原来的代码并不复杂,因此对这部分下载组件进行了重写。这里记录一下里面的多线程断点续传功能的实现。

请查看完整的PDF版
(更多完整项目下载。未完待续。源码。图文知识后续上传github。)
可以点击关于我联系我获取完整PDF
(VX:mm14525201314)

多线程下载意义

首先我们谈一谈,多线程下载的意义。

在日常的场景下,网络中不可能只有下载方与服务器之间这样一条连接,为了避免在这样的场景下的网络拥塞,TCP 协议通过调节窗口的大小来避免出现拥塞,但这个窗口的大小可能没办法达到我们预期的效果:充分利用我们的带宽。因此我们可以采用多个 TCP 连接的形式来提高我们带宽的利用率,从而加快下载速度。

打个比喻就是我们要从一个水缸中用抽水机通过水管抽水,由于管子的直径等等的限制,我们单条管子无法完全利用我们的抽水机的抽水动力。因此我们就将这些抽水的任务分成了多份,分摊到多个管子上,这样就可以更充分的利用我们的抽水机动力,从而提高抽水的速度。

因此,我们使用多线程下载的主要意义就是——提高下载速度。

多线程下载原理

任务分配

前面提到了我们主要的目的是将一个总的下载任务分摊到多个子任务中,比如假设我们用 5 个线程下载这个文件,那么我们就可以对一个长度为 N 的任务进行如下图的均分:

但真实场景下往往 N 都不是刚好为 5 的倍数的,因此对于最后一个任务还需要加上剩余的任务量,也就是 N/5+N%5。

Http Range 请求头

上面的任务分配我们已经了解了,看起来很理想,但有一个问题,我们如何实现向服务器只请求这个文件的某一段而不是全部呢?

我们可以通过在请求头中加入 Range 字段来指定请求的范围,从而实现指定某一段的数据。

如:RANGE bytes=10000-19999 就指定了 10000-19999 这段字节的数据

所以我们的核心思想就是通过它拿到文件对应字节段的 InputStream,然后对它读取并写入文件。

RandomAccessFile 文件写入

下面再讲讲文件写入问题,由于我们是多线程下载,因此文件并不是每次都是从前往后一个个字节写入的,随时可能在文件的任何一个地方写入数据。因此我们需要能够在文件的指定位置写入数据。这里我们用到了RandomAccessFile 来实现这个功能。

RandomAccessFile 是一个随机访问文件类,同时整合了 FileOutputStreamFileInputStream,支持从文件的任何字节处读写数据。通过它我们就可以在文件的任何字节处写入数据。

接下来简单讲讲我们这里是如何使用 RandomAccessFile 的。我们对于每个子任务来说都有一个开始和结束的位置。每个任务都可以通过 RandomAccessFile::seek 跳转到文件的对应字节位置,然后从该位置开始读取 InputStream 并写入。

这样,就实现了不同线程对文件的随机写入。

文件大小的获取

由于我们在真正开始下载之前,我们需要先将任务分配到各个线程,因此我们需要先了解到文件的大小。

为了获取到文件的大小,我们用到 Response Headers 中的 Content-Length 字段。

如下图所示,可以看到,打开该下载请求的链接后,Response Headers 中包含了我们需要的 Content-Length,也就是该文件的大小,单位是字节。

断点续传原理

对于多个子任务,我们如何实现它们的断点续传呢?

其实原理很简单,只需要保证每个子任务的下载进度能够被即时地记录即可。这样继续下载时只需要读取这些下载记录,从上次下载结束的位置开始下载即可。

它的实现有很多方式,只要能做到数据持久化即可。这里我使用的是数据库来实现。

这样,我们的子任务需要拥有一些必要的信息

  • completedSize:当前下载完成大小
  • taskSize:子任务总大小
  • startPos:子任务开始位置
  • currentPos:子任务进行到的位置
  • endPos:子任务结束位置

通过这些信息,我们就能够记录子任务的下载进度从而恢复我们之前的下载,实现断点续传。

代码实现

下面我们用代码来实现这样一个多线程下载功能。

下载状态

首先,我们定义一下下载中的各个状态:

public class DownloadStatus {
    public static final int IDLE = 233;                    // 空闲,默认状态
    public static final int COMPLETED = 234;        // 完成
    public static final int DOWNLOADING = 235;    // 下载中
    public stati
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_57699613/article/details/117855627

智能推荐

自动发弹幕_直播自动发弹幕脚本-程序员宅基地

文章浏览阅读1w次,点赞2次,收藏10次。一个灰常简单的脚本,懂前端的人都能写出来代码地址及使用方法:https://github.com/xiongyizhu/auto-danmu_直播自动发弹幕脚本

MMU、Cache、TLB 的作用_mmu与tlb和cache的交互-程序员宅基地

文章浏览阅读1.4k次。VM通过页表转换成PM,MMU、Cache、TLB在转换过程中发挥作用:(1)PTE和PA都在Cache或者Memory中:(2)将Cache和Memory拆开描述,PTE和PA是否在Cache中命中:(3)PTE在Cache或Memory中,但是PA不在Cache或Memory中,只能访问Disk:(_mmu与tlb和cache的交互

centos无法删除用户 userdel:cannot remove entry ‘hadoop’ from /etc/passwd_cannot remove entry 'chuqianyun' from /etc/passwd-程序员宅基地

文章浏览阅读4.7k次。刚打算新建hadoop用户,发现居然有了,可是我也不知道密码呀...改也改不了。想着那总能让我删了吧,嗯哼,不行。如图:行吧,总有法子治你,比如:首先,进入home,执行命令vipw找到之前创建的用户,用dd删除该行(:wq保存退出)执行命令vipw -s 找到那个用户所属组,dd删掉即可(:wq保存退出)这时候修改密码检测一下就可以知道有没有删除了好..._cannot remove entry 'chuqianyun' from /etc/passwd

devexpress bandgridview使用总结(14.2)-程序员宅基地

文章浏览阅读791次。这两天利用bandgridview做表头,希望做成如下形状在制作过程中发现如果想实现动态表头,代码的书写顺序需要稍加注意实例化gridband绑定gridband至bandgridviewgridband属性设置实例化bandgridcolumn绑定bandgridcolumn至gridbandbandgridcolumn属性设置  绑定数..._gridband 设置visibleindex

2021-01-28_请把程序拷贝到“官方软件固件\pm3-bin-2.0.0\win32 (client+gui)”根目-程序员宅基地

文章浏览阅读174次。proxmark3 Easy问题及PM3重新连接的方法PM3软件界面如下:连接状态: 已连接(这是在自动识别串口号的方式下)如果有有问题就是下图:(这也是在自动识别串口号的方式下)在手动设置串口号的情况下:好了,下面说说遇到的情况:时间长了没用那个PM3,今天拿出来说使用下,结果用不了,环境:在WIN10的环境下,直接用桌面上的PM3程序,结果直接打不开,试了很多多方法都不行, 记得这是当时从原来另一台能用的电脑(win7)上直接复制过来的,重新装好..._请把程序拷贝到“官方软件固件\pm3-bin-2.0.0\win32 (client+gui)”根目录下再打

计算机网络安全员好就业吗,网络安全就业前景怎么样?-程序员宅基地

文章浏览阅读2.3k次。原标题:网络安全就业前景怎么样?现在无论是企业还是个人,都会注意网络安全。21世纪是信息化时代,我们的生活越来越离不开网络,但是与此同时,网页篡改、计算机病毒、系统非法入侵、数据泄密、网站欺骗、服务瘫痪、漏洞非法利用等信息安全事件时有发生,网络安全越来越被重视。但是由于我国网络安全起步晚,所以现在网络安全工程师十分紧缺。根据职友集的数据显示,当前市场上需求量较大的几类网络安全岗位,如安全运维、渗透..._网络安全博士就业

随便推点

layui总结_layui lay-affix="eye-程序员宅基地

文章浏览阅读480次。layui简介layui是一种采用自身模块规范编写的前端UI框架,遵循原生HTML/CSS/JS的书写组织形式,门槛极低,拿来即用. 无需涉足各种前端工具的复杂配置,只需面对浏览器本身.使用layui获取layui将其完整地部署到项目目录引用css文件和js文件初始化模块 //一般直接写在一个js文件中 layui.use(['layer'..._layui lay-affix="eye

fedora配置阿里云镜像_fedora 阿里云-程序员宅基地

文章浏览阅读536次。在使用dnf进行软件安装的时候,有时候会遇到软件安装的特别慢的情况,这时候可以使用国内一些镜像很好的解决这一问题。配置阿里云镜像备份mv /etc/yum.repos.d/fedora.repo /etc/yum.repos.d/fedora.repo.backupmv /etc/yum.repos.d/fedora-updates.repo /etc/yum.repos.d/fedora-updates.repo.backup下载新的文件下载新的fedora.repo和fedora-_fedora 阿里云

Nginx(一)_nginx重载语句-程序员宅基地

文章浏览阅读223次。Nginx(一)Nginx 的主要应用场景Nginx 的主要优点Nginx 的主要优点Nginx 的版本介绍 Nginx 目录并编译下载NginxautoCHANGES文件conf文件configure脚本contrib文件html目录man目录src 目录编译NginxNginx 配置语法Nginx 命令:重载,热部署,日志切割重载配置文件热部署日志切割Nginx 的主要应用场景静态资源服务反向代理服务API服务Nginx 的主要优点高并发,高性能可扩展性 - 模块化设计高可靠性 -_nginx重载语句

玩转图论算法C#版笔记03:图的广度优先遍历_c#:实现广度优先搜索遍历图算法-程序员宅基地

文章浏览阅读364次。广度优先遍历原理及代码实现、求最短路及对比两种遍历算法_c#:实现广度优先搜索遍历图算法

程序猿的春天是啥样子的?-程序员宅基地

文章浏览阅读575次。程序猿是啥?我的理解是脑子灵活思维li

Wsl2 Ubuntu18.04图形化界面,亲测成功_wsl ubuntu图形界面-程序员宅基地

文章浏览阅读8.2k次,点赞13次,收藏41次。Wsl2 Ubuntu18.04图形化界面,亲测成功Windows端Linux端最后抖抖索索搞了两天,差点Windows系统都重装,终于搞成功了。参考文献:一定要看非常感谢这个哥们,成功搞出来了。Windows端powershell内管理员模式运行wsl --list --verbose确保Version是22. ipconfig记wsl的IPv4地址:192.168.233.193.每个人不一样3.下载VcXSrv X server for Windows.提供给你们一个下载链_wsl ubuntu图形界面