Flutter 學(xué)習(xí) - 網(wǎng)絡(luò)請求和數(shù)據(jù)解析

前言

在這個內(nèi)容為王的時代赃阀,數(shù)據(jù)淶源一般都會來源于網(wǎng)絡(luò)霎肯,所以一款app,現(xiàn)在都離不開要通過網(wǎng)絡(luò)來獲取數(shù)據(jù)榛斯,對于客戶端來說观游,獲取網(wǎng)絡(luò)數(shù)據(jù)就需要在客戶端集成網(wǎng)絡(luò)請求,F(xiàn)lutter官方為我們提供了HttpClient來發(fā)起網(wǎng)絡(luò)請求驮俗,可以參考在Flutter中發(fā)起HTTP網(wǎng)絡(luò)請求

轉(zhuǎn)折

雖然Flutter官網(wǎng)提供了自己的網(wǎng)絡(luò)請求懂缕,但是官方還有一句話,是說HttpClient本身功能較弱王凑,很多常用功能都不支持搪柑,所以官方建議我們使用dio來發(fā)起網(wǎng)絡(luò)請求,這是一個強(qiáng)大易用的dart http 請求庫索烹,支持Restful API工碾、FormData、攔截器百姓、請求取消渊额、Cookie管理、文件上傳/下載、全局配置旬迹、超時等

正文 - 網(wǎng)絡(luò)請求

這篇文章還是在上一篇文章Flutter 學(xué)習(xí)- 基礎(chǔ)框架的基礎(chǔ)上繼續(xù)完善的火惊,有圖有真相,下面先看效果圖

網(wǎng)絡(luò)請求演示.gif

項目列表的展示主要是listview奔垦,這部分內(nèi)容會在后面的文章中分享出來屹耐,本篇文章我們主要描述如何在flutter中使用網(wǎng)絡(luò)請求,并且將數(shù)據(jù)解析出來

  • 引入第三方框架

這里我們要先將dio庫添加到我們的項目中椿猎,我們要打開pubspec.yaml文件,在dependencies:下添加代碼

  dio: ^2.1.0

在你需要用到dio的地方導(dǎo)入包

  import 'package:dio/dio.dart';

官方給出了簡單的使用方法

  void getHttp() async {
    try {
      Response response = await Dio().get("http://www.google.com");
      print(response);
    } catch (e) {
       print(e);
    }
  }

看到了吧其實很簡單惶岭,dio幫我們完成了所有的操作,我們只要一行代碼就得到了我們的請求犯眠,但是俗他,當(dāng)然有但是,我們的日常開發(fā)中的接口還會帶參數(shù)阔逼,那要怎么傳遞呢,官方也給出了簡單的使用方法地沮,

  • 方法1
 Response response;
 Dio dio = new Dio();
 response = await dio.get("/test?id=12&name=wendu")
 print(response.data.toString());
  • 方法2
Response response;
Dio dio = new Dio();
response = await dio.get("/test", queryParameters: {"id": 12, "name": "wendu"});
print(response.data.toString());

到此dio的使用方法就結(jié)束了嗜浮,這也太簡單了,但是這也太不實用了摩疑,每次都要把參數(shù)那么艱難的拼進(jìn)去多麻煩危融,實際開發(fā)中使用太不方便了,因此我們就要對這些使用方法進(jìn)行封裝

  • 封裝 - 第一步

設(shè)置請求雷袋,這里我們只做最常用的Get和Post的請求吉殃,有興趣的可以做更深入的探究

  static void _request(String url, Function successCallback,
      {String method,
      Map<String, String> params,
      Function errorCallBack}) async {
    print("url = $url");
    String errorMsg = "";
    int statusCode;
    try {
      Response response;
      BaseOptions baseOptions = new BaseOptions(
        connectTimeout: HttpUtils.TIMEOUT_CONNECT,
        receiveTimeout: HttpUtils.TIMEOUT_RECEIVE,
      );
      // dio庫中默認(rèn)將請求數(shù)據(jù)序列化為json,此處可根據(jù)后臺情況自行修改
//      contentType:new ContentType('application', 'x-www-form-urlencoded',charset: 'utf-8')
      Options options = new Options(
        connectTimeout: HttpUtils.TIMEOUT_CONNECT,
        receiveTimeout: HttpUtils.TIMEOUT_RECEIVE,
        sendTimeout: HttpUtils.TIMEOUT_SEND,
      );
      Dio dio = new Dio(baseOptions);
      if (method == HttpUtils.GET) {
        response =
            await dio.get(url, queryParameters: params, options: options);
      } else {
        response =
            await dio.post(url, queryParameters: params, options: options);
      }
      statusCode = response.statusCode;
      if (statusCode != HttpStatus.ok) {
        errorMsg = "網(wǎng)絡(luò)請求錯誤,狀態(tài)碼:" + statusCode.toString();
        _handError(errorCallBack, errorMsg);
      } else {
        if (successCallback != null) {
          var data = json.decode(response.toString()); //對數(shù)據(jù)進(jìn)行Json轉(zhuǎn)化
          successCallback(data);
          print("data = " + data);
        }
      }
    } catch (exception) {
      _handError(errorCallBack, exception.toString());
    }
  }
  • 封裝-第二步

