
前言
最近Google開源的跨平臺移動開發(fā)框架Flutter非常火熱,推出了1.0的正式版,趁著熱度,我也是抽空粗略地學(xué)習(xí)了一下。目前網(wǎng)上Flutter相關(guān)的資料和開源項目也非常多了,在學(xué)習(xí)的過程中給了我很多幫助。因此,我想通過一系列文章記錄一下自己學(xué)習(xí)Flutter遇到的一些問題,既是對自身技術(shù)的鞏固,也方便日后即時查閱。
本文介紹一下Flutter中如何進行json數(shù)據(jù)的解析。在移動端開發(fā)中,請求服務(wù)端返回json數(shù)據(jù)并解析是一個很常見的使用場景。Android原生開發(fā)中,有GsonFormat這樣的神器,一鍵生成JavaBean,并利用Gson實現(xiàn)json數(shù)據(jù)和對象的轉(zhuǎn)化;在React Native中更是得益于直接使用javascript語言,無需對json對象進行解析便可以直接訪問屬性。那么在Flutter中如何實現(xiàn)對json數(shù)據(jù)的解析呢?
Flutter采用dart語言進行開發(fā),dart具有很多核心庫,其中dart:convert庫中內(nèi)置了json轉(zhuǎn)換器,可以實現(xiàn)將json數(shù)據(jù)轉(zhuǎn)換成dart對象。簡單的使用如下:
import 'dart:convert';
void main() {
// 解析對象
String jsonStr1 = '{"name":"Curry","email":"SC@GSW.com"}';
Map<String, dynamic> map = json.decode(jsonStr1);
print(map['name']);
// 解析列表
String jsonStr2 = '[{"name":"Curry"},{"name":"Thompson"}]';
List list = json.decode(jsonStr2);
// 輸出列表第一個對象的"name"屬性
print(list[0]["name"]);
}
解析json串的方法很簡單,直接調(diào)用json.decode()即可,但是由于json.decode()方法返回類型為dynamic,因此無法進行類型的檢查,編譯時不會報錯,容易使程序發(fā)生錯誤。采取的做法是像原生開發(fā)一樣,新建一個model實體類,將json轉(zhuǎn)為實體類對象。生成實體類的方法有以下兩種:
方法一.手寫實體類
一個簡單的實體類實例如下
class User{
final String name;
final String email;
User(this.name,this.email);
// 命名構(gòu)造函數(shù)
User.fromJson(Map<String, dynamic> json)
: name = json['name'],
email = json['email'];
Map<String,dynamic> toJson() =>{
'name':name,
'email':email
};
}
實體類中需要添加兩個方法:User.fromJson和toJson,其中,User.fromJson是一個命名構(gòu)造函數(shù),通過傳入的map構(gòu)造出實體類對象;toJson()方法用于將實體類對象序列化為json字符串。
使用方法如下:
import 'dart:convert';
// 這里需要替換為實體類所在路徑
import 'package:json_parse_test/user.dart';
void main() {
// 解析對象
String jsonStr1 = '{"name":"Curry","email":"SC@GSW.com"}';
Map<String, dynamic> map = json.decode(jsonStr1);
User user = User.fromJson(map);
print(user.name);
// 解析列表
String jsonStr2 = '[{"name":"Curry"},{"name":"Thompson"}]';
List list= json.decode(jsonStr2);
// 將列表中的第一個對象轉(zhuǎn)換成User對象
print(User.fromJson(list[0]).name);
// 將對象序列化為json串
// json.encode()會自動調(diào)用實體類中的toJson()
String jsonText = json.encode(user);
print(jsonText);
}
這樣就完成了將json轉(zhuǎn)化成實體對象,步驟很簡單,但是還有一個問題是,真的每個實體類都要我們自己去手寫嗎,有沒有類似GsonFormat這種一鍵生成實體類的插件呢。當然是有的,之前從鴻洋大神推薦的Flutter學(xué)習(xí)資源中偶然發(fā)現(xiàn)了一個神奇的網(wǎng)站:
https://javiercbk.github.io/json_to_dart/

