Flutter - JSON解析與復(fù)雜模型轉(zhuǎn)換實(shí)用技巧

JSON 序列化方式

項(xiàng)目開(kāi)發(fā)中使用手動(dòng)序列化和 json_to_dart 在線轉(zhuǎn)換工具更靈活高效

如何序列化

將 JSON 格式的字符串轉(zhuǎn)為 Dart 對(duì)象,這個(gè)可以通過(guò) dart:convert 中內(nèi)置的 JSON 解碼器 json.decode() 來(lái)實(shí)現(xiàn)晦攒,該方法可以根據(jù) JSON 字符串具體內(nèi)容將其轉(zhuǎn)為 List 或 Map民珍,這樣我們就可以通過(guò)他們來(lái)查找所需的值斯辰,如:

//一個(gè)JSON格式的用戶列表字符串
String jsonStr = '[{"name":"Jack"},{"name":"Rose"}]';
//將JSON字符串轉(zhuǎn)為Dart對(duì)象(此處是List)
List items = json.decode(jsonStr);
print('${items[0]['name']}!');
print('${items[1]['name']}.');  
String jsonStr = '{"name": "John Smith","email": "john@example.com"}';
Map<String, dynamic> map = json.decode(jsonStr);
print('Howdy, ${map['name']}!');
print('We sent the verification link to ${map['email']}.');

通過(guò) json.decode() 將 JSON 字符串轉(zhuǎn)為 List/Map 的方法比較簡(jiǎn)單替蔬,它沒(méi)有外部依賴或其它的設(shè)置,對(duì)于小項(xiàng)目很方便馁龟。但在 List/Map 中存放那些字段在使用時(shí)很不方便也容易出錯(cuò)怨酝,這時(shí)將 List/Map 轉(zhuǎn)成 Model 即可啦扬。

具體做法就是,通過(guò)預(yù)定義一些與 Json 結(jié)構(gòu)對(duì)應(yīng)的 Model 類凫碌,然后在請(qǐng)求到數(shù)據(jù)后再動(dòng)態(tài)根據(jù)數(shù)據(jù)創(chuàng)建出 Model 類的實(shí)例扑毡。這樣一來(lái),在開(kāi)發(fā)階段我們使用的是 Model 類的實(shí)例盛险,而不再是 Map/List瞄摊,這樣訪問(wèn)內(nèi)部屬性時(shí)就不會(huì)發(fā)生拼寫(xiě)錯(cuò)誤。

例如苦掘,我們可以通過(guò)引入一個(gè)簡(jiǎn)單的模型類(Model class)來(lái)解決前面提到的問(wèn)題换帜,我們稱之為 User。在 User 類內(nèi)部鹤啡,我們有:

  • 一個(gè) User.fromJson 構(gòu)造函數(shù), 用于從一個(gè) map 構(gòu)造出一個(gè)User 實(shí)例 map structure
  • 一個(gè) toJson 方法, 將 User 實(shí)例轉(zhuǎn)化為一個(gè) map.
class User {
  String name;
  String email;

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

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

  Map<String, dynamic> toJson() {
    Map<String, dynamic> data = new Map();
    data['name'] = this.name;
    data['email'] = this.email;
    return data;
  }
}

采用這種新方法惯驼,我們可以非常容易地反序列化 user.

String jsonStr = '{"name": "John Smith","email": "john@example.com"}';
Map userMap = json.decode(jsonStr);
var user = new User.fromJson(userMap);

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

User 類字段修改成 final

class User {
  final String name;
  final String email;

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

  factory User.fromJson(Map<String, dynamic> json) {
    return User(name: json['name'], email: json['email']);
  }

  Map<String, dynamic> toJson() {
    Map<String, dynamic> data = new Map();
    data['name'] = this.name;
    data['email'] = this.email;
    return data;
  }
}

復(fù)雜 JSON 解析

解析對(duì)象中的數(shù)組
{
  "url": "xxx",
  "tabs": [
     {
        "labelName":"推薦",
        "channelCode":"photo_global"
     },
     {
        "labelName":"拍照",
        "channelCode":"tab_photo"
     }
  ]
}

解析:

class TravelModel {
  String url;
  List<TravelTab> tabs;

  TravelModel(this.url, this.tabs);

  TravelModel.fromJson(Map<String, dynamic> json) {
    url = json['url'];
    if (json['tabs'] != null) {
      tabs = new List<TravelTab>();
      json['tabs'].forEach((i) {
        tabs.add(new TravelTab.fromJson(i));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['url'] = this.url;
    if (this.tabs != null) {
      data['tabs'] = this.tabs.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class TravelTab {
  String labelName;
  String channelCode;

  TravelTab({this.labelName, this.channelCode});

  TravelTab.fromJson(Map<String, dynamic> json) {
    labelName = json['labelName'];
    channelCode = json['channelCode'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['labelName'] = this.labelName;
    data['channelCode'] = this.channelCode;
    return data;
  }
}

修改為 final

class TravelModel {
  final String url;
  final List<TravelTab> tabs;

  TravelModel({this.url, this.tabs});

  factory TravelModel.fromJson(Map<String, dynamic> json) {
    var tabsJson = json['tabs'] as List;
    List<TravelTab> tabs = tabsJson.map((i) => TravelTab.fromJson(i)).toList();
    return TravelModel(url: json['url'], tabs: tabs);
  }
  
   Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['url'] = this.url;
    if (this.tabs != null) {
      data['tabs'] = this.tabs.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class TravelTab {
  final String labelName;
  final String channelCode;

  TravelTab({this.labelName, this.channelCode});

  factory TravelTab.fromJson(Map<String, dynamic> json) {
    return TravelTab(
        labelName: json['labelName'], channelCode: json['channelCode']);
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['labelName'] = this.labelName;
    data['channelCode'] = this.channelCode;
    return data;
  }
}

在項(xiàng)目中設(shè)置 json_serializable

在項(xiàng)目中設(shè)置json_serializable---- json_serializable設(shè)置方式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子祟牲,更是在濱河造成了極大的恐慌隙畜,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件说贝,死亡現(xiàn)場(chǎng)離奇詭異议惰,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)乡恕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門言询,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人傲宜,你說(shuō)我怎么就攤上這事运杭。” “怎么了函卒?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵辆憔,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我谆趾,道長(zhǎng),這世上最難降的妖魔是什么叛本? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任沪蓬,我火速辦了婚禮,結(jié)果婚禮上来候,老公的妹妹穿的比我還像新娘跷叉。我一直安慰自己,他們只是感情好营搅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布云挟。 她就那樣靜靜地躺著,像睡著了一般转质。 火紅的嫁衣襯著肌膚如雪园欣。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,198評(píng)論 1 299
  • 那天休蟹,我揣著相機(jī)與錄音沸枯,去河邊找鬼。 笑死赂弓,一個(gè)胖子當(dāng)著我的面吹牛绑榴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播盈魁,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼翔怎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起赤套,我...
    開(kāi)封第一講書(shū)人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤飘痛,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后于毙,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體敦冬,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年唯沮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了脖旱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡介蛉,死狀恐怖萌庆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情币旧,我是刑警寧澤践险,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站吹菱,受9級(jí)特大地震影響巍虫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鳍刷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一占遥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧输瓜,春花似錦瓦胎、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至北戏,卻和暖如春负芋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嗜愈。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工示罗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人芝硬。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓蚜点,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親拌阴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子绍绘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

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