Flutter dio结合json_serializable请求数据并解析Demo

前言

我们在开发中,会面临要从服务器请求数据,然后解析服务器过来的json数据,这个在android中,都有相应的的封装好的很好的插件可以做这样的事情,请求数据有okHttp,解析有GSON。那么在flutter中呢,对应的可以是什么呢,我目前请求数据使用的是dio,解析使用的是json_serializable,下面是一个简单的例子

实践

一、集成插件

pubspec.yaml文件中添加diojson_serializable的相关插件,这里我贴上我的:

dependencies:
  flutter:
    sdk: flutter

  dio: ^3.0.8 #网络请求
  json_annotation: ^3.0.1

dev_dependencies:
  flutter_test:
    sdk: flutter

  #这两个是dev的,不要放到上面去了哦
  build_runner: ^1.7.3
  json_serializable: ^3.2.5

二、封装网络请求

import 'package:dio/dio.dart';
import 'dart:convert';
import 'package:the_first_one/model/Api.dart';

//要查网络请求的日志可以使用过滤<net>
class NetUtil {
  static const String GET = "get";
  static const String POST = "post";

  //get请求
  static void get(String url, Function callBack,
      {Map<String, String> params, Function errorCallBack}) async {
    _request(Api.BaseUrl + url, callBack,
        method: GET, params: params, errorCallBack: errorCallBack);
  }

  //post请求
  static void post(String url, Function callBack,
      {Map<String, String> params, Function errorCallBack}) async {
    _request(url, callBack,
        method: POST, params: params, errorCallBack: errorCallBack);
  }

  //具体的还是要看返回数据的基本结构
  //公共代码部分
  static void _request(String url, Function callBack,
      {String method,
      Map<String, String> params,
      Function errorCallBack}) async {
    print("<net> url :<" + method + ">" + url);

    if (params != null && params.isNotEmpty) {
      print("<net> params :" + params.toString());
    }

    String errorMsg = "";
    int statusCode;

    try {
      Response response;
     if (method == GET) {
        //组合GET请求的参数
        if (params != null && params.isNotEmpty) {
          StringBuffer sb = new StringBuffer("?");
          params.forEach((key, value) {
            sb.write("$key" + "=" + "$value" + "&");
          });
          String paramStr = sb.toString();
          paramStr = paramStr.substring(0, paramStr.length - 1);
          url += paramStr;
        }
        response = await Dio().get(url);
      } else {
        if (params != null && params.isNotEmpty) {
          response = await Dio().post(url, data: params);
        } else {
          response = await Dio().post(url);
        }
      }

      statusCode = response.statusCode;

      //处理错误部分
      if (statusCode < 0) {
        errorMsg = "网络请求错误,状态码:" + statusCode.toString();
        _handError(errorCallBack, errorMsg);
        return;
      }

      if (callBack != null) {
        callBack(response.data["data"]);
        print("<net> response data:" + response.data["data"]);
      }
    } catch (exception) {
      _handError(errorCallBack, exception.toString());
    }
  }

  //处理异常
  static void _handError(Function errorCallback, String errorMsg) {
    if (errorCallback != null) {
      errorCallback(errorMsg);
    }
    print("<net> errorMsg :" + errorMsg);
  }
}

以上的封装,主要基于返回的数据结构,我造了个数据,大概长下面这样:

在这里,我使用mocky来创建API

{
  "statusCode": 1,
  "data": {
    "name": "zoe",
    "email": "zoey@qq.com",
    "pics": [
      "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1534747043&di=2e3d49c934bb603bcf3f2fe8befd94fc&imgtype=jpg&er=1&src=http%3A%2F%2Fimg0.pconline.com.cn%2Fpconline%2F1309%2F30%2F3571757_9.jpg",
      "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1534152325030&di=d1d8493bfe1d5f7a9715b6db8ef3d29d&imgtype=0&src=http%3A%2F%2Fc1.cdn.goumin.com%2Fcms%2Fdetail%2Fday_171101%2F20171101_140dd79.png",
      "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1534152325029&di=684aa3a8225a7828ba6b04c8ea4bccd3&imgtype=0&src=http%3A%2F%2Fimgq.duitang.com%2Fuploads%2Fblog%2F201505%2F15%2F20150515014759_Qz5Tw.thumb.700_0.jpeg"
    ]
  }
}
image

三、创建model

为了便利的使用json_serializable库,我们使用这位大牛这个小工具

image

将右侧框内转换过的内容复制下来,在自己项目中创建user.dart文件,将你复制的内容粘贴进去。然后你会看到类中一些地方会飘红线,这是正常的哈,执行下面的命令后就会好了:

