美文网首页flutter学习Flutter
Flutter 中的 JSON 解析

Flutter 中的 JSON 解析

作者: c263ae2147d8 | 来源:发表于2019-03-25 18:17 被阅读0次

    JSON 是我们开发中最常使用的一种数据格式,这篇文章中,我们主要看看在开发中最常见的几种格式的 JSON 数据在 Flutter 中的解析:

    以下案例中,我们都会将json文件放到本地,也就是 assets 文件中,然后从本地读取这些文件进行解析。

    如我们需要读取 assets/person.json :

    image

    那么就需要在 pubspec.yaml 中做如下配置:

    flutter:
        uses-material-design:  true
        # 资源文件配置
        assets:
            -  assets/person.json
    

    下面我们就来解析一些常见的 Json 格式的数据。

    如果对 Dart 基础还不是很了解,可以先看看这篇文章 Dart 基础入门

    简单的对象解析

    定义一个 person.json 如下:

    {
        "name":  "jack",
        "age":  18,
        "height":  175.0
    }
    

    和在 Java 里面一样,我们首先需要构建一个 Person 的实体类,如下:

    class Person {
      String name;
      int age;
      double height;
    
      Person({this.name, this.age, this.height});
    
      factory Person.fromJson(Map<String, dynamic> json) {
        return Person(name: json['name'], age: json['age'], height: json['height']);
      }
    }
    

    接着,我们在创建一个 person_service.dart 来解析 person.json。

    该类中需要导入如下几个依赖库:

    // 使用该库中的 rootBundle 对象来读取 perosn.json 文件
    import 'package:flutter/services.dart';  
    // json
    import 'dart:convert';  
    // 异步 Future
    import 'dart:async';
    

    person_service.dart

    import 'package:flutter/services.dart';
    import 'dart:convert';
    import 'dart:async';
    import '../models/person.dart';
    
    // 读取 assets 文件夹中的 person.json 文件
    Future<String> _loadPersonJson() async {
      return await rootBundle.loadString('assets/person.json');
    }
    
    // 将 json 字符串解析为 Person 对象
    Future<Person> decodePerson() async {
      // 获取本地的 json 字符串
      String personJson = await _loadPersonJson();
    
      // 解析 json 字符串,返回的是 Map<String, dynamic> 类型
      final jsonMap = json.decode(personJson);
    
      print('jsonMap runType is ${jsonMap.runtimeType}');
    
      Person person = Person.fromJson(jsonMap);
    
      print(
          'person name is ${person.name}, age is ${person.age}, height is ${person.height}');
    
      return person;
    }
    

    输入如下:

    flutter: jsonMap runType is _InternalLinkedHashMap<String, dynamic>
    flutter: person name is jack, age is 18, height is 175.0
    

    可以看出 json.decode(personJson) 方法返回的类型为 _InternalLinkedHashMap<String, dynamic> ,意思就是这个 Map 的 key 为 String 类型,而 value 的类型为 dynamic 的,也就是动态的,就如 person.json 中,key 都是 String 类型的,但是 value 可能是 String 、int、double 等等类型。

    包含数组的对象

    定义一个 country.json 如下:

    {
        "name": "China",
        "cities": [
            "Beijing",
            "Shanghai"
        ]
    }
    

    实体类如下:

    class Country {  
      String name;  
      List<String> cities;  
      
      Country({this.name, this.cities});  
      
      factory Country.fromJson(Map<String, dynamic> json) {  
      return Country(name: json['name'], cities: json['cities']);  
      }  
    }
    

    Service 类如下:

    import 'dart:async';
    import 'package:flutter/services.dart';
    import 'dart:convert';
    import '../models/country.dart';
    
    Future<String> _loadCountryJson() async {
      return await rootBundle.loadString('assets/country.json');
    }
    
    Future<Country> decodeCountry() async {
      String countryJson = await _loadCountryJson();
    
      Map<String, dynamic> jsonMap = json.decode(countryJson);
    
      Country country = Country.fromJson(jsonMap);
      print('country name is ${country.name}');
      return country;
    }
    

    然后我们在 main() 中去调用 decodeCountry() 运行,报错了...

    Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<String>'
    ...
    

    错误日志说 List<dynamic> 不是 List<String> 的子类型,也就是我们在country的实体类中直接给 cities 属性赋值为 cities: json['cities'],我们先来看看 json['cities'] 是什么类型:

    factory Country.fromJson(Map<String, dynamic> json) {  
      print('json["cities"] type is ${json['cities'].runtimeType}');  
      return Country(name: json['name'], cities: json['cities']);  
    }
    

    输出如下:

    flutter: json["cities"] type is List<dynamic>
    

    这个时候我们需要将 Country.fromJson(...) 方法作如下更改:

    factory Country.fromJson(Map<String, dynamic> json) {
        print('json["cities"] type is ${json['cities'].runtimeType}');
        var originList = json['cities'];
        List<String> cityList = new List<String>.from(originList);
        return Country(name: json['name'], cities: cityList);
      }
    

    上述代码中,我们创建了一个 List<String> 类型的数组,然后将 List<dynamic> 数组中的元素都添加到了 List<String> 中。输出如下:

    flutter: json["cities"] type is List<dynamic>
    flutter: country name is China
    

    对象嵌套

    定义一个 shape.json ,格式如下:

    {  
      "name": "rectangle",  
      "property": {  
      "width": 5.0,  
      "height": 10.0  
      }  
    }
    

    实体如下:

    class Shape {  
      String name;  
      Property property;  
      
      Shape({this.name, this.property});  
      
      factory Shape.fromJson(Map<String, dynamic> json) {  
      return Shape(name: json['name'], property: json['property']);  
      }  
    }  
      
    class Property {  
      double width;  
      double height;  
      
      Property({this.width, this.height});  
      
      factory Property.fromJson(Map<String, dynamic> json) {  
      return Property(width: json['width'], height: json['height']);  
      }  
    }
    

    Service 类如下:

    import 'dart:async';  
    import 'dart:convert';  
    import 'package:flutter/services.dart';  
    import '../models/shape.dart';  
      
    Future<String> _loadShapeJson() async {  
      return await rootBundle.loadString('assets/shape.json');  
    }  
      
    Future<Shape> decodeShape() async {  
      String shapeJson = await _loadShapeJson();  
      
      Map<String, dynamic> jsonMap = json.decode(shapeJson);  
      
      Shape shape = Shape.fromJson(jsonMap);  
      
      print('shape name is ${shape.name}');  
      return shape;  
    }
    

    运行之后,会报如下错误:

    Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Property'
    

    也就是说 property: json['property'] 这里赋值的类型是 _InternalLinkedHashMap<String, dynamic> 而不是 Propertyjson['property'] 的值是这样的 {width: 5.0, height: 10.0},它是一个 Map ,并不是一个 Property 对象,我们需要先将这个 Map 转化为对象,然后在赋值:

    factory Shape.fromJson(Map<String, dynamic> json) {  
      print('json["property"] is ${json['property']}');  
      Property property = Property.fromJson(json['property']);   // new line
      return Shape(name: json['name'], property: property);  
    }
    

    输出:

    shape name is rectangle
    

    复杂的对象数组嵌套

    {
      "id": "0302",
      "class_name": "三年二班",
      "students": [
        {
          "name": "叶湘伦",
          "sex": "男"
        },
        {
          "name": "路小雨",
          "sex": "女"
        }
      ]
    }
    

    实体:

    class ClassInfo {
      String id;
      String name;
      List<Student> studentList;
    
      ClassInfo({this.id, this.name, this.studentList});
    
      factory ClassInfo.fromJson(Map<String, dynamic> json) {
        return ClassInfo(
            id: json['id'],
            name: json['class_name'],
            studentList: json['students']);
      }
    }
    
    class Student {
      String name;
      String sex;
    
      Student({this.name, this.sex});
    
      factory Student.fromJson(Map<String, dynamic> json) {
        return Student(name: json['name'], sex: json['sex']);
      }
    }
    

    service:

    import 'dart:async';
    import 'dart:convert';
    import 'package:flutter/services.dart';
    import '../models/class_info.dart';
    
    Future<String> _loadClassInfoJson() async {
      return await rootBundle.loadString('assets/class_info.json');
    }
    
    Future<ClassInfo> decodeClassInfo() async {
      String classInfoJson = await _loadClassInfoJson();
    
      Map<String, dynamic> jsonMap = json.decode(classInfoJson);
    
      ClassInfo classInfo = ClassInfo.fromJson(jsonMap);
      classInfo.studentList
          .forEach((student) => print('student name is ${student.name}'));
      return classInfo;
    }
    

    上述代码在运行后还是会报错:

    Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<Student>'
    

    同样,还是在 studentList: json['students'] 出问题了,我们把 json['students'] 的输出来看看:

    [{name: 叶湘伦, sex: 男}, {name: 路小雨, sex: 女}]
    

    上述结果的类型为 List<dynamic> 。现在我们需要将 List<dynamic> 转换到一个 List<Student> 类型的数组中,这里需要用到一个操作符 mapmap 操作符的作用就是将某种类型转换为另一种类型。如下:

    factory ClassInfo.fromJson(Map<String, dynamic> json) {  
      final originList = json['students'] as List;  
      List<Student> studentList =  
          originList.map((value) => Student.fromJson(value)).toList();  
      return ClassInfo(  
      id: json['id'], name: json['class_name'], studentList: studentList);  
    }
    

    输出:

    flutter: student name is 叶湘伦
    flutter: student name is 路小雨
    

    单纯的数组

    member.json

    [
      {
        "id": 1,
        "name": "Jack"
      },
      {
        "id": 2,
        "name": "Rose"
      },
      {
        "id": 3,
        "name": "Karl"
      }
    ]
    

    实体:

    class MemberList {  
      List<Member> memberList;  
      
      MemberList({this.memberList});  
      
      factory MemberList.fromJson(List<dynamic> listJson) {  
      
      List<Member> memberList =  
            listJson.map((value) => Member.fromJson(value)).toList();  
      
      return MemberList(memberList: memberList);  
      }  
    }  
      
    class Member {  
      int id;  
      String name;  
      
      Member({this.id, this.name});  
      
      factory Member.fromJson(Map<String, dynamic> json) {  
      return Member(id: json['id'], name: json['name']);  
      }  
    }
    

    因为 member.json 是一个单纯的数组,所以上述代码中我们创建了一个 MemberList 类来将这个 Member 数组包含起来。

    注意下上述代码中 MemberList.fromJson(...) 中的写法。

    service:

    import 'dart:async';
    import 'package:flutter/services.dart';
    import 'dart:convert';
    import '../models/member.dart';
    
    Future<String> _loadMemberJson() async {
      return await rootBundle.loadString('assets/member.json');
    }
    
    Future<MemberList> decodeMemberList() async {
      String memberListJson = await _loadMemberJson();
    
      List<dynamic> list = json.decode(memberListJson);
    
      MemberList memberList = MemberList.fromJson(list);
    
      memberList.memberList
          .forEach((member) => print('member name is ${member.name}'));
    
      return memberList;
    }
    

    输出:

    flutter: member name is Jack
    flutter: member name is Rose
    flutter: member name is Karl
    

    复杂的 Json 解析

    之前的文章 Flutter 中 ListView 的使用 中用到了 豆瓣API ,这个 API 中返回的数据包含了当前热播的电影,大家尝试着按需解析一下吧 !!!

    image

    如有错误,还请指出。谢谢!!!

    源码地址

    参考链接:

    https://medium.com/flutter-community/parsing-complex-json-in-flutter-747c46655f51

    https://github.com/flutter/flutter/issues/9318

    相关文章

      网友评论

        本文标题:Flutter 中的 JSON 解析

        本文链接:https://www.haomeiwen.com/subject/onbbvqtx.html