Android基于Flutter编写文件下载管理器

目录
  • 前言
  • Dio 的下载方法 download
  • 监测下载进度
  • 取消下载
  • 删除已经下载的文件
  • 调试过程中遇到的一些错误
  • 运行结果及代码
  • 总结

前言

文件下载在很多类型的应用中会涉及,例如音乐、文档、包括图片(只是图片可以使用一些组件完成无感知的下载)。本篇介绍使用 Dio 的下载方法完成文件的下载,涉及到的内容如下:

  • Dio 插件的 download 方法介绍;
  • 使用 download 的回调方法监测下载进度;
  • 使用 CancelToken 取消正在下载的任务;
  • 删除已下载的文件;
  • path_provider 插件管理App文件目录;
  • 下载文件调试过程中发现的一些问题;

Dio 的下载方法 download

Dio 的下载方法定义如下:

Future<Response> download(
  String urlPath,
  savePath, {
  ProgressCallback? onReceiveProgress,
  Map<String, dynamic>? queryParameters,
  CancelToken? cancelToken,
  bool deleteOnError = true,
  String lengthHeader = Headers.contentLengthHeader,
  data,
  Options? options,
});
  • urlPath:网络资源的 url
  • savePathdynamic 类型,可以是下载后存储文件路径的字符串,也可以是一个返回字符串的回调方法(Dio 会把 headers 参数携带过去,方便针对下载返回内容构建文件路径);
  • onReceiveProgress:文件接收进度,是一个void Function(int count, int total)回调函数,调用者可以通过该回调方法监测下载进度。
  • deleteOnError:发生错误时候是否删除已下载的文件,默认是 true。
  • lengthHeader:源文件的实际大小(未压缩前)。默认是 header 的content-length。如果文件压缩了,而没有指定该值的话,那进度回调里的total会是-1;如果使用自定义的 header 指定了文件的大小,那么total会是自定义的 header 对应的文件大小。
  • 其他参数和普通的请求差不多,这里不再赘述。

为了不暴露下载的具体实现,我们在 http_util.dart 中封装一个自己的下载方法。

static Future download(
  String url,
  String savePath, {
  Map<String, dynamic> queryParams,
  CancelToken cancelToken,
  dynamic data,
  Options options,
  void Function(int, int) onReceiveProgress,
}) async {
  try {
    return await _dioInstance.download(
      url,
      savePath,
      queryParameters: queryParams,
      cancelToken: cancelToken,
      onReceiveProgress: onReceiveProgress,
    );
  } on DioError catch (e) {
    if (CancelToken.isCancel(e)) {
      EasyLoading.showInfo('下载已取消!');
    } else {
      if (e.response != null) {
        _handleErrorResponse(e.response);
      } else {
        EasyLoading.showError(e.message);
      }
    }
  } on Exception catch (e) {
    EasyLoading.showError(e.toString());
  }
}

监测下载进度

我们新建一个文件下载页面 file_download.dart完成文件下载的示例。这里定义了几个属性来对文件下载过程进行反馈:

// 文件下载地址,这里是谷歌浏览器的下载地址(Mac 版本)
String _downloadPath =
      'https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg';
// 下载进度比例,用于检测下载是否完成
double _downloadRatio = 0.0;
// 下载进度百分比
String _downloadIndicator = '0.00%';
// 下载文件的存储路径
String _destPath;
// 取消下载的 token
CancelToken _token;
// 指示当前是否处于下载中,以便做业务判断
bool _downloading = false;

然后我们定义一个下载方法,在下载过程中如果 total 不为-1就更新下载进度,否则提示错误(实际调试发现,如果涉及到需要验证的,下载后后端实际会返回网页,这样也能下载网页内容下来,但是不是想要的文件)。

void _downloadFile() {
  _token = CancelToken();
  _downloading = true;
  HttpUtil.download(_downloadPath, _destPath, cancelToken: _token,
      onReceiveProgress: (int received, int total) {
    if (total != -1) {
      if (!_token.isCancelled) {
        setState(() {
          _downloadRatio = (received / total);
          if (_downloadRatio == 1) {
            _downloading = false;
          }
          _downloadIndicator =
              (_downloadRatio * 100).toStringAsFixed(2) + '%';
        });
      }
    } else {
      _downloading = false;
      EasyLoading.showError('无法获取文件大小,下载失败!');
    }
  });
}

