flutter dio封装
痛点
使用app的过程中,接口的请求是必不可少的。为了在开发高效,我当然要尝试封装dio插件。在最近的多个app开发中,尝试多种封装的方法,于是乎就得出啦一下的一套方法。
封装
在封装之前,需要确定我们需要那些需求。
- 部分接口的请求过程中需要一个loading来表示这个接口正在请求中。
- 接口要可以抛出异常的toast
- 不同的接口有不同的请求方法,不同的contentType
- 对响应请求的统一处理
那么先上满足以上的简陋版本
安装插件
dio: "^3.0.9"
flutter_easyloading: ^1.1.2
import 'dart:collection';
import 'package:dio/dio.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:testmuban/constant/constant.dart';
class _Service {
_Service() {
_initDio();
}
Dio _dio = new Dio();
static String token;
void setToken(String tk) {
token = tk;
}
void _initDio () {
// 接口日志
_dio.interceptors.add(LogInterceptor(responseBody: true, requestBody: true));
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (RequestOptions options){
// 超时时间
options.connectTimeout = 3000;
// 在请求被发送之前做一些事情
return options;
},
onResponse: (Response response) {
// 在返回响应数据之前做一些预处理
if (response.data['code'] != '200') {
EasyLoading.showError('Failed with Error',duration: Duration(seconds: 3));
}
return response;
},
onError: (DioError error) {
// 当请求失败时做一些预处理
EasyLoading.showError('Failed with Error',duration: Duration(seconds: 3));
return error;
},
));
}
// 真正发请求的地方
Future fetch(url, {
dynamic params,
Map<String, dynamic> header,
Options option,
bool isShowLoading = false
}) async{
Map<String, dynamic> headers = new HashMap(
);
headers['Authorization'] = token;
if (header != null) {
headers.addAll(header);
}
if (option != null) {
option.headers = headers;
} else {
option = new Options(method: "get");
option.headers = headers;
}
// 是否需要 loading
if (isShowLoading) {
EasyLoading.show(status: 'loading...');
}
try {
// 发送请求获取结果
Response _response = await _dio.request('${Constant.baseUrl}$url', data: params, options: option);
// 返回真正结果
return _response;
} catch (error) {
// 异常提示
EasyLoading.dismiss();
} finally {
// 不管结果怎么样 都需要结束Loading
EasyLoading.dismiss();
}
}
}
final _Service service = new _Service();
接下来是使用这个封装的
import 'package:dio/dio.dart';
import 'package:testmuban/constant/constant.dart';
import 'package:testmuban/service/service.dart';
class Api {
// 获取用户信息
static Function get getBasketball => () => service.fetch('onebox/basketball/nba?key=${Constant.juheKey}', isShowLoading: true);
// static Function get login => (param) => service.fetch('login', params: param, isShowLoading: true, option: new Options(method: "post"));
}
这里各位还需要看下flutter_easyloading的使用教程
这里我在使用过程中还发现了一个小问题
Unhandled Exception: 'package:flutter/src/widgets/overlay.dart': Failed assertion: line 132 pos 12: '_overlay != null': is not true.
我看源码发现,remove函数会设置_overlay = null, 这里就是因为我请求报错的就会去showError,然后这个又会去走_show方法。_show方法中在渲染之前一定都会去remove,但是因为渲染ui的异步操作,导致中间出现调用了两次remove的情况。
这里的WidgetsBinding.instance.addPostFrameCallback就是异步操作,所以导致在出现了连续两次remove。
于是,我就通过在service中添加标识位的方法来避免连续两次remove。
以下是我加的代码
static bool isToast = false;
void setToast(bool val) {
isToast = val;
}
// 在报错之前设置标识为true
setToast(true);
EasyLoading.showError('Failed with Error',duration: Duration(seconds: 3));
// 不管结果怎么样 都需要结束Loading
if (isShowLoading && !isToast) {
EasyLoading.dismiss();
} else if (isToast) {
setToast(false);
}
但是这个方法只针对这个工具函数,最终还是需要提下issue或者pr,让owner去将方法改成同步或者添加个标识位判断下。
封装地址
总结
在封装前,先考虑下自己的需求是什么。封装后如果出现来报错也不要慌,一点点看源码,看他们步骤调用了那些函数。以上就是我最近app项目的dio封装总结。