剖析flutter_download_manager学习如何做下载管理,暂停和取消
前言
内容类应用中图片或文件下载,一般应用中应用更新和升级,这些都是经典的下载场景。下载是项目中基础且重要的模块。
从代码逻辑复用性和人力成本考虑,一直想实现一个纯Dart实现的下载库,作为技术储备。
最近发现了一个纯Dart实现的下载库flutter_download_manager,相对来说各方面还算满足需求,支持断点续传,暂停,取消等我比较看重的功能。但是有些地方还需要改进。
话不多说,首先简单介绍下这个库吧。
flutter_download_manager简介
地址: https://github.com/nabil6391/flutter_download_manager
版本: 0.5.4
特点:
- 纯Dart实现
- 通过 url 管理下载任务
- 能够通知状态和进度更改
- 部分下载功能
- 队列下载
- 暂停、取消或恢复下载
- 并行文件下载(2 个或可以更改)
- 支持批量下载
支持平台: Linux | MacOS | Windows | Android | iOS
使用方法
简单下载一个文件
var dl = DownloadManager();
var url = "adasdad.com/asda.sdas";
dl.addDownload(url, "./test.sdas");
DownloadTask? task = dl.getDownload(url4);
task?.status.addListener(() {
print(task.status.value);
});
task?.progress.addListener(() {
print(task.progress.value);
});
await dl.whenDownloadComplete(url4);
获取下载状态
DownloadTask? task = dl.getDownload(url4);
task?.status.addListener(() {
print(task.status.value);
});
获取下载进度
DownloadTask? task = dl.getDownload(url4);
task?.progress.addListener(() {
print(task.progress.value);
});
等待任务完成
DownloadTask? task = dl.getDownload(url4);
await task.whenDownloadComplete();
取消下载任务
var dl = DownloadManager();
dl.cancelDownload(url5);
暂停下载任务
var dl = DownloadManager();
dl.pauseDownload(url5);
恢复下载任务
var dl = DownloadManager();
dl.resumeDownload(url5);
效果展示

源码解析
类图

任务管理类:DownloadManager
整个核心就类DownloadManager, 而每个下载任务的抽象是DownloadTask,所谓Manager当然是要管理这些Task了。那么如何管理呢? 游离的没法管控,只有先找到才能调配,通过Map持有Task句柄达到“找到”目的,其中_cache中以<下载URL,下载任务>方式在内存中缓存每个任务状态;而_queue则是新添加的下载任务请求,这两者关系后面流程中会具体讲到。
任务的抽象:DownloadTask
重点说下status和progress字段设计,不论是批量下载还是单任务下载,进度监听不是通过传统传入一个回调给download或者addDownload来进行的,而是用了系统的ValueNotifier。笔者考虑这样设计原因是配合flutter系统提供的ValueListenerBuilder更容易组织UI。(这样的设计是不是看起来更Dart)
任务请求抽象:DownloadRequest
重点说下cancelToken,该字段在暂停,取消,恢复下载任务实现中起了关键作用。像放出去的风筝,想收回时可以收回。怎么收回呢?通过线,这条线的作用就是cancelToken。而风筝就像是一个个任务请求,放风筝的人就是Manager,放风筝这件事就是Task。
每个请求都必须带个cancelToken,方便取消请求。(不带线的风筝,难道让你上天?)
未标明方法说明
图中DownloadManager中方法只写了单任务下载相关方法,批量相关方法差不多就省略了,类似(add | pause | cancel | resume | remove ).BatchDownload等,最终通过循环执行了单实现的方法。
原理解析
如何管理任务
这里不具体阐述代码流程,为方便理解直接拿生活中惯用做事逻辑举例,代码实现可自行查阅,也是按照这个套路来滴,首先有两个集合:
- 任务请求列表,里面是想做的事情,每件事情如果非要定义状态的话,可以说是“规划中”。
后续简称任务列表均指请求列表。
- 任务管理表,里面的事情一般不会去记,在脑子里面。软件开发中,PM该表格维护者。