这里因为涉及到可能取消,因此只有在没有取消的情况下才更新下载状态,要不可能会出现取消的时候还处在下载接收字节的过程中,虽然取消了但是看到下载进度还在走的情况。

取消下载

取消下载其实很简单,当我们点击取消按钮的时候,调用 CancelToken 的cancel方法即可。这里我们做了一个判断,下载比例低于1才可以取消,因为下载完成再取消会抛出异常。同时取消后重置下载比例和显示的下载百分比。

void _cancelDownload() {
  if (_downloadRatio < 1.0) {
    _token.cancel();
    _downloading = false;
    setState(() {
      _downloadRatio = 0;
      _downloadIndicator = '0.00%';
    });
  }
}

删除已经下载的文件

对于 App,没有别的入口管理文件,因此实际过程中我们需要提供下载入口供用户清理已下载的文件。实际已下载的文件,我们需要有下载文件管理功能供用户管理文件,这个时候会需要本地存储支撑,我们在后续的章节会介绍本地存储。

删除文件前需要判断文件是否存在,如果文件不存在删除可能抛出异常。文件的管理使用的是 dart:io 中的方法。

void _deleteFile() {
  try {
    File downloadedFile = File(_destPath);
    if (downloadedFile.existsSync()) {
      downloadedFile.delete();
    } else {
      EasyLoading.showError('文件不存在');
    }
  } catch (e) {
    EasyLoading.showError(e.toString());
  }
}

path_provider文件目录管理

在 App 中没法直接知道应用的文件存储目录,因此需要借用 path_provider 插件来获取 App 的文件存储目录,path_provider 提供了如下方法:

  • getTemporaryDirectory:应用临时目录(可能被清除)
  • getApplicationDocumentsDirectory:应用文档目录(不会被系统清除,主要用户数据存储目录),对于安卓推荐使用外部存储getExternalStorageDirectory。
  • getApplicationSupportDirectory:应用支持目录,一般放置与用户无关的数据。
  • getLibraryDirectory:指向应用可以持久存储数据的目录,不支持安卓平台。
  • getExternalStorageDirectory:获取外部存储目录,不支持 iOS 平台。
  • getExternalCacheDirectories:获取外部缓存目录,,不支持 iOS 平台。
  • getExternalStorageDirectories:获取外部可以的目录列表,不支持 iOS 平台。
  • getDownloadsDirectory:获取下载目录,用于 Web 端,不支持安卓和 iOS平台。

通过 path_provider拿到Directory对象后,就可以通过 Directory的 path 属性获取到完整的目录路径。本例我们是在 initialState 里获取文件存储路径的,使用的是临时目录。

void initState() {
  getTemporaryDirectory()
      .then((tempDir) => {_destPath = tempDir.path + 'googlechrome.dmg'});

  super.initState();
}

调试过程中遇到的一些错误

  • OS Error: Read-only file system:安卓系统需要获取READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE权限。同时需要使用 path_provider获取应用的文件目录再往对应的目录读写文件和访问文件目录。
  • onReceivedProgress 中如果total=-1则表示该文件被压缩或者需要会话信息才可以下载(如后端开启了验证)。
  • 删除文件的时候需要检查文件是否在下载过程中,如果在下载过程中删除会引起文件读写冲突,抛出异常。
  • CancelToken一个实例只能取消一次请求,因此每次发起请求的时候需要重新构建CancelToken对象,否则取消一次后无法再次取消。

运行结果及代码

运行结果如下图所示:

屏幕录制2021-07-24 下午9.59.04.gif

总结