可以直接通過json生成實體類代碼,仿佛是發(fā)現(xiàn)了新大陸,不得不佩服開發(fā)出這些快捷工具的大神們,為后面學(xué)習(xí)的人鋪平了道路。網(wǎng)站的操作很簡單,一看就會。
最近偶然發(fā)現(xiàn)Android Studio也有了相關(guān)插件,我使用的是FlutterJsonBeanFactory,安裝過程我就不說了,裝好在目錄下右鍵依次選擇New、dart bean class File from JSON,之后會彈出一個窗口,填入json字符串和實體類名稱,就可以像GsonFormat那樣自動生成dart實體類文件啦。


需要注意的是默認情況生成的文件名和類名會加上entity后綴,可以從設(shè)置中進行配置,依次點擊File→Settings,從Tools下選擇FlutterJsonBeanFactory,修改model suffix即可。

方法二.通過json_serializable自動生成
json_serializable是Google官方推薦的一個json序列化庫。使用之前需要在pubspec.yaml文件中添加依賴項:
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
添加之后在項目根目錄文件夾中運行flutter packages get (或者在編輯器中點擊 “Packages Get”) 以在項目中使用這些新的依賴項。
使用時也是需要新建一個實體類
import 'package:json_annotation/json_annotation.dart';
// user.g.dart通過命令自動生成
part 'user_model.g.dart';
@JsonSerializable()
class User {
// 自定義json字段名對應(yīng)的屬性名,不是必須的
@JsonKey(name: 'userName')
String name;
String email;
User(this.name, this.email);
factory User.fromJson(Map<String, dynamic> json) =>
_$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
需要我們手寫的就這些,這時代碼會報錯,我們需要運行命令來自動生成缺少的文件,有兩種生成的方法:
- 一次性生成
在項目根目錄文件夾下運行
flutter packages pub run build_runner build
- 持續(xù)生成
在項目根目錄文件夾下運行
flutter packages pub run build_runner watch
兩者的區(qū)別是,一次性生成只執(zhí)行一次,后面每新建一個實體類都需要重新運行該命令;持續(xù)生成會在我們編寫代碼的過程中根據(jù)需要自動生成缺少的文件。
之后解析json的方法和方法一相同
import 'dart:convert';
// 這里需要替換為實體類所在路徑
import 'package:json_parse_test/user.dart';
void main() {
// 解析對象
String jsonStr = '{"name":"Curry","email":"SC@GSW.com"}';
Map<String, dynamic> map = json.decode(jsonStr);
User user = User.fromJson(map);
print(user.name);
}
這里關(guān)于實體類的生成我找到了做人要簡單這位大神寫的網(wǎng)頁工具,同樣是可以很方便地將json轉(zhuǎn)換成實體類代碼。

生成代碼后點擊下載將實體類dart文件下載到本地,之后放到項目中,在項目根目錄運行上面提到的生成文件命令即可。
當然也可以通過自已定義模板編寫腳本來生成實體類文件,具體做法可以參考《Flutter實戰(zhàn)》。
總結(jié)
Flutter中json的解析分為兩步:
1.通過json.decode()將json串轉(zhuǎn)換成dart對象(Map或List)
2.編寫實體類(兩種方法,手寫或自動生成),利用上一步得到的dart對象構(gòu)造出實體類對象
其實在實際的開發(fā)中,有可能并不需要第一步,這和服務(wù)端返回給我們的數(shù)據(jù)格式有關(guān)(響應(yīng)頭中的Content-Type),如果服務(wù)端直接返回給我們json格式(對應(yīng)Content-Type:application/json),我們可以直接從返回的響應(yīng)中獲取到dart對象,省去了第一步,直接轉(zhuǎn)化成實體類對象即可;如果服務(wù)端返回給我們的是純文本格式(對應(yīng)Content-Type:text/html,這里不一定是html,也有可能是xml等其他格式),則需要先將響應(yīng)的字符串轉(zhuǎn)換成dart對象。
參考資料
《Flutter實戰(zhàn)》Json轉(zhuǎn)Model
flutter json解析相關(guān) for json_serializable