方法調(diào)用楷怒,參數(shù)傳遞

  /**
   * get 請求
   */
  static getData(String url, Function successCallback,
      {Map<String, String> params, Function errorCallBack}) async {
    if (params != null && params.isNotEmpty) {
      StringBuffer stringBuffer = new StringBuffer("?");
      params.forEach((key, value) {
        stringBuffer.write("$key" + "=" + "$value" + "&");
      });
      String paramStr = stringBuffer.toString();
      paramStr = paramStr.substring(0, paramStr.length - 1);
      url += paramStr;
    }
    _request(url, successCallback,
        method: HttpUtils.GET, params: params, errorCallBack: errorCallBack);
  }

  /**
   * Post請求
   */
  static postData(String url, Function successCallback,
      {Map<String, String> params, Function errorCallBack}) async {
    _request(url, successCallback,
        method: HttpUtils.POST, params: params, errorCallBack: errorCallBack);
  }

這時候我們就可以把這些方法放到一個類里面蛋勺,在后面的請求中直接調(diào)用了

  HttpController.getData(url, (data) {
      if (!mounted) return;
      setState(() {
        /**
        TODO Sth  
       解析數(shù)據(jù),刷新界面
        **/
      });
    }, params: params);

是不是蠻簡單鸠删,網(wǎng)絡(luò)請求到此告一段落~~~

正文- 數(shù)據(jù)解析

網(wǎng)絡(luò)請求已經(jīng)完成數(shù)據(jù)我們拿到了抱完,但是我們怎么搞定數(shù)據(jù)的解析轉(zhuǎn)變成我們想要的類呢,Android中有Gson幫我們刃泡,在flutter中有沒有類似的框架呢巧娱,恭喜你,flutter中沒有烘贴,是不是很意外禁添,flutter就是這么的剛,但是呢我們解析也不是不能做桨踪,當(dāng)然是需要我們自己動手的

  • 首先先看一個接口數(shù)據(jù)
   {
    "data": {
        "curPage": 1,
        "datas": [{
                    "author": "guojun_fire",
                "chapterName": "基礎(chǔ)知識",
                "link": "https://juejin.im/post/5c9c2c76f265da60c576fab1",
                "niceDate": "1天前",
                "superChapterName": "自定義控件",
                "tags": [
                    {
                        "name": "項目",
                        "url": "/project/list/1?cid=294"
                    }
                ],
                "title": "你需要了解下Android View的更新requestLayout與重繪invalidate",
            },
            {
                ...
            },
            ....
        ],
        "offset": 0,
        "over": false,
        "pageCount": 314,
        "size": 20,
        "total": 6265
    },
    "errorCode": 0,
    "errorMsg": ""
}

這個json數(shù)據(jù)中我們可以看到首先是我們需要一個實體類來接收這個數(shù)據(jù)中的所有字段

 class ArticleBean {
  int curPage;
  int offset;
  bool over;
  int pageCount;
  int size;
  int total;
  List<Article> datas =[];
}

另外我們看到數(shù)據(jù)中還有兩個json數(shù)組老翘,那我們也要對應(yīng)創(chuàng)建兩個數(shù)組中數(shù)據(jù)中的實體類

class Article {
  final String author;
  final String chapterName;
  final String title;
  final String niceDate;
  final String superChapterName;
  final String link;
  final List<Tag> tags;
}

class Tag{
  String name;
  String url;
}

下面問題來了對于數(shù)組,我們要怎么解析呢,直接看示例

  class Tag{
  String name;
  String url;

  Tag({this.name, this.url});//創(chuàng)建構(gòu)造函數(shù)
  //將我們的實體類數(shù)據(jù)傳入進(jìn)行解析
  factory Tag.fromJson(Map<String, dynamic> parsedJson){
    return Tag(
      name: parsedJson['name'],
      url: parsedJson['url']
    );
  }
}