从示例可以看到,Dio 的下载方法是简单易用的,而且提供了友好的下载反馈。同时,借助 CancelToken 也能取消或者暂停下载(暂停时设置deleteOnError=false,表示不删除文件,然后恢复到时候从已下载的偏移量开始,也可以按这种方式做断点续传,具体方式可以搜索或者自己完成)。Dio 网络请求系列的详细介绍到这一篇结束,后续实际业务用到的时候再穿插介绍,接下来一篇将对 Dio 系列文章做一个整体总结。

以上就是Android基于Flutter编写文件下载管理器的详细内容,更多关于Android文件下载的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android实现下载文件功能的方法

    本文所述为Android实现下载文件功能的完整示例代码,对于学习和研究android编程相信会有一定的帮助,尤其是对Android初学者有一定的借鉴价值. 完整功能代码如下: package com.test; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import and

  • Android实现文件下载

    前言 总体思路:下载文件到应用缓存路径,在相册创建文件夹,Copy过去,通知相册刷新. 下载文件到APP缓存路径,这样可避免Android高版本读取本地权限问题, 准备 implementation 'com.squareup.okhttp3:okhttp:3.6.0' implementation 'com.squareup.okio:okio:1.11.0' 调用 url:文件url path:储存的路径 应用缓存路径:getExternalCacheDir().getPath() Down

  • Android简单实现文件下载

    本文实例为大家分享了Android简单实现文件下载的具体代码,供大家参考,具体内容如下 权限 <!-- 文件读写权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- 访问内存 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_S

  • android实现文件下载功能

    android 在网络上下载文件,供大家参考,具体内容如下 步骤 : 1.使用HTTP协议下载文件 - 创建一个HttpURLConnection对象 : HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); - 获取一个InputStream对象 : urlConn.getInputStream() - 访问网络的权限 : android.permission.INTERNET 2.将下载的文件写入SDCAR

  • Android文件下载功能实现代码

    本文实例为大家分享了Android文件下载功能的具体代码,供大家参考,具体内容如下 1.普通单线程下载文件: 直接使用URLConnection.openStream()打开网络输入流,然后将流写入到文件中! public static void downLoad(String path,Context context)throws Exception { URL url = new URL(path); InputStream is = url.openStream(); //截取最后的文件名

  • Android利用DownloadManager实现文件下载

    Android中文件下载,app更新,我们一般利用的都是 Retrofit或者 Okhttp等实现,但其实Android 早在API 9之后,就为我们提供了DownLoadManager,这是Android提供的系统服务,通过这个服务下载文件,整个过程全部交给了系统负责,免去了我们别的操作. 下面我们就来实地演示一下操作. 测试api sdk28, Android Studio3.4 小米5s Plus 代码如下: //定义一个成功接口 public interface IDownloadlis

  • Android基于Flutter编写文件下载管理器

    目录 前言 Dio 的下载方法 download 监测下载进度 取消下载 删除已经下载的文件 调试过程中遇到的一些错误 运行结果及代码 总结 前言 文件下载在很多类型的应用中会涉及,例如音乐.文档.包括图片(只是图片可以使用一些组件完成无感知的下载).本篇介绍使用 Dio 的下载方法完成文件的下载,涉及到的内容如下: Dio 插件的 download 方法介绍: 使用 download 的回调方法监测下载进度: 使用 CancelToken 取消正在下载的任务: 删除已下载的文件: path_p

  • Android基于OkHttp实现文件上传功能

    本文实例为大家分享了Android基于OkHttp实现文件上传的具体代码,供大家参考,具体内容如下 一.相关概述 Android请求访问服务端大多数情况下依旧是使用http协议,故而可以参照web端的数据传输形式来实现. multipart/form-data是浏览器提交表单上传文件的一种方式. 有关于http的get,post请求大家可以自行百度了解. OkHttp是一款优秀的HTTP框架,它支持get请求和post请求,支持基于Http的文件上传和下载,支持加载图片,支持下载文件透明的GZI

  • 基于Android Flutter编写贪吃蛇游戏

    目录 前言 开发步骤: 1.定义蛇和豆子 2.让蛇动起来 3.使用陀螺仪来控制蛇 4.让蛇吃掉豆子 5.吃掉豆子随机生成一个豆子 前言 放假期间,小T打算回顾一下经典,想用Flutter做一下小游戏,做什么好呢,从打飞机到坦克大战,最后还是想做一款贪吃蛇,依稀还记得,小时候第一次玩游戏是在父母的小灵通上玩贪吃蛇哈哈,但是光光一个贪吃蛇太单调了,我们就加一个陀螺仪吧~ 话不多说,先上效果图,有图有真相!!(陀螺仪好难操控)! 开发步骤: 非常简单,就是玩起来有点费手~ github仓库还没有搭建,

  • Android编程解析XML文件的方法详解【基于XmlPullParser】

    本文实例讲述了Android编程解析XML文件的方法.分享给大家供大家参考,具体如下: 前言 在学习Android的Framework层源码时,Android大量的使用XmlPullParser来解析xml文件的源码.因此,这里也顺道介绍一下XmlPullParser的使用. XML XML(eXtensible Markup Language)中文名为可扩展标记语言.标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种信息的文章等. 用途 XML设计用了传送及携带数据信息,

  • Android基于Http协议实现文件上传功能的方法

    本文实例讲述了Android基于Http协议实现文件上传功能的方法.分享给大家供大家参考,具体如下: 注意一般使用Http协议上传的文件都比较小,一般是小于2M 这里示例是上传一个小的MP3文件 1.主Activity:MainActivity.java public class MainActivity extends Activity { private static final String TAG = "MainActivity"; private EditText timel

  • Golang+Android基于HttpURLConnection实现的文件上传功能示例

    本文实例讲述了Golang+Android基于HttpURLConnection实现的文件上传功能.分享给大家供大家参考,具体如下: 这里要演示的是使用Android程序作为客户端(使用HttpURLConnection访问网络),Golang程序作为服务器端,实现文件上传. 客户端代码: public static String uploadFile(String uploadUrl, String filePath) { Log.v(TAG, "url:" + uploadUrl)

  • Android基于socket实现的简单C/S聊天通信功能

    本文实例讲述了Android基于socket实现的简单C/S聊天通信功能.分享给大家供大家参考,具体如下: 主要想法:在客户端上发送一条信息,在后台开辟一个线程充当服务端,收到消息就立即回馈给客户端. 第一步:创建一个继续Activity的SocketClientActity类,包为com.pku.net 编写布局文件socketclient.xml,代码如下: <?xml version="1.0" encoding="utf-8"?> <Lin

  • 详解Android 基于TCP和UDP协议的Socket通信

    本来想讲一下基础的网络通信方面的知识点,发现太枯燥乏味了,不过笔试中也经常会问到这方面的问题,所以关于通信方面的知识点,小编会放到面试中去,因为实战中也就面试会用到这方面知识点 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是"请求-响应方式",即在请求时建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据. 而Socket通信中基于TCP/IP协议的通信则是在双方建立起连接后就可以直接进行数

  • Android基于TCP和URL协议的网络编程示例【附demo源码下载】

    本文实例讲述了Android基于TCP和URL协议的网络编程.分享给大家供大家参考,具体如下: 手机本身是作为手机终端使用的,因此它的计算能力,存储能力都是有限的.它的主要优势是携带方便,可以随时打开,而且手机通常总是处于联网状态.因此网络支持对于手机应用非常重要. Android完全支持JDK本身的TCP,UDP网络通信API,也可以使用ServerSocket,Socket来建立基于TCP/IP协议的网络通信,也可以使用DatagramSocket,Datagrampacket来建立基于UD

  • 基于Flutter实现图片选择和图片上传

    目录 内容简介 图片选择插件 权限申请 UI 改造 图片上传 内容简介 本篇将介绍 Flutter 中如何完成图片上传,以及上传成功后的表单提交.涉及的知识点如下: 图片选择插件wechat_assets_picker的使用. 图片选择 iOS 和安卓的应用权限配置. 图片选择组件的封装. 图片上传接口的封装. 添加和编辑页面中图片上传实现. 图片选择插件 Flutter 的图片选择插件很多,包括了官方的 image_picker,multi_image_picker(基于2.0出了 multi

随机推荐