关于 Flutter JSON 序列化

官方关于JSON序列化的文档:JSON and serialization
大致意思是 Flutter 没有类似 Gson 的 JSON 序列化库,那样需要借助反射机制知晓运行时类型,Flutter应用会对多余的代码进行优化,这种优化机制与反射冲突,所以只能借助注解编译生成序列化的代码。

Dart内置的 convert 包,有两个函数是用来序列化和反序列化的:
jsonEncode()
jsonDecode()
但是这两个函数是转化 String 和 Map,即 
String jsonEncode(Map)
Map jsonDecode(String)
我这里写的函数声明类型跟实际不一样,但是 jsonEncode() 只有传入 Map 才能转化成功,基本就是 Map对应JSON对象,List对应JSON数组,Dart最开始是携带JS基因的,但是又是强类型语言,Map 类的字面量十分接近JSON,如果要将JSON字符串转成自定义的类,就要编写对应的函数:
//构造函数
ClassName.fromJson(Map json)

//实例方法
Map toJson()
下面是高德web服务API查询天气获取的JSON数据:
{
  "status": "1",
  "count": "1",
  "info": "OK",
  "infocode": "10000",
  "forecasts": [
    {
      "city": "深圳市",
      "adcode": "440300",
      "province": "广东",
      "reporttime": "2022-07-09 16:00:47",
      "casts": [
        {
          "date": "2022-07-09",
          "week": "6",
          "dayweather": "多云",
          "nightweather": "多云",
          "daytemp": "33",
          "nighttemp": "27",
          "daywind": "北",
          "nightwind": "北",
          "daypower": "≤3",
          "nightpower": "≤3"
        },
        {
          "date": "2022-07-10",
          "week": "7",
          "dayweather": "多云",
          "nightweather": "多云",
          "daytemp": "33",
          "nighttemp": "27",
          "daywind": "北",
          "nightwind": "北",
          "daypower": "≤3",
          "nightpower": "≤3"
        },
        {
          "date": "2022-07-11",
          "week": "1",
          "dayweather": "晴",
          "nightweather": "晴",
          "daytemp": "33",
          "nighttemp": "27",
          "daywind": "北",
          "nightwind": "北",
          "daypower": "≤3",
          "nightpower": "≤3"
        },
        {
          "date": "2022-07-12",
          "week": "2",
          "dayweather": "晴",
          "nightweather": "晴",
          "daytemp": "33",
          "nighttemp": "27",
          "daywind": "北",
          "nightwind": "北",
          "daypower": "≤3",
          "nightpower": "≤3"
        }
      ]
    }
  ]
}

对应的数据类(手动编写JSON序列化代码):

import 'dart:convert';
//手动编写JSON序列化的代码
class Weather {
  String status = '';
  String count = '';
  String info = '';
  String infocode = '';
  List forecasts = [];

  Weather.fromJson(String json) {
    var result = jsonDecode(
        json /*, reviver: (key, value) {
      print('$key=$value ${value.runtimeType}');
    }*/
        );
    // print('result.runtimeType=${result.runtimeType}'); // Map
    status = result['status'];
    count = result['count'];
    info = result['info'];
    infocode = result['infocode'];
    // print(result['forecasts'].runtimeType);// List
    forecasts = (result['forecasts'] as List)
        .map((e) => Forecast.fromMap(e as Map))
        .toList();
  }

  Map toJson() {
    return {
      'status': status,
      'count': count,
      'info': info,
      'infocode': infocode,
      'forecasts': forecasts.map((e) => e.toJson()).toList(),
    };
  }
}

class Forecast {
  String city = '';
  String adcode = '';
  String province = '';
  String reporttime = '';
  List casts = [];

  Forecast.fromMap(Map map) {
    city = map["city"];
    adcode = map["adcode"];
    province = map["province"];
    reporttime = map["reporttime"];
    casts = (map["casts"] as List)
        .map((e) => Cast.fromMap(e as Map))
        .toList();
  }

  Map toJson() {
    return {
      'city': city,
      'adcode': adcode,
      'province': province,
      'reporttime': reporttime,
      'casts': casts.map((e) => e.toJson()).toList(),
    };
  }
}

