此文注重梳理官方文檔和整合實(shí)際開發(fā)的業(yè)務(wù)場景進(jìn)行分析呕乎,鞏固基礎(chǔ)荚斯。
首先,F(xiàn)lutter中是否有GSON / Jackson / Moshi霉颠?官方文檔明確表明--沒有对碌!且是禁用的,因?yàn)檫@些工具使用了反射機(jī)制蒿偎,反射會默認(rèn)使用Dark所有代碼俭缓,讓tree shaking會很難工作,運(yùn)用文檔所說的:
使用 dart:convert手動序列化JSON
使用工具:Flutter有一個內(nèi)置dart:convert庫
關(guān)鍵代碼:
- User.fromJson 構(gòu)造函數(shù), 用于從一個map構(gòu)造出一個 User實(shí)例 map structure
- toJson 方法, 將 User 實(shí)例轉(zhuǎn)化為一個map.
解析代碼:
import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
class User {
final String name;
final String password;
User(this.name, this.password);
User.fromJson(Map<String, dynamic> json)
: name = json['name'],
password = json['password'];
Map<String, dynamic> toJson() => {
'name': name,
'password': password,
};
}
String jsonStr = "{\"name\": \"Hank\",\"password\": \"123456\"}";//解析數(shù)據(jù)
void main() {
test('json test', () {
Map userMap = json.decode(jsonStr);
var user = new User.fromJson(userMap);
print('name, ${user.name}!');
print('password, ${user.password}.');
print('user json, ${user.toJson()}.');
});
}
使用代碼生成庫序列化JSON
使用了json_serializable package包椿息,它是一個自動化的源代碼生成器。
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
注意坷衍,yaml配置文件對于縮進(jìn)要求十分嚴(yán)格寝优,下面的build_runner和json_serializable應(yīng)該
是dev_dependencies的一級子項(xiàng),json_serializable千萬不要寫在build_runner縮進(jìn)后枫耳,這樣它會認(rèn)為是build_runner的子集目錄乏矾!
在項(xiàng)目根文件夾中運(yùn)行 flutter packages get (或者在編輯器中點(diǎn)擊 “Packages Get”) 以在項(xiàng)目中使用這些新的依賴項(xiàng)。
解析代碼:
import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:json_annotation/json_annotation.dart';
// user.g.dart 將在我們運(yùn)行生成命令后自動生成
part 'user.g.dart';
@JsonSerializable()
class User {
String name;
String password;
User(this.name, this.password);
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
String jsonStr = "{\"name\": \"Hank\",\"password\": \"123456\"}";
void main() {
test('json test', () {
Map userMap = json.decode(jsonStr);
var user = new User.fromJson(userMap);
print('name, ${user.name}!');
print('password, ${user.password}.');
print('user json, ${user.toJson()}.');
});
}
復(fù)制以上代碼使用json_serializable第一次創(chuàng)建類時迁杨,您會看到與下圖類似的錯誤钻心。
這些錯誤是完全正常的,這是因?yàn)閙odel類的生成代碼還不存在铅协。為了解決這個問題捷沸,我們必須運(yùn)行代碼生成器來為我們生成序列化模板。這就讓我想起和Dagger一樣需要預(yù)編譯才可以調(diào)用生成類狐史。
有兩種運(yùn)行代碼生成器的方法:
一次性生成
通過在我們的項(xiàng)目根目錄下運(yùn)行flutter packages pub run build_runner build痒给,我們可以在需要時為我們的model生成json序列化代碼。 這觸發(fā)了一次性構(gòu)建骏全,它通過我們的源文件苍柏,挑選相關(guān)的并為它們生成必要的序列化代碼。
雖然這非常方便姜贡,但如果我們不需要每次在model類中進(jìn)行更改時都要手動運(yùn)行構(gòu)建命令的話會更好序仙。
持續(xù)生成
使用watcher可以使我們的源代碼生成的過程更加方便。它會監(jiān)視我們項(xiàng)目中文件的變化鲁豪,并在需要時自動構(gòu)建必要的文件潘悼。我們可以通過flutter packages pub run build_runner watch在項(xiàng)目根目錄下運(yùn)行來啟動watcher律秃。
只需啟動一次觀察器,然后并讓它在后臺運(yùn)行治唤,這是安全的棒动。
但是如果你運(yùn)行了以上命令行均沒有生成user.g.dart那可能你沒有做到以下規(guī)范:
dart代碼中User首字母可以大寫,但是文件名字建議全部為小寫,如user.dart,與User類名同名宾添,生成代碼的時候會匹配文件名和類名是否一致船惨,否則無法生成user.g.dart。
當(dāng)然如果已經(jīng)有User類名能匹配到文件名后缕陕,在該文件再編寫其他不同名的@JsonSerializable class也是能正常編譯出來粱锐。
@JsonKey標(biāo)注:
如果我們正在使用的API返回帶有registration_date_millis字段,但我們想在我們的模型中使用registrationDateMillis
@JsonKey(name: 'registration_date_millis')
final int registrationDateMillis;