image

这个时候,你在项目根目录下输入命令:flutter packages pub run build_runner build(这个命令需要每次在model类中进行更改时都要手动运行构建。也可以使用命令:flutter packages pub run build_runner watch,它会监视我们项目中文件的变化,并在需要时自动构建必要的文件,只需启动一次观察器,然后并让它在后台运行,这是安全的。个人推荐后面这个命令哈),完成之后会在user.dart同级目录下,自动创建一个名为user.g.dart的文件:

image

有时候也会有些很诡异的事情出现,比如不管怎么输命令,最后就是生成不了g.dart文件,这时候可以使用命令flutter packages pub run build_runner build --delete-conflicting-outputs,将所有的都删除,重新生成,一般都会变好,我也是不晓得为什么

以下是日志(其中会有一些警告信息,比如Unable to resolve asset ID for "dart:ui",在我看来,好像不影响哈,暂时可以不用管):

F:\FlutterSpace\flutter_the_first_demo>flutter packages pub run build_runner build
[INFO] Generating build script...
[INFO] Generating build script completed, took 465ms

[INFO] Initializing inputs
[INFO] Reading cached asset graph...
[WARNING] Throwing away cached asset graph due to version mismatch.
[INFO] Reading cached asset graph completed, took 57ms

[INFO] Building new asset graph...
[INFO] Building new asset graph completed, took 522ms

[INFO] Checking for unexpected pre-existing outputs....
[INFO] Checking for unexpected pre-existing outputs. completed, took 2ms

[INFO] Running build...
[INFO] 2.6s elapsed, 3/65 actions completed.
[INFO] 3.6s elapsed, 4/65 actions completed.
[INFO] 4.7s elapsed, 4/65 actions completed.
[INFO] 5.7s elapsed, 4/65 actions completed.
[INFO] 6.8s elapsed, 4/65 actions completed.
[INFO] 7.9s elapsed, 4/65 actions completed.
[INFO] 9.0s elapsed, 4/65 actions completed.
[INFO] 10.0s elapsed, 4/65 actions completed.
[SEVERE] json_serializable on lib/components/BottomComponent2.dart:
Unable to resolve asset ID for "dart:ui"
[INFO] 17.0s elapsed, 56/65 actions completed.
[INFO] Running build completed, took 17.7s

[INFO] Caching finalized dependency graph...
[INFO] Caching finalized dependency graph completed, took 52ms

[SEVERE] Failed after 17.8s
pub finished with exit code 1

使用

import 'package:flutter/material.dart';
import 'package:the_first_one/model/user.dart';
import 'package:the_first_one/utils/NetUtil.dart';
import 'package:the_first_one/components/LoadingComponent.dart';

class JsonSeralizablePage extends StatefulWidget {
  @override
  _JsonSeralizablePageState createState() => _JsonSeralizablePageState();
}

class _JsonSeralizablePageState extends State<JsonSeralizablePage> {
  String name = "";
  String email = "";
  List<String> picList = <String>[];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("JSON"),
      ),
      body: (picList != null && picList.length == 0)
          ? LoadingComponent()
          : SingleChildScrollView(
              child: Column(
                children: <Widget>[
                  Text(
                    name,
                    style: TextStyle(color: Colors.black, fontSize: 20.0),
                  ),
                  SizedBox(height: 20.0),
                  Text(
                    email,
                    style: TextStyle(color: Colors.black, fontSize: 15.0),
                  ),
                  SizedBox(height: 20.0),
                  SizedBox(
                    height: 250.0 * picList.length,
                    child: ListView.builder(
                      physics: ClampingScrollPhysics(),
                      itemCount: picList != null && picList.length > 0
                          ? picList.length
                          : 0,
                      itemBuilder: (BuildContext context, int index) {
                        return picList != null && picList.length > 0
                            ? Image(
                                image: NetworkImage(picList[index]),
                                width: 400.0,
                                height: 250.0,
                                fit: BoxFit.cover)
                            : Text("no pics");
                      },
                    ),
                  ),
                ],
              ),
            ),
    );
  }

  @override
  void initState() {
    super.initState();

    getContent();
  }

  //获取网络数据
  void getContent() {
    NetUtil.get("http://www.mocky.io/v2/5b7143ae3200001402f36c46", (data) {
      User user = User.fromJson(data);
      setState(() {
        name = user.name;
        email = user.email;
        picList = user.pics;
      });
    }, errorCallBack: (errorMsg) {
      print("error:" + errorMsg);
    });
  }
}

效果:

image

写在最后

本人刚入门,所学尚浅,如有不当或不足之处,希望能得到指点

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

推荐阅读更多精彩内容