class Cast {
  String date = '';
  String week = '';
  String dayweather = '';
  String daytemp = '';
  String nighttemp = '';
  String daywind = '';
  String nightwind = '';
  String daypower = '';
  String nightpower = '';

  Cast.fromMap(Map map) {
    date = map['date'];
    week = map['week'];
    dayweather = map['dayweather'];
    daytemp = map['daytemp'];
    nighttemp = map['nighttemp'];
    daywind = map['daywind'];
    nightwind = map['nightwind'];
    daypower = map['daypower'];
    nightpower = map['nightpower'];
  }

  Map toJson() {
    return {
      'date': date,
      'week': week,
      'dayweather': dayweather,
      'daytemp': daytemp,
      'nighttemp': nighttemp,
      'daywind': daywind,
      'nightwind': nightwind,
      'daypower': daypower,
      'nightpower': nightpower,
    };
  }
}
这里使用的 JSON 数据已经算比较复杂了,如果实际开发中使用更复杂的数据,手动编写就很繁琐了,这时候就要借助工具来生成样板代码,生成样板代码需要在 pubspec.yaml 添加如下依赖:
dependencies:
  ...
  json_serializable: ^6.3.1

dev_dependencies:
  ...
  build_runner: ^2.1.11

按照官方文档中的示例编写如下的数据类代码(IDE会有红色提示,先忽略,运行本文后面提到的 flutter 指令后会生成缺失的方法),其中两个类的注解带有explicitToJson 参数@JsonSerializable(explicitToJson: true),这样是为了解析嵌套的类

import 'package:json_annotation/json_annotation.dart';

/// This allows the `WeatherX` class to access private members in
/// the generated file. The value for this is *.g.dart, where
/// the star denotes the source file name.
part 'weather_x.g.dart';

/// An annotation for the code generator to know that this class needs the
/// JSON serialization logic to be generated.
/// explicitToJson: true 是为了解析嵌套的类
@JsonSerializable(explicitToJson: true)
class WeatherX {
  String status = '';
  String count = '';
  String info = '';
  String infocode = '';
  List forecasts = [];

  WeatherX(this.status, this.count, this.info, this.infocode, this.forecasts);

  /// A necessary factory constructor for creating a new WeatherX instance
  /// from a map. Pass the map to the generated `_$WeatherXFromJson()` constructor.
  /// The constructor is named after the source class, in this case, WeatherX.
  factory WeatherX.fromJson(Map json) =>
      _$WeatherXFromJson(json);

  /// `toJson` is the convention for a class to declare support for serialization
  /// to JSON. The implementation simply calls the private, generated
  /// helper method `_$WeatherXToJson`.
  Map toJson() => _$WeatherXToJson(this);
}

@JsonSerializable(explicitToJson: true)
class ForecastX {
  String city = '';
  String adcode = '';
  String province = '';
  String reporttime = '';
  List casts = [];

  ForecastX(this.city, this.adcode, this.province, this.reporttime, this.casts);

  factory ForecastX.fromJson(Map json) =>
      _$ForecastXFromJson(json);

  Map toJson() => _$ForecastXToJson(this);
}

@JsonSerializable()
class CastX {
  String date = '';
  String week = '';
  String dayweather = '';
  String daytemp = '';
  String nighttemp = '';
  String daywind = '';
  String nightwind = '';
  String daypower = '';
  String nightpower = '';

  CastX(this.date, this.week, this.dayweather, this.daytemp, this.nighttemp,
      this.daywind, this.nightwind, this.daypower, this.nightpower);

  factory CastX.fromJson(Map json) =>
      _$CastXFromJson(json);

  Map toJson() => _$CastXToJson(this);
}

 然后在工程根目录执行下面的指令:

flutter pub run build_runner build

命令执行成功,就会生成 xxx.g.dart 文件,里面包含了生成的样板代码,之前编写的数据类也不再提示错误,最后就可以使用下面的代码进行JSON序列化和反序列化:

import 'dart:convert';

import '../weather_x.dart';

// JSON 字符串转 Dart 类实例
WeatherX weatherX = WeatherX.fromJson(jsonDecode(jsonString));

// 类实例转 JSON 字符串
String jsonString = jsonEncode(weatherX);

你可能感兴趣的:(flutter,json)