剖析flutter_download_manager学习如何做下载管理,暂停和取消

神行太保
• 阅读 1310

前言

内容类应用中图片或文件下载,一般应用中应用更新和升级,这些都是经典的下载场景。下载是项目中基础且重要的模块。

从代码逻辑复用性和人力成本考虑,一直想实现一个纯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);

效果展示

剖析flutter_download_manager学习如何做下载管理,暂停和取消

源码解析

类图

剖析flutter_download_manager学习如何做下载管理,暂停和取消

任务管理类: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该表格维护者。

剖析flutter_download_manager学习如何做下载管理,暂停和取消

完成某任务一般流程如下:

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

流程图如下:

剖析flutter_download_manager学习如何做下载管理,暂停和取消

如何实现暂停恢复取消

关键是对DownloadRequest中cancelToken的控制。

暂停任务

剖析flutter_download_manager学习如何做下载管理,暂停和取消

恢复任务

剖析flutter_download_manager学习如何做下载管理,暂停和取消

取消任务

剖析flutter_download_manager学习如何做下载管理,暂停和取消

暂停和取消任务骗谁呢?

一般理解暂停表示之前下载了50%,恢复后继续从50%下载;取消表示之前下载50%点击恢复重头再来。

暂停和取消逻辑除更新状态不一样其他基本一样,是在忽悠我么?

莫慌!在下载时候还有处理呢?

通过上述恢复实现与如下下载中逻辑归纳整个暂停实现流程:

  1. 恢复下载中③④⑤会赋予暂停中url新的CancelToken重新添加到请求列表中,并开启请求列表的自遍历执行。
  2. 请求列表的自遍历执行是给暂停掉Task重新执行的机会,Cancel掉的任务就没法再执行了(下述第6行)。
  3. 下载过程中如果之前暂停未下载完毕的文件,通过设置header中range:bytes来实现断点续传(下述第29行)。

剖析flutter_download_manager学习如何做下载管理,暂停和取消

优点和缺点

优点

  • 逻辑复用: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设置;任务取消单纯通过请求库取消实现。

❤️本文由 编程黑板报 原创,欢迎关注同名公众号,原创技术文章第一时间推送。❤️
点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Easter79 Easter79
3年前
vue+axios下载pdf文件流
项目中用到流文件下载的需求,之前使用的方法一直都没问题,但是这次就是下载不下来,查了多种方法终于解决了,方式如下://下载文件downLoadFile(e){letide.target.dataset.id;letnamee.target.dataset.name;
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
Python 环境搭建
pythonbug集目录\toc\00python模块下载地址pyhton模块下载地址(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.lfd.uci.edu%2F%7Egohlke%2Fpythonlibs%2F)01pythonpip
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
3年前
Android版添加phonegap
1.下载插件包。2\.解压所下载的包,从lib目录中得到所需要的所有的库:BaiduSocialShareSDKAndroid2.0.0.jar3\.修改AndroidManifest.xml,增加以下权限:<usespermissionandroid:name"android.permiss
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
神行太保
神行太保
Lv1
暂时还承受不起任何人的爱意。
文章
3
粉丝
0
获赞
0