美文网首页
[Flutter] 07-Flutter中反序列化Json

[Flutter] 07-Flutter中反序列化Json

作者: codeTao | 来源:发表于2020-06-22 16:24 被阅读0次

    由于Flutter中禁用运行时反射,所以如果项目简单的话可以考虑手动JSON 反序列化,如果你的项目很复杂的话,可以考虑官方建议的 json_serializable 代码生成器库。
    在本文中,我们主要讨论对象反序列化,即如何将服务器端返回的字符串数据转化为对象, 其他的Json转Model方式在下章讨论。

    • 首先先要了解什么是序列化和反序列化?

    把对象转换为字节序列的过程称为对象的序列化
    把字节序列恢复为对象的过程称为对象的反序列化

    接下来我们看下几种Json格式,如何反序列化的:

    一 简单map

    1) 分析的Json数据

    分析要诀:

    • 1> Json中用花括号是 Map,用方括号是 List。
    • 2> 对于嵌套结构,首先创建类和构造函数,然后从底层添加工厂方法。

    student.json 代码如下:

    {
      "id":"123456",
      "name":"codeTao",
      "score" : 99
    }
    

    该Json数据很明显是一个Map结构,可以创建一个Student类,通过factory构造方法来反序列化。

    2) 与Json结构对应的Model类

    student_model.dart 文件代码如下:

    class Student{
      String studentId;
      String studentName;
      int studentScores;
    
      Student({
        this.studentId,
        this.studentName,
        this.studentScores
    });
    
      factory Student.fromJson(Map<String, dynamic> parsedJson){
        return Student(
          studentId: parsedJson['id'],
          studentName : parsedJson['name'],
          studentScores : parsedJson ['score']
        );
      }
    }
    

    注意: fromJson 方法中的参数是一个 Map<String, dynamic> ,这意味着直到运行时我们才知道值的类型。

    3) 请求数据并反序列化

    student_services.dart 中请求数据, 并解析json, 最后调用 Student.fromJson 来反序列化,从 Student 对象中获取值。代码如下:

    //1.import 导入相关文件
    import 'dart:async' show Future;
    import 'package:flutter/services.dart' show rootBundle;
    import 'dart:convert';
    import 'package:parsing_json_demo/model/student_model.dart'; // 导入模型文件
    
    //2.加载 Json Asset
    Future<String> _loadAStudentAsset() async {
      return await rootBundle.loadString('assets/student.json');
    }
    
    //3. 加载响应数据
    Future loadStudent() async {
      //从 assets 中加载原始 json 字符串
      String jsonString = await _loadAStudentAsset();
      //解析 json 字符串
      final jsonResponse = json.decode(jsonString);
      //通过调用 Student.fromJson 方法反序列化解析的 json,以便可以使用 Student 对象来访问数据
      Student student = new Student.fromJson(jsonResponse);
      //Student 类里打印了 studentScores
      print("student.studentScores= ${student.studentScores}");
    }
    
    • 在这项目中,所有 json 文件放在 assets 文件夹下,所以我们必须这样加载 json。你也可以进行网络调用,网络调用不在这篇文章的讨论范围内。

    • 使用Flutter内置的dart:convert库Json解码器json.decode() 来实现,该方法可以根据 Json 字符串具体内容将其转为 List 或 Map。

    注意:请记住上面请求数据并反序列化的 3 个步骤(1.import 导入相关文件; 2.加载 Json Asset; 3.加载响应数据),接下来 json 解析都会用到(只更改文件名和方法名),我不会再重复书写该代码。但你可以在示例项目中查看所有内容。

    二. Map含有简单List结构

    1) 分析的Json数据

    {
      "city": "广州",
      "streets": [
        "北京路",
        "上下九街"
      ]
    }
    
    • 该数据是一个含有 List<String>的Map

    2) 与Json结构对应的Model类

    class Address {
      final String city;
      final List<String> streets;
    
      Address({
        this.city,
        this.streets
      });
    
      factory Address.fromJson(Map<String, dynamic> parsedJson) {
        var streetsFromJson  = parsedJson['streets'];
        print(streetsFromJson.runtimeType); //List<dynamic>
        // 显式地转换成 List<String>
        // List<String> streetsList = new List<String>.from(streetsFromJson);
        List<String> streetsList = streetsFromJson.cast<String>();
    
        return new Address(
          city: parsedJson['city'],
          streets: streetsList,
        );
      }
    }
    

    三 Map含有简单Map嵌套结构

    1) 分析的Json数据

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

    2) 与Json结构对应的Model类

    class Shape{
      String shapeName;
      Property property;
    
      Shape({
        this.shapeName,
        this.property
      });
    
      factory Shape.fromJson(Map<String, dynamic> parsedJson){
        return Shape(
          shapeName: parsedJson['shape_name'],
          property: Property.fromJson(parsedJson['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']
        );
      }
    }
    

    四 Map含有对象列表的嵌套结构

    1) 分析的Json数据

    {
      "id":1,
      "name":"盒装牛奶",
      "images":[
        {
          "id":11,
          "imageName":"telunsu.png"
        },
        {
          "id":22,
          "imageName":"wahaha.png"
        }
      ]
    }
    
    • Map含有 对象列表 的嵌套结构

    2) 与Json结构对应的Model类

    class Product {
      final int id;
      final String name;
      final List<Image> images;
    
      Product({this.id, this.name, this.images});
    
      factory Product.fromJson(Map<String, dynamic> parsedJson){
        var list = parsedJson['images'] as List;
        print(list.runtimeType); //List<dynamic>
        List<Image> imagesList = list.map((i) => Image.fromJson(i)).toList();
        //print(imagesList.runtimeType); // map操作后imagesList类型为 'MappedListIterable<dynamic, Image>
        //不转化为List<Image>就会报错: Unhandled Exception: type 'MappedListIterable<dynamic, Image>' is not a subtype of type 'List<Image>'
    
        return Product(
          id: parsedJson['id'],
          name: parsedJson['name'],
          images: imagesList
        );
      }
    }
    
    class Image {
      final int imageId;
      final String imageName;
    
      Image({this.imageId, this.imageName});
    
      factory Image.fromJson(Map<String, dynamic> parsedJson){
       return Image(
         imageId:parsedJson['id'],
         imageName:parsedJson['imageName']
       );
      }
    }
    

    其中 List<Image> imagesList = list.map((i) => Image.fromJson(i)).toList();
    list 在这里是一个 List。现在我们通过调用 Image.fromJson 遍历整个列表,并把 list 中的每个对象映射到 Image 中,然后我们将每个 map 对象放入一个带有 toList() 的新列表中,并将它存储在 List<Image> imagesList。

    五 map列表

    1) 分析的Json数据

    [
      {
        "albumId": 1,
        "id": 1,
        "title": "美丽的小径",
        "url": "http://b.zol-img.com.cn/sjbizhi/images/11/640x1136/1592364145769.jpg",
        "thumbnailUrl": "http://b.zol-img.com.cn/sjbizhi/images/11/480x800/1592364145769.jpg"
      },
      {
        "albumId": 1,
        "id": 2,
        "title": "小朋友说,别笑,我在办公呢?",
        "url": "http://b.zol-img.com.cn/sjbizhi/images/11/640x1136/1592366115586.jpg",
        "thumbnailUrl": "http://b.zol-img.com.cn/sjbizhi/images/11/480x800/1592366115586.jpg"
      },
      {
        "albumId": 1,
        "id": 3,
        "title": "豪华跑车",
        "url": "http://sjbz.fd.zol-img.com.cn/t_s640x1136c/g3/M08/0E/0B/ChMlWF7oPRuIcWdWABs0s8RzN5wAAU0PwJXf0sAGzTL604.jpg",
        "thumbnailUrl": "http://sjbz.fd.zol-img.com.cn/t_s480x800c/g3/M08/0E/0B/ChMlWF7oPRuIcWdWABs0s8RzN5wAAU0PwJXf0sAGzTL604.jpg"
      }
    ]
    

    2) 与Json结构对应的Model类

    class PhotosList {
      final List<Photo> photos;
    
      PhotosList({
        this.photos,
    });
    
      factory PhotosList.fromJson(List<dynamic> parsedJson) {
    
        List<Photo> photos = new List<Photo>();
        photos = parsedJson.map((i)=>Photo.fromJson(i)).toList();
    
        return new PhotosList(
          photos: photos
        );
      }
    }
    
    class Photo{
      final String id;
      final String title;
      final String url;
    
      Photo({
        this.id,
        this.url,
        this.title
    }) ;
    
      factory Photo.fromJson(Map<String, dynamic> json){
        return new Photo(
          id: json['id'].toString(),
          title: json['title'],
          url: json['json'],
        );
      }
    }
    

    六 复杂的嵌套结构

    1) 分析的Json数据

    {
      "page": 1,
      "per_page": 3,
      "total": 12,
      "total_pages": 4,
      "author":{
        "name": "CodeTao"
      },
      "data": [
        {
          "id": 1,
          "name": "Harry",
          "avatar": "https://img.haomeiwen.com/i126164/be76091e050f0605.png",
          "images": [
            {
              "id" : 22,
              "imageName": "aaa.jpeg"
            },
            {
              "id" : 23,
              "imageName": "bbb.jpeg"
            }
          ]
        },
        {
          "id": 2,
          "name": "Jame",
          "avatar": "https://img.haomeiwen.com/i126164/be76091e050f0605.png",
          "images": [
            {
              "id" : 33,
              "imageName": "ccc.jpeg"
            },
            {
              "id" : 34,
              "imageName": "ddd.jpeg"
            }
          ]
        },
        {
          "id": 3,
          "name": "Henry",
          "avatar": "https://img.haomeiwen.com/i126164/be76091e050f0605.png",
          "images": [
            {
              "id" : 44,
              "imageName": "eee.jpeg"
            },
            {
              "id" : 45,
              "imageName": "fff.jpeg"
            }
          ]
        }
      ]
    }
    

    2) 与Json结构对应的Model类

    class Page{
      int page;
      int perPage;
      int total;
      int totalPages;
      Author author;
      List<Data> data;
    
      Page({
        this.page,
        this.perPage,
        this.total,
        this.totalPages, this.author, this.data});
    
      factory Page.fromJson(Map<String, dynamic> parsedJson){
    
        var list = parsedJson['data'] as List;
        List<Data> data = list.map((i) => Data.fromJson(i)).toList();
    
        return Page(
            page: parsedJson['page'],
            perPage: parsedJson['per_page'],
            total: parsedJson['total'],
            totalPages: parsedJson['total_pages'],
            author: Author.fromJson(parsedJson['author']),
            data: data
        );
      }
    }
    
    
    class Author{
      String name;
    
      Author({this.name});
    
      factory Author.fromJson(Map<String, dynamic> parsedJson){
        return Author(
          name: parsedJson['name'],
        );
      }
    }
    
    class Data{
      int id;
      String name; // add others
      List<Image> imagesList;
    
      Data({
        this.id, this.name, this.imagesList
    });
    
      factory Data.fromJson(Map<String, dynamic> parsedJson){
    
        var list = parsedJson['images'] as List;
        List<Image> images = list.map((i) => Image.fromJson(i)).toList();
    
        return Data(
            id: parsedJson['id'],
            name: parsedJson['name'],
            imagesList: images
        );
      }
    }
    
    class Image{
      int id;
      String imageName;
    
      Image({
      this.id, this.imageName
    
      });
    
      factory Image.fromJson(Map<String, dynamic> parsedJson){
        return Image(
            id: parsedJson['id'],
            imageName : parsedJson['imageName'],
        );
      }
    
    }
    

    七 手动Json转Model优缺点:

    • 优点:完全是自己可控的,并且需要哪些字段就转化哪些字段,对于不需要的,忽略即可;并且继承关系也会一目了然
    • 缺点:数据嵌套层级多,会非常麻烦,并且容易出错。

    所以如果数据嵌套层级多的话,建议使用dart官方推荐json_serializable方式进行Json转Model ,进一步了解查看下一篇[Flutter] 08-Flutter中的Json转Model

    由于笔者水平有限,文中如果有错误的地方,或者有更好的方法,还望大神指出。
    附上本文的所有 demo 下载链接,【GitHub】
    如果你看完后觉得对你有所帮助,还望在 GitHub 上点个 star。赠人玫瑰,手有余香。

    相关文章

      网友评论

          本文标题:[Flutter] 07-Flutter中反序列化Json

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