Flutter - JSON與序列化

兩種JSON序列化方式:

  • 手動(dòng)序列化:適用小項(xiàng)目
  • 代碼生成自動(dòng)序列化:適用大中型項(xiàng)目

手動(dòng)序列化

使用 dart:convert 中內(nèi)置的JSON解碼器。將原始JSON字符串傳遞給 jsonDecode() 方法,然后在 Map<String, dynamic> 結(jié)果中查找需要的值。

優(yōu)點(diǎn):簡(jiǎn)單,不需要其它依賴或特別設(shè)置。
缺點(diǎn):手寫序列化邏輯容易出錯(cuò),當(dāng)字段錯(cuò)誤將會(huì)拋出異常。

//示例:user model 的 json
{
  "name": "John Smith",
  "email": "john@example.com"
}

通過dart:convert序列化的兩種方式:

  1. 內(nèi)聯(lián)序列化JSON
    dart:convert 中,通過給 jsonDecode()方法傳遞JSON字符串參數(shù)來實(shí)現(xiàn)解碼,但只能返回 Map<String, dynamic> ,這意味著直到運(yùn)行時(shí)才知道值的類型,且失去了大部分靜態(tài)語言特性:類型安全、自動(dòng)補(bǔ)全和最重要的編譯時(shí)異常。
Map<String, dynamic> user = jsonDecode(jsonString);

print('Howdy, ${user['name']}!');
print('We sent the verification link to ${user['email']}.');
  1. 模板類型序列化JOSN
    通過引入模型類(model class)來解決前面提到的問題。
    示例: User model
    • User.fromJson() 構(gòu)造函數(shù):用于從 map 中構(gòu)造 User 實(shí)例。
    • toJson() 方法:將 User 實(shí)例轉(zhuǎn)化為 map。
//user.dart
class User {
  final String name;
  final String email;

  User(this.name, this.email);

  User.fromJson(Map<String, dynamic> json)
      : name = json['name'],
        email = json['email'];

  Map<String, dynamic> toJson() =>
    {
      'name': name,
      'email': email,
    };
}

//反序列化(decode)
Map userMap = jsonDecode(jsonString);
var user = new User.fromJson(userMap);

print('Howdy, ${user.name}!');
print('We sent the verification link to ${user.email}.');

//序列化(encode)
String json = jsonEncode(user);

自動(dòng)序列化

使用外部庫生成序列化模板,通過初始化設(shè)置,運(yùn)行從model類自動(dòng)生成代碼的文件觀察器。
如:json_serializable 、 built_value

優(yōu)點(diǎn):字段錯(cuò)誤,會(huì)在編譯期捕獲。
缺點(diǎn):需要初始化設(shè)置。

示例:使用 json_serializable

  1. 添加依賴
    • dependencies:依賴
    • dev_dependencies 開發(fā)依賴:只在開發(fā)環(huán)境使用
//pubspec.yaml
dependencies:
  # Your other regular dependencies here
  json_annotation: ^2.0.0

dev_dependencies:
  # Your other dev_dependencies here
  build_runner: ^1.0.0
  json_serializable: ^2.0.0
  1. 以json_serializable的方式創(chuàng)建model類
//user.dart
import 'package:json_annotation/json_annotation.dart';

/// user.g.dart 將在運(yùn)行生成命令后自動(dòng)生成
part 'user.g.dart';

/// 該注解告訴代碼生成器需要生成什么model
@JsonSerializable()

class User {
  User(this.name, this.email);

  String name;
  String email;

  /// 不同的類使用不同的mixin
  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);

  Map<String, dynamic> toJson() => _$UserToJson(this);
}

//自定義字段名
@JsonKey(name: 'registration_date_millis')
final int registrationDateMillis;
  1. 運(yùn)行代碼生成
    第一次使用json_serializable創(chuàng)建類時(shí)可能會(huì)有如下錯(cuò)誤:

    解決:通過代碼生成器生成序列化模板,有兩種方式:

    1. 一次性生成
      在項(xiàng)目根目錄運(yùn)行 flutter packages pub run build_runner build,會(huì)觸發(fā)一次性構(gòu)建 -- 檢查篩選需要序列化的代碼。
    2. 持續(xù)生成
      在項(xiàng)目根目錄運(yùn)行 flutter packages pub run build_runner watch 開啟監(jiān)視器(watcher),當(dāng)項(xiàng)目文件變化時(shí)自動(dòng)生成相應(yīng)的文件。
  2. 使用

//decode
Map userMap = jsonDecode(jsonString);
var user = User.fromJson(userMap);

//encode
String json = jsonEncode(user);

沒有有GSON / Jackson / Moshi

這些庫使用了反射,而 Flutter中禁用反射。
反射會(huì)干擾 tree shaking,在發(fā)版時(shí) tree shaking 會(huì)“去除”未使用的代碼,降低應(yīng)用的大小。

雖然不能使用反射,但是一些基于代碼生成的庫,提供了類似的API。
詳細(xì)參看:code generation libraries

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容