Flutter网络请求库Dio与Future特性

Flutter自带的网络请求引擎HttpClient功能,但HttpClient本身功能较弱,很多常用功能都不支持。Dio是Flutter的一个第三方网络库,它是一个强大易用的dart http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时等。

Dio使用方法

1.添加依赖:

dependencies:
  dio: ^x.x.x  // 请使用pub上的最新版本

2.在调用的文件导入:

import 'package:dio/dio.dart';

3.发起一个Post网络请求:

Response response = await dio.post(
          url , 
          data: paramters,
          options: opt,
        );

url 表示请求的地址;
data:Post提交的参数,key-value的Map类型;
options参数:网络请求头设置、其他自定义配置等。

其中Options是一个配置类:

Options({
    String method,
    int connectTimeout,
    int sendTimeout,
    int receiveTimeout,
    Iterable<Cookie> cookies,
    Map<String, dynamic> extra,
    Map<String, dynamic> headers,
    ResponseType responseType,
    ContentType contentType,
    ValidateStatus validateStatus,
    bool receiveDataWhenStatusError,
    bool followRedirects,
    int maxRedirects,
  })

通过其内部的属性可以看到,可以设置
method:Get/Post方式;
connectTimeout超时时间(毫秒单位);
headers就是设置请求头。
contentType和responseType可设置返回的内容是xml/json/text-plain等格式。
followRedirects可设置是否允许重定向。
cookies可以设置cookies。

Dart Future

网络请求离不开异步机制,Dart语法特性对异步机制使用了Future机制。这套机制和ES6的Promise原理是一样的。

如果你对Js的ES6熟悉,那么你将很容易理解和使用。他们都是协程,大致都是采用async/await 机制,将一个异步请求的过程放入一个协程里面,将结果以“同步”的方式返回,注意:不是真正的同步请求,实际上任何异步请求都是天然存在的客观事实,你无法真正将一个异步请求改成一个同步请求。

回到我们Dart语法中:
像上面的post请求方法,如果一个方法是异步的,那么该方法在没有返回结果前需要等待,dart语法要求在方法前加上“await”标识:

await xxxxxx()

那么,响应的该语句执行的方法返回也必须在结尾添加异步标识async:

Future xxxxxxx(paramters) async {
await xxxxxx()
}

该方法的放回类型一般为Future类型,以便调用方使用then()取得结果。(注意:返回类型不必一定为Future,可也是void,那么调用方就不能使用then()取结果而已)。

可能很多人不知道Future标识有什么意思,标识Future标识该方法的返回是一个then()-catchError(e)结果体,其中then({闭包})里是正确的返回结果,catchError({闭包})就是异步异常的结果。

当然,异步的请求也可以不以Future形式返回,我们可以通过自定义闭包结构体返回,比如我的网络请求返回是2个callback:

void request (String url, 
                Map paramters, 
                Function completeCallback, 
                Function errorCallback) async {

    if (!url.startsWith("http")) {
      String baseUrl = "https://www.wowoshenghuo.com";
      url = baseUrl + url;
    }
    String errorMsg = "";
    try {
      Options opt = await wowoLifeHeaders();
      Response response = await dio.post(
          url , 
          data: paramters,
          options: opt,
        );
      print("网络请求状态码:" + response.statusCode.toString());
      //处理错误部分
      if (response.statusCode < 200 || response.statusCode > 400) {
        errorMsg = "网络请求错误,状态码:" + response.statusCode.toString();
        _handError(errorCallback, errorMsg);
        return;
      }

      //网络connected
      Map<String, dynamic> json;
      if (response.data is Map) {
        json = response.data;
      }else {
        json = jsonDecode(response.data);
      }
      print(json);
      //转模型
      YWResponse resp = YWResponse.fromJson(json);
      
      if (completeCallback != null) {
        completeCallback(resp);
      }

    } catch(exception) {
      _handError(errorCallback, exception.toString());
    }
  }

  void _handError(Function errorCallback, String errorMsg) {
    if (errorCallback != null) {
      errorCallback(errorMsg);
    }
  }

}

我的网络返回是通过两个Function返回的:
completeCallback:网络正常的回调(当然业务错误也属于这种)
errorCallback:网络异常、不通的回调。

虽然我的网络请求是async标识的,由于我自定义了网络回调,所以我仅仅申明void返回即可。

获取设备信息和APP包信息

我们经常需要获取手机设备诸如系统版本,平台信息以及APP包名称,APP版本等信息。这些Flutter有一些第三方插件提供了这方面的api.

device_info

device_info 插件同样需要安装然后import
初始化:

DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();

deviceInfo为我们提供了iosInfo和androidInfo;
那么我们首先需要自己判断当前设备是哪个平台:

if (Platform.isIOS) {
      IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
      device["sysVersion"] = iosInfo.systemVersion;
      device["model"] = iosInfo.localizedModel;
      device["imei"] = iosInfo.identifierForVendor;
      device["brand"] = "iPhone";
    }else {
      AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
      device["sysVersion"] = androidInfo.version.baseOS;
      device["model"] = androidInfo.model;
      device["imei"] = androidInfo.id;
      device["brand"] = androidInfo.brand;
    }

然后通过iosInfo或者AndroidInfo即可获取system、model等设备信息。
需要注意的是:deviceInfo获取设备信息的方法是个异步的
需要await/async。

package_info

package_info是读取APP工程的信息的,如APP名称、APP唯一标识、APP迭代版本号等。
同样,和device_info一样,这个方法也是异步获取pakage信息:

Future<PackageInfo> pakageInfo() async {
    PackageInfo packageInfo = await PackageInfo.fromPlatform();
    return packageInfo;
  }

最后根据我们公司需要将设备信息作为header的获取方法全部完成了,贴一下我的header代码:

Future<Options> wowoLifeHeaders() async {

    if (store == null) {
      store = await storage();
    }
    if (deviceMap == null) {
      deviceMap = await deviceSystemVersion();
    }
    if (pakage == null) {
      pakage = await pakageInfo();
    }

    String uToken = "-1";
    if (store != null && store.getString("user_token") != null) {
      uToken = store.getString("user_token");
    } 
    Options options = Options(
      headers: {
        HttpHeaders.contentTypeHeader:"application/json;charset=UTF-8",
        "source" : Platform.isIOS ? "2" : "1",
        "sys_version" : deviceMap["sysVersion"],
        "model" : deviceMap["model"],
        "imei" : deviceMap["imei"],
        "app_version" : pakage.version,
        "user_token" : uToken,
        "userToken" : uToken,
      },
      connectTimeout: 30000,
      receiveTimeout: 25000,
      contentType: ContentType.json,
      responseType: ResponseType.json,
      );
    return options;
  }

以上。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容