完成某任务一般流程如下:
- 生成一个任务请求表达意愿。
- 查询任务管理表中任务状态并决定是否有资格真正添加到请求列表。
- 已完成任务:3天前已经摸过了一次鱼,一周最多摸鱼一次,直接返回任务结果,否掉这种不切实际的想法,没脸加入请求列表。
- 未开始任务:一周没玩lol,可以将游戏添加到请求列表中,并更新到任务管理列表中。
- 未执行完任务:搬砖上次搬了50%下周继续搬。此时看你怎么处理了,若50%的砖还在,你可以继续搬,将任务添加到请求列表,从50%开始直到完成。若没搬的砖堆得横七竖八不想继续码,可删除任务管理表中记录,当一次新任务添加请求列表和管理列表中。
- 新规划任务:任务管理列表中无该记录的情况,当新任务重新添加到请求列表中。
- 循环执行请求列表中各任务并适时更新管理列表中状态,直至请求列表为空。
流程图如下:

如何实现暂停恢复取消
关键是对DownloadRequest中cancelToken的控制。
暂停任务

恢复任务

取消任务

暂停和取消任务骗谁呢?
一般理解暂停表示之前下载了50%,恢复后继续从50%下载;取消表示之前下载50%点击恢复重头再来。
暂停和取消逻辑除更新状态不一样其他基本一样,是在忽悠我么?
莫慌!在下载时候还有处理呢?
通过上述恢复实现与如下下载中逻辑归纳整个暂停实现流程:
- 恢复下载中③④⑤会赋予暂停中url新的CancelToken重新添加到请求列表中,并开启请求列表的自遍历执行。
- 请求列表的自遍历执行是给暂停掉Task重新执行的机会,Cancel掉的任务就没法再执行了(下述第6行)。
- 下载过程中如果之前暂停未下载完毕的文件,通过设置header中range:bytes来实现断点续传(下述第29行)。

