flutter开发实战-dio文件下载实现

flutter开发实战-dio文件下载实现

在开发中,需要下载文件,这里使用的是dio
dio 是一个强大的 Dart HTTP 请求库,支持全局配置、Restful API、FormData、拦截器、 请求取消、Cookie 管理、文件上传/下载、超时以及自定义适配器等。

在这里插入图片描述

一、引入dio

在工程中pubspec.yaml引入dio

dio: ^5.1.1dio_cookie_manager: ^3.0.0

二、代码实现

我们对dio进行封装

// 定义枚举,请求方法枚举
enum HttpApiMethod {GET,POST,DELETE,PUT,
}// 网络请求的成功与失败
// 上传
typedef OnUploaded = void Function(Map<String, dynamic> result);
// 下载进度
typedef OnDownloadProgress = void Function(int count, int total);
// 下载成功
typedef OnDownloaded = void Function();
// 请求成功
typedef OnSuccess = void Function(ResponseData responseData);
// 请求失败
typedef OnFailure = void Function(ApiHttpError error);// 请求Api
class HttpApi {// 网络请求库dioDio dio = Dio(BaseOptions(// connectTimeout: 60000, // 连接服务器超时时间,单位是毫秒.// receiveTimeout: 10000, // 响应流上前后两次接受到数据的间隔,单位为毫秒, 这并不是接收数据的总时限headers: {HttpHeaders.acceptHeader: "text/plain,""text/plain,""multipart/form-data,""application/json,""text/html,""image/jpeg,""image/png,""application/octet-stream,""text/json,""text/javascript,""text/html",},));// 私有构造函数HttpApi._internal();//保存单例static HttpApi _singleton = HttpApi._internal();//工厂构造函数factory HttpApi() => _singleton;/// 配置请求头header///   /// The request Content-Type. The default value is 'application/json; charset=utf-8'.//   /// If you want to encode request body with 'application/x-www-form-urlencoded',//   /// you can set [Headers.formUrlEncodedContentType], and [Dio]//   /// will automatically encode the request body.Future<void> configHeaders(String requestUrl, Map<String, dynamic>? params) async {dio.options.headers['Content-Type'] = Headers.jsonContentType;LoggerManager().info("requestUrl:${requestUrl} dio.options.headers:${dio.options.headers}");}get(String url, ApiServiceDomain serviceDomain,{Map<String, dynamic>? params, OnSuccess? success, OnFailure? failure}) {doRequest(url, serviceDomain, HttpApiMethod.GET,params: params, success: success, failure: failure);}post(String url, ApiServiceDomain serviceDomain,{Map<String, dynamic>? params, OnSuccess? success, OnFailure? failure}) {doRequest(url, serviceDomain, HttpApiMethod.POST,params: params, success: success, failure: failure);}// 请求服务器// params,参数// 请求成功// 请求失败Future<void> doRequest(String url, ApiServiceDomain serviceDomain, HttpApiMethod method,{Map<String, dynamic>? params,OnSuccess? success,OnFailure? failure}) async {String requestUrl = getRequestUrl(url, serviceDomain);try {/// 可以添加headerawait configHeaders(requestUrl, params);Response? response;switch (method) {case HttpApiMethod.GET:{// get请求if (params != null && params.isNotEmpty) {response = await dio.get(requestUrl,queryParameters: params,options: Options(contentType: Headers.jsonContentType));LoggerManager().debug("await dio.get response:$response,params:$params");} else {response = await dio.get(requestUrl,options: Options(contentType: Headers.jsonContentType));}break;}case HttpApiMethod.POST:{// post请求String? contentType = Headers.formUrlEncodedContentType;if (params != null && params.isNotEmpty) {response = await dio.post(requestUrl,data: params, options: Options(contentType: contentType));LoggerManager().debug("await dio.post response:$response,params:$params");} else {response = await dio.post(requestUrl,options: Options(contentType: contentType));}break;}// case HttpApiMethod.PUT: {//   break;// }// case HttpApiMethod.DELETE: {//   break;// }default:}LoggerManager().debug('doRequest: $response, params:$params');if (response != null) {Map<String, dynamic> result = json.decode(response.toString());assert(() {// assert只会在debug模式下执行,release模式下不会执行// 打印信息LoggerManager().debug('''api: $requestUrl\nresult: $result''');return true;}());ResponseData responseData = ResponseData.fromJson(result);if (responseData.status == 0) {if (success != null) {//返回请求数据success(responseData);}} else {//返回失败信息ApiHttpError apiHttpError = getErrorRequestResponseData(responseData);LoggerManager().debug("apiHttpError:${apiHttpError.toString()}");LoggerManager().error('''api: $requestUrl\nresult: $result''');if (failure != null) {failure(apiHttpError);}}} else {// 没有获得response,failureApiHttpError apiHttpError =ApiHttpError(ApiHttpErrorType.Default, "请求失败!");LoggerManager().debug("apiHttpError:${apiHttpError.toString()}");if (failure != null) {failure(apiHttpError);}}} on DioError catch (e, s) {// catch到异常,failure// The request was made and the server responded with a status code// that falls out of the range of 2xx and is also not 304.LoggerManager().error("doRequest api: $requestUrl, dioError:${e.message}, s:$s");ApiHttpError apiHttpError = getRequestFailure(e.response, e.type);LoggerManager().debug("apiHttpError:${apiHttpError.toString()}");if (failure != null) {failure(apiHttpError);}} catch (e) {// 可以捕获任意异常ApiHttpError apiHttpError =ApiHttpError(ApiHttpErrorType.Default, "${e.toString()}");if (failure != null) {failure(apiHttpError);}}}// 上传文件(图片)doUploadFile(String url, UploadFileInfo fileInfo,{Map<String, dynamic>? params,OnUploaded? uploaded,OnFailure? failure}) async {try {String timeStamp = DateTime.now().millisecondsSinceEpoch.toString();Map<String, dynamic> fromParams = Map();if (params != null && params.isNotEmpty) {fromParams.addAll(params);}fromParams["file"] = await MultipartFile.fromFile(fileInfo.file.path,filename: '${fileInfo.key}-${timeStamp}.jpg');FormData formData = FormData.fromMap(fromParams);Response? response = await dio.post(url, data: formData);assert(() {// assert只会在debug模式下执行,release模式下不会执行// 打印信息LoggerManager().error('''api: $url\nresult: $response''');return true;}());if (response != null) {Map<String, dynamic> result = json.decode(response.toString());assert(() {// assert只会在debug模式下执行,release模式下不会执行// 打印信息LoggerManager().debug('''api: $url\nresult: $result''');return true;}());if (response.statusCode == 200) {if (uploaded != null) {uploaded(result);}} else {//返回失败信息LoggerManager().error('''api: $url\nresult: $result''');ApiHttpError apiHttpError =ApiHttpError(ApiHttpErrorType.Default, "请求失败!");if (failure != null) {failure(apiHttpError);}}} else {//返回失败信息// 没有获得response,failureApiHttpError apiHttpError =ApiHttpError(ApiHttpErrorType.Default, "请求失败!");if (failure != null) {failure(apiHttpError);}}} on DioError catch (e, s) {// catch到异常,failureLoggerManager().error("doUploadFile api: $url, dioError:$e, s:$s");ApiHttpError apiHttpError = getRequestFailure(e.response, e.type);if (failure != null) {failure(apiHttpError);}} catch (e) {// 可以捕获任意异常ApiHttpError apiHttpError =ApiHttpError(ApiHttpErrorType.Default, "${e.toString()}");if (failure != null) {failure(apiHttpError);}}}// 下载文件void doDownload(String url, String savePath,{required CancelToken cancelToken,Map<String, dynamic>? params,dynamic? data,Options? options,OnDownloadProgress? progress,OnDownloaded? completion,OnFailure? failure}) async {try {dio.download(url,savePath,queryParameters: params,cancelToken: cancelToken,onReceiveProgress: (int count, int total) {if (total != -1) {if (!cancelToken.isCancelled) {double downloadRatio = (count / total);if (downloadRatio == 1) {if (completion != null) {completion();}} else {if (progress != null) {progress(count, total);}}}} else {ApiHttpError apiHttpError =ApiHttpError(ApiHttpErrorType.Default, "无法获取文件大小,下载失败!");if (failure != null) {failure(apiHttpError);}}},);} on DioError catch (e) {ApiHttpError apiHttpError =ApiHttpError(ApiHttpErrorType.Default, e.toString());if (CancelToken.isCancel(e)) {apiHttpError = ApiHttpError(ApiHttpErrorType.Cancel, "下载已取消!");} else {if (e.response != null) {apiHttpError = getRequestFailure(e.response, e.type);} else {apiHttpError = ApiHttpError(ApiHttpErrorType.Default, e.message??"");}}if (failure != null) {failure(apiHttpError);}} on Exception catch (e) {// EasyLoading.showError(e.toString());ApiHttpError apiHttpError =ApiHttpError(ApiHttpErrorType.Default, e.toString());if (failure != null) {failure(apiHttpError);}} catch (e) {// 可以捕获任意异常ApiHttpError apiHttpError =ApiHttpError(ApiHttpErrorType.Default, "${e.toString()}");if (failure != null) {failure(apiHttpError);}}}// 根据服务器来拼接服务器具体地址String getRequestUrl(String url, ApiServiceDomain serviceDomain) {String requestUrl = url;return requestUrl;}ApiHttpError getErrorRequestResponseData(ResponseData responseData) {//返回失败信息ApiHttpError apiHttpError =ApiHttpError(ApiHttpErrorType.Default, responseData.errorMsg);if (kNeedAuthLoginErrorCode == responseData.errorCode) {apiHttpError = ApiHttpError(ApiHttpErrorType.Auth, responseData.errorMsg);}return apiHttpError;}ApiHttpError getRequestFailure(Response? response, DioErrorType dioErrorType) {LoggerManager().error("getRequestFailure: $response, dioError:$dioErrorType");ApiHttpErrorType errorType = ApiHttpErrorType.Default;String errorMessage = "请求失败!";if (response != null) {if (dioErrorType == DioErrorType.connectionTimeout) {errorType = ApiHttpErrorType.NetWork;errorMessage = "网络链接异常!";} else if (dioErrorType == DioErrorType.sendTimeout) {errorType = ApiHttpErrorType.Timeout;errorMessage = "网络链接异常!";} else if (dioErrorType == DioErrorType.receiveTimeout) {errorType = ApiHttpErrorType.Timeout;errorMessage = "网络链接异常!";} else if (dioErrorType == DioErrorType.badResponse) {// When the server response, but with a incorrect status, such as 404, 503...if (response != null) {if (response.statusCode == 401) {errorType = ApiHttpErrorType.Auth;errorMessage = "认证失败!";} else if (response.statusCode == 400) {errorType = ApiHttpErrorType.BadRequest;errorMessage = "无效请求!";} else if (response.statusCode == 404) {errorType = ApiHttpErrorType.NotFound;errorMessage = "访问的资源丢失了!";} else if (response.statusCode == 405) {// 请求的方法错误errorType = ApiHttpErrorType.BadParamHeader;errorMessage = "参数出错!";} else if (response.statusCode! >= 500) {errorType = ApiHttpErrorType.BadRequest;errorMessage = "服务器居然累倒了!";}}} else if (dioErrorType == DioErrorType.cancel) {errorType = ApiHttpErrorType.Cancel;errorMessage = "请求已经取消";}} else {errorType = ApiHttpErrorType.NetWork;errorMessage = "网络链接异常!";}ApiHttpError apiHttpError = ApiHttpError(errorType, errorMessage);return apiHttpError;}
}/// 上传的文件类
class UploadFileInfo {File file;String key;UploadFileInfo({required this.file, required this.key});
}

