Flutter 处理Json数据

引用头文件

import ‘dart:convert’

通过http用get方法得到Json数据

玩Android的banner数据为例:

    //异步获取
    var responseBody;
    var url = 'https://www.wanandroid.com/banner/json';
    var httpClient = new HttpClient();
    var request = await httpClient.getUrl(Uri.parse(url));
    var response = await request.close();
    if (response.statusCode == 200) {
        //得到Json格式的字符串
      responseBody = await response.transform(utf8.decoder).join();
    } else {
      print("get json error");
    }
    //返回Json格式字符串,之后解析
    return responseBody;

其中Json数据:

{
    "data": [
        {
            "desc": "Android高级进阶直播课免费学习",
            "id": 23,
            "imagePath": "https://wanandroid.com/blogimgs/92d96db5-d951-4223-ac42-e13a62899f50.jpeg",
            "isVisible": 1,
            "order": 0,
            "title": "Android高级进阶直播课免费学习",
            "type": 0,
            "url": "https://url.163.com/4bj"
        },
        {
            "desc": "一起来做个App吧",
            "id": 10,
            "imagePath": "https://www.wanandroid.com/blogimgs/50c115c2-cf6c-4802-aa7b-a4334de444cd.png",
            "isVisible": 1,
            "order": 0,
            "title": "一起来做个App吧",
            "type": 1,
            "url": "https://www.wanandroid.com/blog/show/2"
        },
        {
            "desc": "",
            "id": 6,
            "imagePath": "https://www.wanandroid.com/blogimgs/62c1bd68-b5f3-4a3c-a649-7ca8c7dfabe6.png",
            "isVisible": 1,
            "order": 1,
            "title": "我们新增了一个常用导航Tab~",
            "type": 1,
            "url": "https://www.wanandroid.com/navi"
        },
        {
            "desc": "",
            "id": 20,
            "imagePath": "https://www.wanandroid.com/blogimgs/90c6cc12-742e-4c9f-b318-b912f163b8d0.png",
            "isVisible": 1,
            "order": 2,
            "title": "flutter 中文社区 ",
            "type": 1,
            "url": "https://flutter.cn/"
        }
    ],
    "errorCode": 0,
    "errorMsg": ""
}

结构(规则一)

[ 开头的是List of map

{ 开头的是map

例子:

//list数组
[
  "id":"487349",
  "name":"Pooja Bhaumik",
  "score" : 1000
]
//Map对象
{
  "id":"487349",
  "name":"Pooja Bhaumik",
  "score" : 1000
}

序列化和反序列化

序列化只是意味着将数据(可能在对象中)写为字符串,而反序列化则与此相反。它获取原始数据并重建对象模型。即可以通过对象来得到其中的数据。

Json解析

1.内连序列化

通过调用JSON.decode方法来解码JSON,使用JSON字符串作为参数,例:

//这里的MAP中,第一个参数指key的类型是String,但是key值对应得值可能有int,String,List等,所以为动态
Map<String,dynamic> student = JSON.decode(json);

由于返回的数据类型为dynamic,所以只有运行的时候才知道类型有没有出错。通过这种方法,我们失去了大部分静态类型语言特性:类型安全、自动补全和最重要的编译时异常。这样一来,我们的代码可能会变得非常容易出错。

对于简单的Json数据用这种方法较为简单,如官方例子:

{
  "name": "John Smith",
  "email": "john@example.com"
}
2.在模型类中序列化 (规则2:对于嵌套结构,首先创建类和构造函数,然后从底层添加工厂方法。)此处为反序列化,因为没有用toJson

(官方方法为先反序列得到数据类型,再通过toJson进行序列化,这里不用toJson)

通过创建一个模型类(model)来方便在编译时知道类型,提醒错误。例:

//主要是写banner1中的fromJson方法,实现反序列化的目的并且

//其中banner1中有3个Key,其中两个为String,一个为Datas数组(所以还需要创建一个Datas类,再写其中的fromjson方法
//用Banner1是防止与关键字Banner重名
class Banner1 {
  //变量名需要是Json数据中的Key值,Datas类型自己定义,用来序列化data内部的键,
  //否则再外层解析时只能解析到dunamic
  final List<Datas> data;
  final int errorCode;
  final String errorMsg;

  Banner1({this.data,this.errorCode,this.errorMsg});

  //fromJson
  //当不是需要一个对象时候,可以用factory
  factory Banner1.fromJson(Map<String,dynamic> parsedJson){
    
    //由于Json数据中data是一个list数组,所以需要创建一个list分配给data
    //不能用data:paresedJson['data']   
    //(会提示type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'data')
    //同时也不能用data:Datas.fromJson(parsedjson['data'])
    //由于data是list<Datas>类型,而不是Datas对象
    var list = parsedJson['data'] as List;
      
    //需要创建一个dataLsit然后分配给data
    //遍历dataList列表,将每一个映射都调用fromJson,再将其存储到dataList中
    List<Datas> dataList = list.map((i) => Datas.fromJson(i)).toList();
    return Banner1(
      errorCode: parsedJson['errorCode'],
      errorMsg: parsedJson['errorMsg'],
      data: dataList
    );
  }
}

class Datas{
  final String desc;
  final int id;
  final String imagePath;
  final int isVisible;
  final int order;
  final String title;
  final int type;
  final String url;

  Datas({this.desc, this.id, this.imagePath, this.isVisible, this.order,
      this.title, this.type, this.url});

  factory Datas.fromJson(Map<String,dynamic> parsedJson){
    return Datas(
      desc: parsedJson['desc'],
      id: parsedJson['id'],
      imagePath: parsedJson['imagePath'],
      isVisible: parsedJson['isVisible'],
      order: parsedJson['order'],
      title: parsedJson['title'],
      type: parsedJson['type'],
      url: parsedJson['url']
    );
  }
}

加载Json数据

//采用异步操作
Future loadBanner(int index) async {
    //所需要的数据
    String imagePath;
    //获取Json格式字符串
    String jsonBanner = await _loadBannerJson();
    //解析Json
    final jsonResponse = json.decode(jsonBanner);
    //进行反序列化,得到banner1对象
    Banner1 banner = new Banner1.fromJson(jsonResponse);
    //得到所需数据
    imagePath = banner.data[index].imagePath;
  }

参考

https://www.jianshu.com/p/4a11d68d3239

https://medium.com/flutter-community/parsing-complex-json-in-flutter-747c46655f51 (原文)