优点和缺点
优点
- 逻辑复用:Dart侧支持暂停,取消,恢复,下载流程,一般下载框架会用桥接实现,涉及到多端实现和通用性问题,比较耗人力。要么就是dio简单实现下载,没有暂停恢复等实现。
- 任务管理,一般应用都是单任务下载,没有管理过程。
- 代码简单明了可读性强,类抽象合理符合单一职责。
缺点
- 任务管理列表只实现了内存缓存未实现磁盘缓存,应用退出再进入啥都没了。
- 网络库不支持扩展,太过依赖dio。
预告:下一篇将实现dio解耦和网络库扩展。
import 'package:dio/dio.dart';
class DownloadRequest {
var cancelToken = CancelToken();
}
------------------------------------------------
import 'package:dio/dio.dart';
class DownloadManager {
var dio = Dio();
Future<void> download(String url, String savePath, cancelToken,
{forceDownload = false}) async {
//...
if(fileExist){
}else(partialFileExist)
{
var response = await dio.download(...);
}else{
var response = await dio.download(...);
}
总结
任务管理体现在列表的增删改查; 断点续传体现在range设置;任务取消单纯通过请求库取消实现。
️本文由 编程黑板报 原创,欢迎关注同名公众号,原创技术文章第一时间推送️
剖析flutter_download_manager学习如何做下载管理,暂停和取消的更多相关文章
- linux基础命令学习五(软件包管理、下载管理)
Linux 软件包管理 本文主要是记录下RedHat系列的软件包管理. 内容分为以下二个部分:二进制包的管理,源代码包的管理 一.二进制包的管理 1.1概念 主要有RPM和YUM这两种包管理. 两 ...
- DICOM医学图像处理:storescp.exe与storescu.exe源码剖析,学习C-STORE请求
转载:http://blog.csdn.net/zssureqh/article/details/39213817 背景: 上一篇专栏博文中针对PACS终端(或设备终端,如CT设备)与RIS系统之间w ...
- 蓝牙芯片NRF51822入门学习1:时间管理
前言 之前辞职找工作的时候发现,很多公司希望招聘蓝牙技术方面的人才,所以干脆丢开LWIP静下心来学习蓝牙技术.原本以为一两星期能基本学会的,谁知道所选的蓝牙芯片nrf51822是个坑货,坑了我一个月. ...
- Android下载管理DownloadManager功能扩展和bug修改
http://www.trinea.cn/android/android-downloadmanager-pro/ 本文主要介绍如何修改Android系统下载管理,以支持更多的功能及部分bug修改和如 ...
- Spring5.0源码学习系列之事务管理概述
Spring5.0源码学习系列之事务管理概述(十一),在学习事务管理的源码之前,需要对事务的基本理论比较熟悉,所以本章节会对事务管理的基本理论进行描述 1.什么是事务? 事务就是一组原子性的SQL操作 ...
- DICOM医学图形处理:storescp.exe与storescu.exe源码剖析,学习C-STORE请求(续)
转载:http://blog.csdn.net/zssureqh/article/details/39237649 背景: 上一篇博文中,在对storescp工具源文件storescp.cc和DcmS ...
- Chrome 应用推荐 - 下载管理扩展: Chrono
地址:http://goo.gl/JVdxvg Chrono下载管理器让你轻松高效地管理Chrome浏览器中的下载任务.Chrono与Chrome浏览器紧密地整合在一起,如菜单.工具栏支持等等.Chr ...
- DownloadManager 下载管理类
演示 简介 从Android 2.3开始新增了一个下载管理类,在SDK的文档中我们查找android.app.DownloadManager可以看到.下载管理类可以长期处理多个HTTP下载任务,客户端 ...
- 从零开始学习PYTHON3讲义(十六)(连载完)学习资源包下载
<从零开始PYTHON3>学习资源包下载 课程连载已经完全结束. 经过整理校对,这里把在课程中出现过的源码和练习答案示例源码全部打包提供下载: https://pan.baidu.com/ ...
- Linux学习之RPM包管理-yum管理(十七)
Linux学习之RPM包管理-yum管理 目录 IP地址配置 网络yum源 yum命令 光盘yum源搭建 IP地址配置 IP+子网掩码就可以在局域网(内网)使用. IP+子网掩码+网关+DNS就可以访 ...
随机推荐
- 深入浅出OSI七层参考
本篇博客是笔者阅读<图解TCP/IP>所记录下的笔记,有兴趣的朋友可以去看一看这本书. OSI七层参考模型 本小节以电子邮件通信为例,分别来阐述OSI七层模型的每一层是如果进行通信处理 ...
- Django框架版本区别
目录 一:django版本区别 1.django1.X路由层使用的是url方法 2.虽然path不支持正则 但是它的内部支持五种转换器 3.五种转换器 4.除了有默认的五个转换器之外 还支持自定义转换 ...
- 【机器学习】李宏毅——生成式对抗网络GAN
1.基本概念介绍 1.1.What is Generator 在之前我们的网络架构中,都是对于输入x得到输出y,只要输入x是一样的,那么得到的输出y就是一样的. 但是Generator不一样,它最大的 ...
- python 之异常捕获及处理(try--except)
在python中,至少有两类错误,一种是程序语法错误,一种是程序异常. 所谓的语法错误是指你未按规定格式书写导致的错误,如:定义函数时,括号后面要紧跟英文冒号,若缺失则不能识别与运行,并抛出 Synt ...
- JavaScript:函数:函数的参数
声明函数的时候,有个括号,这里面可以加上函数的参数,这些参数,我们叫做形参(形式参数): 此时这些参数,也是已经声明了的变量,只是还没有赋值而已. 也可以不加,取决于函数的逻辑.如果函数需要从外部传进 ...
- Ng-Matero v15 正式发布
前言 Angular 按照既定的发版计划在 11 月中旬发布了 v15 版本.推迟了一个月(几乎每个版本都是这个节奏),ng-matero 也终于更新到了 v15.其实 ng-matero 本身的更新 ...
- Spring中使用@RequestBody注解接收的实体类中的某些参数为null
1.问题描述 我写完一个接口,在用postman测试的时候,发现其中有一个参数cEnterpriseId明明是有值的,但接口controller接收到的该参数为null,但其他参数都不为null的. ...
- python之路47 django路由层配置 虚拟环境
可视化界面之数据增删改查 针对数据对象主键字段的获取可以使用更加方便的obj.pk获取 在模型类中定义双下str方法可以在数据对象被执行打印操作的时候方便的查看 ''' form表单中能够触发提交动作 ...
- 03-Sed基础语法及例子
1 Sed语法及举例 在实际使用sed过程中经常使用字符串的替换.删除.查找等操作.Linux中的编辑器Vi.GVIM.emacs等都可以进行上述操作,但是大量进行操作的时候,效率很低. 地址参数 { ...
- Redefinition of 'y1' as different kind of symbol
Redefinition of 'y1' as different kind of symbol 原因 解释:此次定义的y1变量与函数库中定义的y1重名了,所以编译错误,重定义了y1变量. 解决方法: ...