- JSON結(jié)構(gòu)#1:簡(jiǎn)單 map
- 訪問(wèn)對(duì)象
- JSON結(jié)構(gòu)#2:具有數(shù)組的簡(jiǎn)單結(jié)構(gòu)
- Json結(jié)構(gòu)#3:簡(jiǎn)單嵌套結(jié)構(gòu)
- JSON結(jié)構(gòu)#4:具有列表的嵌套結(jié)構(gòu)
- JSON結(jié)構(gòu)#5: List of maps
-
JSON結(jié)構(gòu)#6:復(fù)雜的嵌套結(jié)構(gòu)
趁著年假,今天在網(wǎng)上看到一篇不錯(cuò)的講解在Flutter中解析復(fù)雜的JSON的文章叫确,于是花了兩個(gè)小時(shí)跳芳,翻譯,研究竹勉,覺(jué)得對(duì)我收益挺大飞盆。分享給大家,歡迎大家點(diǎn)贊轉(zhuǎn)發(fā)。
我不得不承認(rèn)吓歇,在Flutter / Dart中使用JSON后孽水,我錯(cuò)過(guò)了Android的* gson* 世界。當(dāng)我開(kāi)始在Flutter中使用API時(shí)城看,JSON解析確實(shí)使我非常費(fèi)力女气。而且我敢肯定空免,這會(huì)讓很多初學(xué)者感到困惑苏揣。
我們將使用dart:convert
此博客的內(nèi)置庫(kù)设联。這是最基本的解析方法敦第,僅在從Flutter開(kāi)始或正在構(gòu)建小型項(xiàng)目時(shí)才建議使用秧饮。盡管如此阴颖,了解Flutter中JSON解析的基礎(chǔ)還是很重要的筐高。如果您擅長(zhǎng)于此也拜,或者需要處理較大的項(xiàng)目赃阀,請(qǐng)考慮使用json_serializable等代碼生成器庫(kù)霎肯。如果可能,我將在以后的文章中找到它們榛斯。
Fork this sample project. 它包含您可以嘗試的此博客的所有代碼姿现。
JSON結(jié)構(gòu)#1:簡(jiǎn)單 map
讓我們從student.json中的簡(jiǎn)單JSON結(jié)構(gòu)開(kāi)始
{
"id":"487349",
"name":"Pooja Bhaumik",
"score" : 1000
}
規(guī)則1: 確定結(jié)構(gòu)。Json字符串將具有一個(gè)Map(鍵-值對(duì))或一個(gè)Map列表肖抱。
規(guī)則2:從大括號(hào)開(kāi)始备典?這是一map.
以方括號(hào)開(kāi)頭?That’s a List of maps.**
student.json
顯然是map. ( E.g like, id
is a key, and 487349
is the value for id
)
讓我們?yōu)榇薺son結(jié)構(gòu)制作一個(gè)PODO(普通的舊式Dart對(duì)象意述?)文件提佣。您可以在示例項(xiàng)目的student_model.dart中找到此代碼。
class Student{
String studentId;
String studentName;
int studentScores;
Student({
this.studentId,
this.studentName,
this.studentScores
});}
完美的荤崇!
*是嗎 因?yàn)閖son映射與此PODO文件之間沒(méi)有映射拌屏。甚至實(shí)體名稱都不匹配。
*我知道我知道术荤。我們還沒(méi)有完成倚喂。我們必須完成將這些類成員映射到j(luò)son對(duì)象的工作。為此瓣戚,我們需要?jiǎng)?chuàng)建一個(gè)factory
方法端圈。根據(jù)Dart文檔,我們factory
在實(shí)現(xiàn)構(gòu)造器時(shí)使用了關(guān)鍵字子库,該構(gòu)造器并不總是創(chuàng)建其類的新實(shí)例舱权,而這正是我們現(xiàn)在所需要的。
factory Student.fromJson(Map<String, dynamic> parsedJson){
return Student(
studentId: parsedJson['id'],
studentName : parsedJson['name'],
studentScores : parsedJson ['score']
);
}
在這里仑嗅,我們正在創(chuàng)建一個(gè)工廠方法Student.fromJson
宴倍,該方法的目標(biāo)是簡(jiǎn)單地反序列化您的json张症。
我有點(diǎn)菜鳥,您能告訴我有關(guān)反序列化的信息嗎鸵贬?
當(dāng)然俗他。首先讓我們介紹一下序列化和反序列化。序列化只是意味著將數(shù)據(jù)(可能在對(duì)象中)寫入字符串阔逼,而反序列化則相反拯辙。它獲取原始數(shù)據(jù)并重建對(duì)象模型。在本文中颜价,我們主要將處理反序列化部分涯保。在第一部分中,我們將從中反序列化json字符串student.json
So our factory method could be called as our converter method.
還必須注意fromJson
方法中的參數(shù)周伦。這是一個(gè)Map<String, dynamic>
意思是它映射一個(gè)String
鍵和一個(gè)dynamic
值夕春。這正是我們需要確定結(jié)構(gòu)的原因。 If this json structure were a List of maps, 則此參數(shù)將有所不同
***但是為什么要?jiǎng)討B(tài)专挪?****
*讓我們先看看另一個(gè)json結(jié)構(gòu)來(lái)回答您的問(wèn)題
name
is a Map<String, String> ,majors
is a Map of String and List and subjects
is a Map of String and List
由于密鑰始終是 string
并且值可以是任何類型及志,因此我們將其保持dynamic
安全。
Check the full code for student_model.dart
here.
訪問(wèn)對(duì)象
讓我們來(lái)編寫student_services.dart
其中的代碼寨腔,該代碼可以調(diào)用Student.fromJson
并從Student
對(duì)象中檢索值
Snippet #1 : imports
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;
import 'dart:convert';
import 'package:flutter_json/student_model.dart';
最后的導(dǎo)入將是模型文件的名稱
**Snippet #2 : 加載Json Asset(可選)
Future<String> _loadAStudentAsset() async {
return await rootBundle.loadString('assets/student.json');
}
在這個(gè)特定的項(xiàng)目中速侈,我們的json文件位于assets文件夾中,因此我們必須以這種方式加載json迫卢。但是倚搬,如果您將json文件存儲(chǔ)在云中,則可以進(jìn)行網(wǎng)絡(luò)調(diào)用乾蛤。網(wǎng)絡(luò)調(diào)用不在本文討論范圍之內(nèi)每界。
Snippet #3 : 加載響應(yīng)
Future loadStudent() async {
String jsonString = await _loadAStudentAsset();
final jsonResponse = json.decode(jsonString);
Student student = new Student.fromJson(jsonResponse);
print(student.studentScores);
}
在此loadStudent()
方法中,
Line 1 : 加載原始json字符串家卖。from the assets.
Line 2 : 解碼我們得到的原始json字符串
Line 3 : 現(xiàn)在眨层,我們通過(guò)調(diào)用Student.fromJson
方法來(lái)反序列化解碼的json響應(yīng),以便我們現(xiàn)在可以使用Student
object訪問(wèn)實(shí)體
Line 4 : 就像我們?cè)谶@里所做的那樣上荡,where we printed studentScores
from Student
class.
檢查Flutter控制臺(tái)以查看所有打印值趴樱。(In Android Studio, its under Run tab)*
瞧!您只是進(jìn)行了第一個(gè)JSON解析(或沒(méi)有)酪捡。
注意:請(qǐng)記住這里的3個(gè)代碼段叁征,我們將使用它來(lái)進(jìn)行下一組json解析(僅更改文件名和方法名稱),在此我將不再重復(fù)代碼沛善。但是您仍然可以在示例項(xiàng)目中找到所有內(nèi)容航揉。
JSON結(jié)構(gòu)#2:具有數(shù)組的簡(jiǎn)單結(jié)構(gòu)
現(xiàn)在塞祈,我們征服了一種與上述結(jié)構(gòu)相似的json結(jié)構(gòu)金刁,但它可能不僅具有單個(gè)值帅涂,而且還可能have an array of values.
{
"city": "Mumbai",
"streets": [
"address1",
"address2"
]
}
So in this address.json, we have city
entity that has a simple String
value, but streets
is an array of String
.
據(jù)我所知,Dart沒(méi)有數(shù)組數(shù)據(jù)類型尤蛮,但是有 a List 所以這里streets
是一個(gè)List<String>
媳友。
現(xiàn)在我們必須檢查Rule#1和Rule#2。這絕對(duì)是一 map 因?yàn)樗曰ɡㄌ?hào)開(kāi)頭产捞。. streets
is still a List
though, 但我們稍后會(huì)擔(dān)心醇锚。
所以address_model.dart
最初看起來(lái)像這樣
class Address {
final String city;
final List<String> streets;
Address({
this.city,
this.streets
});
}
現(xiàn)在,由于這是一amap, 因此我們的Address.fromJson
方法將仍然具有一個(gè)Map<String, dynamic>
參數(shù)坯临。
factory Address.fromJson(Map<String, dynamic> parsedJson) {
return new Address(
city: parsedJson['city'],
streets: parsedJson['streets'],
);
}
現(xiàn)在焊唬,address_services.dart
通過(guò)添加我們上面提到的3個(gè)片段來(lái)構(gòu)建。必須記住要放置正確的文件名和方法名看靠。示例項(xiàng)目已經(jīng)*address_services.dart*
為您構(gòu)建赶促。
現(xiàn)在,當(dāng)您運(yùn)行此命令時(shí)挟炬,您將得到一個(gè)不錯(cuò)的小錯(cuò)誤鸥滨。:/
type 'List<dynamic>' is not a subtype of type 'List<String>'
我告訴你,這些錯(cuò)誤幾乎都發(fā)生在我使用Dart開(kāi)發(fā)的每個(gè)步驟中谤祖。而且您也將擁有它們婿滓。因此,讓我解釋一下這意味著什么粥喜。我們正在請(qǐng)求一個(gè)凸主,List<String>
但是卻收到一個(gè),List<dynamic>
因?yàn)槲覀兊膽?yīng)用程序尚無(wú)法識(shí)別類型额湘。
因此秕铛,我們必須將其明確轉(zhuǎn)換為 List<String>
var streetsFromJson = parsedJson['streets'];
List<String> streetsList = new List<String>.from(streetsFromJson);
在這里,首先我們將變量映射streetsFromJson
到streets
實(shí)體缩挑。streetsFromJson
還是一個(gè)List<dynamic>
〉剑現(xiàn)在,我們明確地創(chuàng)建一個(gè)新的List<String> streetsList
包含所有元素的streetsFromJson
供置。
在此處檢查更新的方法谨湘。現(xiàn)在注意return語(yǔ)句。
現(xiàn)在芥丧,您可以運(yùn)行此程序紧阔,*address_services.dart*
它將完美運(yùn)行。
Json結(jié)構(gòu)#3:簡(jiǎn)單嵌套結(jié)構(gòu)
現(xiàn)在续担,如果我們有一個(gè)來(lái)自shape.json的嵌套結(jié)構(gòu)擅耽,該怎么辦
{
"shape_name":"rectangle",
"property":{
"width":5.0,
"breadth":10.0
}
}
在這里,property
包含一個(gè)對(duì)象而不是基本的原始數(shù)據(jù)類型物遇。
那么PODO會(huì)是什么樣子乖仇?
好吧憾儒,讓我們分解一下。In our shape_model.dart
, let’s make a class for Property
first.
class Property{
double width;
double breadth;
Property({
this.width,
this.breadth
});
}
現(xiàn)在乃沙,我們?yōu)闃?gòu)建類Shape
起趾。我將兩個(gè)類都放在同一個(gè)Dart文件中。
class Shape{
String shapeName;
Property property;
Shape({
this.shapeName,
this.property
});
}
請(qǐng)注意警儒,第二個(gè)數(shù)據(jù)成員property
is basically an object of是我 們上一類的對(duì)象 Property
.
規(guī)則3:對(duì)于嵌套結(jié)構(gòu)训裆,請(qǐng)首先創(chuàng)建類和構(gòu)造函數(shù),然后從底層添加工廠方法
所謂底層蜀铲,是指首先征服*Property*
階級(jí)边琉,然后再上一層*Shape*
*。
By bottom level, we mean, first we conquer *Property*
class, and then we go one level above to the *Shape*
class. 這只是我的建議记劝,而不是Flutter規(guī)則艺骂。
factory Property.fromJson(Map<String, dynamic> json){
return Property(
width: json['width'],
breadth: json['breadth']
);
}
這是一 simple map.*
但是對(duì)于我們 factory method at Shape
class, 我們不能僅僅這樣做
factory Shape.fromJson(Map<String, dynamic> parsedJson){
return Shape(
shapeName: parsedJson['shape_name'],
property : parsedJson['property']
);
}
property : parsedJson['property']
首先,這將引發(fā)類型不匹配錯(cuò)誤-
type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Property'
And second, *hey we just *制作了一個(gè)不錯(cuò)的 little class for Property, 我看不到它在任何地方都有用隆夯。
Right.我們必須在此處映射我們的Property類钳恕。
factory Shape.fromJson(Map<String, dynamic> parsedJson){
return Shape(
shapeName: parsedJson['shape_name'],
property: Property.fromJson(parsedJson['property'])
);
}
因此,基本上蹄衷,我們Property.fromJson
從Property
類中調(diào)用該方法忧额,作為返回,we map it to the property
entity. Simple! Check out the code here.
Run this with your shape_services.dart
and you are good to go.
JSON結(jié)構(gòu)#4:具有列表的嵌套結(jié)構(gòu)
讓我們檢查一下product.json
{
"id":1,
"name":"ProductName",
"images":[
{
"id":11,
"imageName":"xCh-rhy"
},
{
"id":31,
"imageName":"fjs-eun"
}
]
}
好的愧口,現(xiàn)在我們?cè)絹?lái)越深入睦番。我在內(nèi)部某處看到對(duì)象列表。哇耍属。 Woah.*
是的托嚣,因此此結(jié)構(gòu)具有一個(gè)對(duì)象列表,但其本身仍是 a map. (請(qǐng)參閱規(guī)則1和規(guī)則2)『衿現(xiàn)在參考規(guī)則3示启,讓我們構(gòu)造我們的product_model.dart
。
所以我們創(chuàng)建了兩個(gè)新類Product
和Image
领舰。
Note: *Product*
will 將具有一個(gè)數(shù)據(jù)成員夫嗓,該成員是 List of *Image*
class Product {
final int id;
final String name;
final List<Image> images;
Product({this.id, this.name, this.images});
}
class Image {
final int imageId;
final String imageName;
Image({this.imageId, this.imageName});
}
The factory method for Image
will be非常簡(jiǎn)單和基本。
factory Image.fromJson(Map<String, dynamic> parsedJson){
return Image(
imageId:parsedJson['id'],
imageName:parsedJson['imageName']
);
}
Now for the factory method for Product
factory Product.fromJson(Map<String, dynamic> parsedJson){
return Product(
id: parsedJson['id'],
name: parsedJson['name'],
images: parsedJson['images']
);
}
這顯然會(huì)引發(fā)運(yùn)行時(shí)錯(cuò)誤
type 'List<dynamic>' is not a subtype of type 'List<Image>'
如果我們這樣做冲秽,
images: Image.fromJson(parsedJson['images'])
這也絕對(duì)是錯(cuò)誤的舍咖,它會(huì)立即引發(fā)錯(cuò)誤,因?yàn)槟鸁o(wú)法將Image
對(duì)象分配給List<Image>
因此锉桑,我們必須創(chuàng)建一個(gè)List<Image>
排霉,然后將其分配給images
var list = parsedJson['images'] as List;
print(list.runtimeType); //returns List<dynamic>List<Image> imagesList = list.map((i) => Image.fromJson(i)).toList();
list
這是一個(gè)List 。現(xiàn)在民轴,我們遍歷列表攻柠,每個(gè)對(duì)象映射list
到Image
調(diào)用Image.fromJson
球订,(and map each object in list
to Image
by calling Image.fromJson
)and then we把每個(gè)map object into 一個(gè)新的列表with toList()
and 存儲(chǔ)in List<Image> imagesList
. Find the full code here.
JSON結(jié)構(gòu)#5: List of maps
現(xiàn)在讓我們轉(zhuǎn)到photo.json
[
{
"albumId": 1,
"id": 1,
"title": "accusamus beatae ad facilis cum similique qui sunt",
"url": "http://placehold.it/600/92c952",
"thumbnailUrl": "http://placehold.it/150/92c952"
},
{
"albumId": 1,
"id": 2,
"title": "reprehenderit est deserunt velit ipsam",
"url": "http://placehold.it/600/771796",
"thumbnailUrl": "http://placehold.it/150/771796"
},
{
"albumId": 1,
"id": 3,
"title": "officia porro iure quia iusto qui ipsa ut modi",
"url": "http://placehold.it/600/24f355",
"thumbnailUrl": "http://placehold.it/150/24f355"
}
]
哦,哦辙诞。規(guī)則1和規(guī)則2告訴我這不可能是 a map 因?yàn)閖son字符串以方括號(hào)開(kāi)頭這是對(duì)象列表嗎辙售?是的 The object being here is Photo
(或任何您想調(diào)用的對(duì)象).
class Photo{
final String id;
final String title;
final String url;
Photo({
this.id,
this.url,
this.title
}) ;
factory Photo.fromJson(Map<String, dynamic> json){
return new Photo(
id: json['id'].toString(),
title: json['title'],
url: json['json'],
);
}
}
但是它的列表*Photo*
轻抱,這是否意味著您必須構(gòu)建一個(gè)包含的類*List<Photo>*
飞涂?
是的,我建議祈搜。
class PhotosList {
final List<Photo> photos;
PhotosList({
this.photos,
});
}
另請(qǐng)注意较店,此json字符串是List of maps. 。因此容燕,在我們的工廠方法中梁呈,我們沒(méi)有Map<String, dynamic>
參數(shù),因?yàn)樗且粋€(gè)列表蘸秘。這就是為什么首先確定結(jié)構(gòu)很重要的原因官卡。因此,我們的新參數(shù)將為List<dynamic>
醋虏。
factory PhotosList.fromJson(List<dynamic> parsedJson) {
List<Photo> photos = new List<Photo>();
return new PhotosList(
photos: photos,
);
}
這會(huì)引發(fā)錯(cuò)誤
Invalid value: Valid value range is empty: 0
嘿寻咒,因?yàn)槲覀冇肋h(yuǎn)無(wú)法使用該Photo.fromJson
方法。
如果在列表初始化后添加此行代碼怎么辦颈嚼?
photos = parsedJson.map((i)=>Photo.fromJson(i)).toList();
與之前的概念相同毛秘,我們不必將其映射到j(luò)son字符串中的任何鍵,因?yàn)樗橇斜碜杩危皇怯成浣行ode here.
JSON結(jié)構(gòu)#6:復(fù)雜的嵌套結(jié)構(gòu)
Here is page.json.
我將要求您解決此問(wèn)題。它已經(jīng)包含在示例項(xiàng)目中限煞。您只需要為此構(gòu)建模型和服務(wù)文件抹恳。但是在給您提示之前,我不會(huì)總結(jié)(如果需要署驻,則需要任何提示)适秩。
照常應(yīng)用規(guī)則1和規(guī)則2。首先確定結(jié)構(gòu)硕舆。這是一 a map. 因此秽荞,從1-5開(kāi)始的所有json結(jié)構(gòu)都會(huì)有所幫助。
規(guī)則3要求您首先創(chuàng)建類和構(gòu)造函數(shù)抚官,然后從最底層添加工廠方法扬跋。Just another tip. Also add the classes from the deep/bottom level. For e.g, for this json structure, make the class for Image
first, then Data
and Author
and then the main class Page
. 并按相同順序添加工廠方法。
對(duì)于類Image
凌节,Data
請(qǐng)參考Json結(jié)構(gòu)#4钦听。
有關(guān)類洒试,Author
請(qǐng)參閱Json結(jié)構(gòu)#3
初學(xué)者提示:在嘗試任何新資產(chǎn)時(shí),請(qǐng)記住在pubspec.yaml文件中進(jìn)行聲明朴上。
這篇Fluttery文章就是這樣垒棋。本文可能不是那里最好的JSON解析文章,(因?yàn)槲疫€在學(xué)習(xí)很多東西)痪宰,但我希望它能幫助您入門叼架。
如果您學(xué)到了一兩件事,請(qǐng)拍拍手??盡可能多地表示支持衣撬!這激勵(lì)著我寫更多的東西乖订。
此,從1-5開(kāi)始的所有json結(jié)構(gòu)都會(huì)有所幫助具练。
規(guī)則3要求您首先創(chuàng)建類和構(gòu)造函數(shù)乍构,然后從最底層添加工廠方法。Just another tip. Also add the classes from the deep/bottom level. For e.g, for this json structure, make the class for Image
first, then Data
and Author
and then the main class Page
. 并按相同順序添加工廠方法扛点。
對(duì)于類Image
哥遮,Data
請(qǐng)參考Json結(jié)構(gòu)#4。
有關(guān)類陵究,Author
請(qǐng)參閱Json結(jié)構(gòu)#3
初學(xué)者提示:在嘗試任何新資產(chǎn)時(shí)眠饮,請(qǐng)記住在pubspec.yaml文件中進(jìn)行聲明。
這篇Fluttery文章就是這樣畔乙。本文可能不是那里最好的JSON解析文章君仆,(因?yàn)槲疫€在學(xué)習(xí)很多東西),但我希望它能幫助您入門牲距。
如果您學(xué)到了一兩件事返咱,請(qǐng)拍拍手??盡可能多地表示支持!這激勵(lì)著我寫更多的東西牍鞠。