文件下载页面实现实例

class DownloadPage extends StatefulWidget {const DownloadPage({Key? key,this.messages,this.uniqueId,this.arguments,}) : super(key: key);final Object? arguments;final String? messages;final String? uniqueId;State<DownloadPage> createState() => _DownloadPageState();
}class _DownloadPageState extends State<DownloadPage> {String _downloadPath ='https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg';double _downloadRatio = 0.0;String _downloadIndicator = '0.00%';late String _destPath;late CancelToken _token;bool _downloading = false;void initState() {getTemporaryDirectory().then((tempDir) => {_destPath = tempDir.path + 'googlechrome.dmg'});super.initState();}void _downloadFile() {if (_downloading == true) {return;}_token = CancelToken();_downloading = true;HttpApi().doDownload(_downloadPath, _destPath, cancelToken: _token,progress: (int received, int total) {// 下载进度setState(() {_downloadRatio = (received / total);if (_downloadRatio == 1) {_downloading = false;}_downloadIndicator = (_downloadRatio * 100).toStringAsFixed(2) + '%';});}, completion: () {// 下载成功_downloading = false;FlutterLoadingHud.showToast(message: "\"下载完成\"");}, failure: (error) {// 下载出错_downloading = false;FlutterLoadingHud.showToast(message: error.message);});}void _cancelDownload() {if (_downloadRatio < 1.0) {_token.cancel();_downloading = false;setState(() {_downloadRatio = 0;_downloadIndicator = '0.00%';});}}void _deleteFile() {try {File downloadedFile = File(_destPath);if (downloadedFile.existsSync()) {downloadedFile.delete();} else {FlutterLoadingHud.showToast(message: "文件不存在");}} catch (e) {FlutterLoadingHud.showToast(message: "${e.toString()}");}}Widget build(BuildContext context) {return Scaffold(resizeToAvoidBottomInset: false,appBar: AppBar(leading: AppBarIconButton(icon: Icon(Icons.arrow_back_ios),onPressed: () => {NavigatorRoute.pop()},),centerTitle: true,backgroundColor: ColorUtil.hexColor(0xffffff),foregroundColor: ColorUtil.hexColor(0x777777),elevation: 0,title: Text("下载示例",textAlign: TextAlign.center,softWrap: true,style: TextStyle(fontSize: 17,color: ColorUtil.hexColor(0x333333),fontWeight: FontWeight.w600,fontStyle: FontStyle.normal,decoration: TextDecoration.none,),),shadowColor: ColorUtil.hexColor(0xffffff),toolbarHeight: 44.0,bottomOpacity: 0.0,),body: Container(color: ColorUtil.hexColor(0xf7f7f7),alignment: Alignment.center,padding: EdgeInsets.all(10),child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Row(children: [_buildDownloadButton(),TextButton(child: Text('取消'),onPressed: () {_cancelDownload();},),TextButton(child: Text('删除',style: TextStyle(color: !_downloading ? Colors.red : Colors.grey),),onPressed: (!_downloading ? _deleteFile : null),style: ButtonStyle(),),],),SizedBox(height: 25,),Row(children: [Expanded(child: LinearProgressIndicator(backgroundColor: Colors.grey[600],value: _downloadRatio,),),SizedBox(width: 5,),Text(_downloadIndicator,style: TextStyle(color: Colors.black, fontSize: 12.0),),]),],),),);}Widget _buildDownloadButton() {return ButtonWidget(onPressed: () {_downloadFile();},child: Text("下载文件",textAlign: TextAlign.center,softWrap: true,style: TextStyle(fontSize: 16,fontWeight: FontWeight.w400,fontStyle: FontStyle.normal,color: ColorUtil.hexColor(0xffffff),decoration: TextDecoration.none,),),height: 40,width: 100.0,highlightedColor: ColorUtil.hexColor(0xff462e),bgColor: ColorUtil.hexColor(0xff462e),bgHighlightedColor: ColorUtil.hexColor(0xff462e, alpha: 0.75),enabled: true,bgDisableColor: Colors.grey,borderRadius: 22.0,);}
}

三、小结

flutter开发实战-dio文件下载实现,封装dio下载功能,实现文件下载

学习记录,每天不停进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/690.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JS脚本 - 批量给所有指定标签追加Class属性

JS脚本 - 批量给所有指定标签追加Class属性 前言一. 脚本二. 测试运行 前言 公司里我们有个应用引入了UBT埋点&#xff0c;记录了页面上所有的点击操作以及对应的点击按钮。但是我们看下来发现&#xff0c;我们需要给每个按钮加一个唯一标识做区分&#xff0c;并且这个ID是给U…

Flask 使用Flask的session来保存用户登录状态例子

使用Python的Flask库实现的登录接口、查询金额接口和注销接口的示例。 当用户发送POST请求到/login接口时&#xff0c;代码会获取请求中的用户名和密码。如果用户名和密码匹配&#xff08;在示例中是admin和admin123&#xff09;&#xff0c;则会将用户名保存在session中&…

吴恩达机器学习2022-Jupyter特征缩放

1可选实验室: 特征缩放和学习率(多变量) 1.1 目标 在这个实验室里: 利用前一实验室开发的多变量线性回归模型程序在具有多种功能的数据集上运行梯度下降法探讨学习速度 alpha 对梯度下降法的影响通过使用 z 分数标准化的特征缩放来提高梯度下降法的性能 1.2 工具 您将使用…

Python爬虫学习笔记(三)————urllib

目录 1.使用urllib来获取百度首页的源码 2.下载网页图片视频 3.总结-1 4.请求对象的定制&#xff08;解决第一种反爬&#xff09; 5.编解码 &#xff08;1&#xff09;get请求方式&#xff1a;urllib.parse.quote&#xff08;&#xff09; &#xff08;2&#xff09;get请求…

RPC分布式网络通信框架(三)—— 服务配置中心Zookeeper模块

文章目录 一、使用Zookeeper的意义二、Zookeeper基础1 文件系统2 通知机制3 原生zkclient API存在的问题4 服务配置中心Zookeeper模块 三、Zk类实现Start方法创建节点、get节点值方法 四、框架应用rpc提供端框架rpc调用端&#xff08;客户端&#xff09;框架 总结 一、使用Zook…

flutter开发实战-生日等日期选择器DatePicker

flutter开发实战-生日等日期选择器DatePicker 在开发遇到设置生日等信息需要选择日期&#xff0c;这里用到的是CupertinoDatePicker iOS效果的日期、时间选择器 一、效果图 运行后效果图如下 二、代码实现 我们需要调用底部弹窗显示 //显示底部弹窗static void bottomShe…

Python实现PSO粒子群优化算法优化BP神经网络回归模型(BP神经网络回归算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 PSO是粒子群优化算法&#xff08;Particle Swarm Optimization&#xff09;的英文缩写&#xff0c;是一…

H3C-Cloud Lab实验-三层交换机实验

实验拓扑图&#xff1a; 实验需求&#xff1a; 1. 按照图示为 PC2 和 PC3 配置 IP 地址和网关 2. PC2 属于 Vlan10&#xff0c;PC3 属于 Vlan20&#xff0c;在三层交换机上配置 Vlanif 三层接口实现 Vlan10 和 Vlan20 三层互通 3. PC2 和 PC3 可以互通 实验步骤&#xff1a…

WEB:Web_php_include(多解)

背景知识 文件包含 file://协议 php://协议 data://协议 了解strstr函数 题目 <?php show_source(__FILE__); echo $_GET[hello]; /*可以构造payload*/ $page$_GET[page]; while (strstr($page, "php://")) { /*strstr()函数*/$pagestr_replace("php://&q…

Django实现接口自动化平台(十一)项目模块Projects序列化器及视图【持续更新中】

相关文章&#xff1a; Django实现接口自动化平台&#xff08;十&#xff09;自定义action names【持续更新中】_做测试的喵酱的博客-CSDN博客 本章是项目的一个分解&#xff0c;查看本章内容时&#xff0c;要结合整体项目代码来看&#xff1a; python django vue httprunner …

在外Windows远程连接MongoDB数据库【无公网IP】

文章目录 前言1. 安装数据库2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射2.3 测试随机公网地址远程连接 3. 配置固定TCP端口地址3.1 保留一个固定的公网TCP端口地址3.2 配置固定公网TCP端口地址3.3 测试固定地址公网远程访问 转载自cpolar极点云文章&#xff1a;公网远程…

论文阅读-2:基于深度学习的大尺度遥感图像建筑物分割研究

一、该网络中采用了上下文信息捕获模块。通过扩大感受野&#xff0c;在保留细节信息的同时&#xff0c;在中心部分进行多尺度特征的融合&#xff0c;缓解了传统算法中细节信息丢失的问题&#xff1b;通过自适应地融合局部语义特征&#xff0c;该网络在空间特征和通道特征之间建…

docker服务启动过程分析

How docker.service start&#xff1f; just by ref 我们先了解docker的各个核心组件的介绍 runc&#xff1a;runc实现了容器的底层功能&#xff0c;例如创建、运行等。runc通过调用内核接口为容器创建和管理cgroup、namespace等Linux内核功能&#xff0c;来实现容器的核心特…

PyTorch预训练和微调:以VGG16为例

文章目录 预训练和微调代码测试结果参考来源 预训练和微调代码 数据集&#xff1a;CIFAR10 CIFAR-10数据集由10类32x32的彩色图片组成&#xff0c;一共包含60000张图片&#xff0c;每一类包含6000图片。其中50000张图片作为训练集&#xff0c;10000张图片作为测试集。数据集介…

SolidUI AI生成可视化,0.1.0版本模块划分以及源码讲解

1.背景 随着文本生成图像的语言模型兴起&#xff0c;SolidUI想帮人们快速构建可视化工具&#xff0c;可视化内容包括2D,3D,3D场景&#xff0c;从而快速构三维数据演示场景。SolidUI 是一个创新的项目&#xff0c;旨在将自然语言处理&#xff08;NLP&#xff09;与计算机图形学相…

【微信小程序-uniapp】CustomDialog 居中弹窗组件

1. 效果图 2. 组件完整代码 <template><uni-popup :ref="ref" type="center" @change

Ubuntu下配置Redis哨兵集群

目录 准备实例和配置 启动哨兵集群 测试配置 搭建一个三节点形成的Sentinel集群&#xff0c;来监管Redis主从集群。 三个sentinel哨兵实例信息如下&#xff1a; 节点IPPORTs1192.168.22.13527001s2192.168.22.13527002s3192.168.22.13527003 准备实例和配置 要在同一台虚…

组合式API

文章目录 前言了解组合式API简单类型 ref封装对象类型 user.name子组件数组类型 reactive封装 组合式 API 基础练习基础练习优化 前言 Vue 3 的组合式 API&#xff08;Composition API&#xff09;是一组函数和语法糖&#xff0c;用于更灵活和可组合地组织 Vue 组件的代码逻辑…

leetcode 538. 把二叉搜索树转换为累加树

2023.7.16 这道题利用中序遍历&#xff08;右中左&#xff09;的操作不断修改节点的值即刻&#xff0c;直接看代码&#xff1a; class Solution { public:TreeNode* convertBST(TreeNode* root) {stack<TreeNode*> stk;//前面的累加值int pre_value 0;TreeNode* cur r…

review回文子串

给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串 。返回 s 所有可能的分割方案。 回文串 是正着读和反着读都一样的字符串。 class Solution {List<List<String>> lists new ArrayList<>(); // 用于存储所有可能…