看到Tag類的方法酪捡,我們就可以聯(lián)想到Article類的方法了叁征,是一樣的,只是稍做修改

  class Article {
  final String author;
  final String chapterName;
  final String title;
  final String niceDate;
  final String superChapterName;
  final String link;
  final List<Tag> tags;

  Article(
      {this.author,
      this.chapterName,
      this.title,
      this.niceDate,
      this.superChapterName,
      this.link,
      this.tags});

  factory Article.fromJson(Map<String, dynamic> parsedJson) {
    return Article(
        author: parsedJson['author'],
        chapterName: parsedJson['chapterName'],
        title: parsedJson['title'],
        niceDate: parsedJson['niceDate'],
        superChapterName: parsedJson['superChapterName'],
        link: parsedJson['link'],
      tags: (parsedJson['tags'] as List)
          .map((i) => Tag.fromJson(i))
          .toList(),);
  }
}

重點(diǎn)來看tags的獲取逛薇,首先是將“tags“這個key的數(shù)據(jù)進(jìn)行轉(zhuǎn)化捺疼,然后用map進(jìn)行循環(huán)遍歷,通過Tag.fromJson方法生成Tag類永罚,最后用tolist方法轉(zhuǎn)化成列表啤呼。

  parsedJson['tags'] as List)
          .map((i) => Tag.fromJson(i))
          .toList()

這段代碼我們可以拆解來看

    var list = parsedJson['tags'] as List;
    List<Tag> tags = new List();
    tags = list.map((i) => Tag.fromJson(i)).toList();

這樣就容易理解了。
同樣的方法我們可以得到ArticleBean類的數(shù)據(jù)獲得

 class ArticleBean {
  int curPage;
  int offset;
  bool over;
  int pageCount;
  int size;
  int total;
  List<Article> datas =[];

  ArticleBean(
      {this.curPage,
      this.offset,
      this.over,
      this.pageCount,
      this.size,
      this.total,
      this.datas});

  factory ArticleBean.from(Map<String, dynamic> parsedJson) {
    return ArticleBean(
      curPage: parsedJson["curPage"],
      offset: parsedJson["offset"],
      over: parsedJson["over"],
      pageCount: parsedJson["pageCount"],
      size: parsedJson["size"],
      total: parsedJson["total"],
      datas: (parsedJson['datas'] as List)
          .map((i) => Article.fromJson(i))
          .toList(),
    );
  }
}

然后在使用的時候我們只需要把上面的那段json數(shù)據(jù)傳進(jìn)去就可以解析了

  HttpController.getData(url, (data) {
      if (!mounted) return;
      setState(() {
        //data["data"]就是從網(wǎng)絡(luò)上獲取到的數(shù)據(jù)
        ArticleBean articleBean = ArticleBean.from(data["data"]);
      });
    }, params: params);

到此為止呢袱,網(wǎng)絡(luò)請求和數(shù)據(jù)解析部分就講解完成了官扣,后面就可以在各個頁面中完成項目中所需要的UI,該項目已被放在Github上面進(jìn)行開源,內(nèi)容在不斷更新中羞福,后續(xù)還會有更多實際項目中所要用到的基礎(chǔ)知識惕蹄,如有問題,也歡迎大家留言治专,指正卖陵。

以下是我的Flutter系列的鏈接,后續(xù)會持續(xù)更新张峰,歡迎大家指正泪蔫。

Flutter 系列文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市喘批,隨后出現(xiàn)的幾起案子撩荣,更是在濱河造成了極大的恐慌,老刑警劉巖饶深,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件餐曹,死亡現(xiàn)場離奇詭異,居然都是意外死亡敌厘,警方通過查閱死者的電腦和手機(jī)凸主,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來额湘,“玉大人卿吐,你說我怎么就攤上這事》婊” “怎么了嗡官?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長毯焕。 經(jīng)常有香客問我衍腥,道長磺樱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任婆咸,我火速辦了婚禮竹捉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘尚骄。我一直安慰自己块差,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布倔丈。 她就那樣靜靜地躺著憨闰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪需五。 梳的紋絲不亂的頭發(fā)上鹉动,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機(jī)與錄音宏邮,去河邊找鬼泽示。 笑死,一個胖子當(dāng)著我的面吹牛蜜氨,可吹牛的內(nèi)容都是我干的边琉。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼记劝,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了族扰?” 一聲冷哼從身側(cè)響起厌丑,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎渔呵,沒想到半個月后怒竿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扩氢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年耕驰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片录豺。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡朦肘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出双饥,到底是詐尸還是另有隱情媒抠,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布咏花,位于F島的核電站趴生,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜苍匆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一刘急、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧浸踩,春花似錦叔汁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至后裸,卻和暖如春瑰钮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背微驶。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工浪谴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人因苹。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓苟耻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親扶檐。 傳聞我的和親對象是個殘疾皇子凶杖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容