在 Flutter 中使用JSON 現(xiàn)在網(wǎng)上已經(jīng)有很多教程了卦方。此篇文章用于記錄和學(xué)習(xí)使用
參考 Flutter中文網(wǎng) - JSON
本文介紹了使用JSON的兩個(gè)常規(guī)策略:
- 手動(dòng)序列化和反序列化
- 通過代碼生成自動(dòng)序列化和反序列化
不同的項(xiàng)目具有不同的復(fù)雜度和場景逛艰。對(duì)于較小項(xiàng)目迎捺,使用代碼生成器可能會(huì)過度浙垫。對(duì)于具有多個(gè)JSON model的復(fù)雜應(yīng)用程序逞频,手動(dòng)序列化可能會(huì)比較重復(fù)吏砂,并會(huì)很容易出錯(cuò)崎弃。
小項(xiàng)目手動(dòng)序列化
手動(dòng)JSON序列化是指使使用dart:convert
中內(nèi)置的JSON解碼器。它將原始JSON字符串傳遞給JSON.decode() 方法疾瓮,然后在返回的Map<String, dynamic>
中查找所需的值脖镀。 它沒有外部依賴或其它的設(shè)置,對(duì)于小項(xiàng)目很方便。
當(dāng)您的項(xiàng)目變大時(shí)蜒灰,手動(dòng)編寫序列化邏輯可能變得難以管理且容易出錯(cuò)弦蹂。如果您在訪問未提供的JSON字段時(shí)輸入了一個(gè)錯(cuò)誤的字段,則您的代碼將會(huì)在運(yùn)行時(shí)會(huì)引發(fā)錯(cuò)誤强窖。
如果您的項(xiàng)目中JSON model并不多凸椿,并且希望快速測試一下,那么手動(dòng)序列化可能會(huì)很方便翅溺。有關(guān)手動(dòng)序列化的示例脑漫,請(qǐng)參考這里。
在大中型項(xiàng)目中使用代碼生成
代碼生成功能的JSON序列化是指通過外部庫為您自動(dòng)生成序列化模板咙崎。它需要一些初始設(shè)置优幸,并運(yùn)行一個(gè)文件觀察器,從您的model類生成代碼褪猛。 例如网杆,json_serializable和built_value就是這樣的庫。
這種方法適用于較大的項(xiàng)目伊滋。不需要手寫碳却,如果訪問JSON字段時(shí)拼寫錯(cuò)誤,這會(huì)在編譯時(shí)捕獲的笑旺。代碼生成的不利之處在于它涉及到一些初始設(shè)置昼浦。另外,生成的源文件可能會(huì)在項(xiàng)目導(dǎo)航器會(huì)顯得混亂燥撞。
使用代碼生成庫序列化JSON
這里主要介紹json_serializable座柱,大概步驟:
- 1 創(chuàng)建一個(gè)實(shí)體類
- 2 生成代碼:來讓build runner生成序列化代碼。運(yùn)行完成后文件夾下會(huì)出現(xiàn)一個(gè)xxx.g.dart文件物舒,這個(gè)文件就是生成后的文件色洞。
- 3 代理實(shí)現(xiàn):把fromJson和toJson操作代理給上面生成出來的類
json_serializable 借助了build_runner 和json_annotation 庫,來自動(dòng)生成fromJson/toJson函數(shù)內(nèi)容冠胯。(關(guān)于使用build_runner生成代碼的原理火诸,參考Flutter路由管理代碼這么長長長長長,阿里工程師怎么高效解決荠察?(實(shí)用))
1置蜀、添加項(xiàng)目依賴
dependencies:
flutter:
sdk: flutter
dio: ^1.0.14
json_annotation: ^2.0.0
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^1.1.3
json_serializable: ^2.0.1
2、創(chuàng)建實(shí)體類
JSON 格式
{
"list1": [
{
"rown": 1,
"ID": "cc72a5fb-659a-4941-b56d-1f0f734667b3",
"DAH": "201806060000669",
"XMMC": "晶澤·云璽(一期)",
"XMDZ": "南湖生態(tài)城B-05地塊",
"BSM": 8635,
"XSMC": "晶澤·云璽",
"XMJJ": 8300.05,
"QY": 510302,
"FTime": "2018-09-06",
"ZTS": 752,
"PIC": "../../images/xmimg/b72c1ecd-2f0b-46a0-b226-2440817e9f4d-20180607093242.jpg"
}
]
}
創(chuàng)建實(shí)體類
在這里可以借助工具 為了便利使用 json_serializable庫
將 JSON 拷進(jìn)去會(huì)自動(dòng)生成對(duì)應(yīng)實(shí)體類(據(jù)說復(fù)雜的格式可能會(huì)有問題悉盆,需要自己斟酌)
import 'package:json_annotation/json_annotation.dart';
part 'newhouse.g.dart';
@JsonSerializable()
class newhouse extends Object {
@JsonKey(name: 'list1')
List<List1> list1;
newhouse(this.list1,);
factory newhouse.fromJson(Map<String, dynamic> srcJson) => _$newhouseFromJson(srcJson);
Map<String, dynamic> toJson() => _$newhouseToJson(this);
}
@JsonSerializable()
class List1 extends Object {
@JsonKey(name: 'rown')
int rown;
@JsonKey(name: 'ID')
String iD;
@JsonKey(name: 'DAH')
String dAH;
@JsonKey(name: 'XMMC')
String xMMC;
@JsonKey(name: 'XMDZ')
String xMDZ;
@JsonKey(name: 'BSM')
int bSM;
@JsonKey(name: 'XSMC')
String xSMC;
@JsonKey(name: 'XMJJ')
double xMJJ;
@JsonKey(name: 'QY')
int qY;
@JsonKey(name: 'FTime')
String fTime;
@JsonKey(name: 'ZTS')
int zTS;
@JsonKey(name: 'PIC')
String pIC;
List1(this.rown,this.iD,this.dAH,this.xMMC,this.xMDZ,this.bSM,this.xSMC,this.xMJJ,this.qY,this.fTime,this.zTS,this.pIC,);
factory List1.fromJson(Map<String, dynamic> srcJson) => _$List1FromJson(srcJson);
Map<String, dynamic> toJson() => _$List1ToJson(this);
}
生成序列化模板
有兩種運(yùn)行代碼生成器的方法:
一次性生成
通過在我們的項(xiàng)目根目錄下運(yùn)行flutter packages pub run build_runner build盯荤,我們可以在需要時(shí)為我們的model生成json序列化代碼。 這觸發(fā)了一次性構(gòu)建焕盟,它通過我們的源文件秋秤,挑選相關(guān)的并為它們生成必要的序列化代碼。
雖然這非常方便,但如果我們不需要每次在model類中進(jìn)行更改時(shí)都要手動(dòng)運(yùn)行構(gòu)建命令的話會(huì)更好灼卢。
持續(xù)生成
使用watcher可以使我們的源代碼生成的過程更加方便绍哎。它會(huì)監(jiān)視我們項(xiàng)目中文件的變化,并在需要時(shí)自動(dòng)構(gòu)建必要的文件鞋真。我們可以通過flutter packages pub run
build_runner watch在項(xiàng)目根目錄下運(yùn)行來啟動(dòng)watcher崇堰。
只需啟動(dòng)一次觀察器,然后并讓它在后臺(tái)運(yùn)行涩咖,這是安全的海诲。
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'newhouse.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
newhouse _$newhouseFromJson(Map<String, dynamic> json) {
return newhouse((json['list1'] as List)
?.map((e) => e == null ? null : List1.fromJson(e as Map<String, dynamic>))
?.toList());
}
Map<String, dynamic> _$newhouseToJson(newhouse instance) =>
<String, dynamic>{'list1': instance.list1};
List1 _$List1FromJson(Map<String, dynamic> json) {
return List1(
json['rown'] as int,
json['ID'] as String,
json['DAH'] as String,
json['XMMC'] as String,
json['XMDZ'] as String,
json['BSM'] as int,
json['XSMC'] as String,
(json['XMJJ'] as num)?.toDouble(),
json['QY'] as int,
json['FTime'] as String,
json['ZTS'] as int,
json['PIC'] as String);
}
Map<String, dynamic> _$List1ToJson(List1 instance) => <String, dynamic>{
'rown': instance.rown,
'ID': instance.iD,
'DAH': instance.dAH,
'XMMC': instance.xMMC,
'XMDZ': instance.xMDZ,
'BSM': instance.bSM,
'XSMC': instance.xSMC,
'XMJJ': instance.xMJJ,
'QY': instance.qY,
'FTime': instance.fTime,
'ZTS': instance.zTS,
'PIC': instance.pIC
};
使用json_serializable模型
反序列化JSON字符串
Map houseMap = json.decode(json);
var house = new newhouse.fromJson(houseMap);
序列化
String json = JSON.encode(house );
最近咸魚團(tuán)隊(duì)也出了自己的文章如何在Flutter上優(yōu)雅地序列化一個(gè)對(duì)象(實(shí)用)
在文章中指出了 json_serializable 的不足之處:
- 使用起來有些繁瑣,多引入了一個(gè)類
- 很重要的一點(diǎn)是抠藕,大量的使用"as"會(huì)給性能和最終產(chǎn)物大小產(chǎn)生不小的影響饿肺。實(shí)際上閑魚內(nèi)部的《flutter編碼規(guī)范》中蒋困,是不建議使用"as"的盾似。(對(duì)包大小的影響可以參見三笠同學(xué)的文章,同時(shí)dart linter也對(duì)as的性能影響有所描述)
并引入了一種正經(jīng)的方式(哈哈):fish-serializable 詳細(xì)內(nèi)容可見文章
雪标。不過暫時(shí)還未開源零院,開源之后再做更新,可能會(huì)是一種更好的方式村刨。