Flutter JSON和序列化

在 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_serializablebuilt_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_runnerjson_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ì)有問題悉盆,需要自己斟酌)

實(shí)例

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ì)是一種更好的方式村刨。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末告抄,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嵌牺,更是在濱河造成了極大的恐慌打洼,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逆粹,死亡現(xiàn)場離奇詭異募疮,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)僻弹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門阿浓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蹋绽,你說我怎么就攤上這事芭毙。” “怎么了卸耘?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵退敦,是天一觀的道長。 經(jīng)常有香客問我蚣抗,道長侈百,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮设哗,結(jié)果婚禮上唱捣,老公的妹妹穿的比我還像新娘。我一直安慰自己网梢,他們只是感情好震缭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著战虏,像睡著了一般拣宰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烦感,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天巡社,我揣著相機(jī)與錄音,去河邊找鬼手趣。 笑死晌该,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绿渣。 我是一名探鬼主播朝群,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼中符!你這毒婦竟也來了姜胖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤淀散,失蹤者是張志新(化名)和其女友劉穎右莱,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體档插,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡慢蜓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了阀捅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胀瞪。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖饲鄙,靈堂內(nèi)的尸體忽然破棺而出凄诞,到底是詐尸還是另有隱情,我是刑警寧澤忍级,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布帆谍,位于F島的核電站,受9級(jí)特大地震影響轴咱,放射性物質(zhì)發(fā)生泄漏汛蝙。R本人自食惡果不足惜烈涮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望窖剑。 院中可真熱鬧坚洽,春花似錦、人聲如沸西土。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽需了。三九已至跳昼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間肋乍,已是汗流浹背鹅颊。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留墓造,地道東北人堪伍。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像滔岳,于是被迫代替她去往敵國和親杠娱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挽牢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 前言 Google推出flutter這樣一個(gè)新的高性能跨平臺(tái)(Android谱煤,ios)快速開發(fā)框架之后,被業(yè)界許多...
    Vadaski閱讀 32,040評(píng)論 15 42
  • 很難想象一個(gè)移動(dòng)應(yīng)用程序不需要與Web服務(wù)器通信或在某些時(shí)候容易存儲(chǔ)結(jié)構(gòu)化數(shù)據(jù)禽拔。制作網(wǎng)絡(luò)連接的應(yīng)用程序時(shí)刘离,遲早需要...
    共田君閱讀 13,460評(píng)論 1 5
  • 參考來源:https://flutterchina.club/json/#%E4%BD%BF%E7%94%A8js...
    _白羊閱讀 837評(píng)論 0 0
  • 當(dāng)年輪轉(zhuǎn)至人的耄耋之年 有誰能抵擋得住歲月侵蝕 當(dāng)往日的笑臉被哀愁侵占 有誰能忍受寂寞孤獨(dú)終老 想要好好的疼愛我的...
    偏愛風(fēng)流閱讀 330評(píng)論 0 3
  • 最近硫惕,D&G辱華事件鬧得沸沸揚(yáng)揚(yáng),他們大張旗鼓來中國掙錢野来,又極其傲慢無禮地傷害中國人的感情恼除,其創(chuàng)始人與設(shè)計(jì)師一幕幕...
    漸行漸知閱讀 1,277評(píng)論 0 7