在Flutter中,沒有像Android原生中可以利用Gson等庫通過反射將服務端返回的Json字符串直接轉換爲對應的實體類,需要自己去解析Json,而在實際解析中也碰到一些問題,以此文記錄下來;
一、Flutter中Json串的結構
在Flutter中的Json串中,存在兩種結構Map以及List;
1、Map結構
最常見的最基礎的Json結構,以花括號“{ }”爲起始,此類結構稱爲Map結構;
eg:
{
"id" : "10086",
"name" : "Jack",
"phone" : "13311112222"
}
2、List結構
以“[ ]”方括號爲起始,在Android原生中爲數組,此類結構稱爲List結構;
eg:
[
"student1",
"student2",
"student3"
]
二、Json串當做參數的格式
針對於以上兩種結構,我們在解析Json串時,將Json串作爲參數傳入方法中去解析,那麼,兩種結構分佈對應怎樣的參數格式呢?
1、Map結構
在Flutter中,Map結構對應的參數格式爲“Map<String, dynamic> map”,通過Map結構,將String類型的key鍵映射爲dynamic類型的值,一般Json串的key值均爲String類型,所以在Map中將key值得格式定位String;但後面的Value值類型並不確定,可以是String類型,也可以是Int類型,也可以是自定義實體類型,所以用動態的dynamic;
2、List結構
在Flutter中沒有數組類型,但是有List,對應的參數格式爲“List<dynamic> list”,通過方括號引起來的結構爲一個List結構,裏面的對象類型也爲動態;
三、複雜Json的分類解析
1、純Map結構
{"id" : "10086", "name" : "Jack", "phone" : "13311112222" }
對於以上結構,我們構建其實體類,並創建其factory修飾的構造方法:
class Student {
String stuId;
String stuName;
String stuTel;
Student({this.stuId, this.stuName, this.stuTel});
factory Student.fromJson(Map<String, dynamic> json) {
return Student(
stuId : json["id"],
stuName : json["name"],
stuTel : json["phone"]
)
};
}
2、Map中包含List結構
{
"id" : "10086",
"students" : [
"student1",
"student2",
"student3"
]
}
實體類:
class A {
String id;
List<String> students;
A({this.id, this.students});
factory A.fromJson(Map<String, dynamic> json) {
return A(
id : json["id"],
students : json["students"]
)
};
}
以上結構爲Map中含有一個List結構,根據上面的方法,在獲取"students"這個key鍵的值時,我們會發現出現報錯“type 'List<dynamic>' is not a subtype of type 'List<String>'”,意思是我們要請求的是一個List<String>類型,但是我們獲取到的是一個List<dynamic>類型,程序無法識別類型,所以我們需要將這個類型手動去轉換一下;
var str = json["students"];
List<String> strList = new List<String>.from(str);
students: strList;
這裏是先將Json中的數組通過key值取出,存入到一個List<dynamic>類型的對象中,在顯示的創建List<String>,其中包含了剛剛拿到的數據,這裏就將dynamic類型改變爲String類型了;
3、Map結構的嵌套
{
"id" : "10086",
"student" : {
"name" : "Jack",
"phone" : "111111"
}
}
這裏Student的實體類同上,在對象A的實體類中,我們獲取Student對象時如果繼續使用 student : json["student"],則會出現報錯“type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Student'”,意思是無法直接將Map中的Map結構映射爲Student對象,所以這裏需要我們做一次轉換:
student : Student.fromJson(json["student"]);
先取出key鍵“student”對應的Map結構對象,此時可以將Map結構作爲參數傳入到Student類的fromJson方法中去解析轉爲Student對象;
4、Map中嵌套含有Map的List結構
{
"id" : "10086",
"student" : [
{
"name" : "Jack",
"phone" : "111111"
},
{
"name" : "Tom",
"phone" : "222222"
}
]
}
在這裏A對象中包含一個String的id,以及List<Student>類型的students,我們從上往下分析,直接在A類中獲取students時會取出是一個List<dynamic>類型,無法直接識別爲Student類型,所以還需要再次轉換:
var list = json["students"] as List;
List<Student> stus = list.map((i) => Student.fromJson(i)).toList;
這裏首先將key鍵“students”取出,通過打日誌“print(list.runtimeType)”會發現,這個list的類型爲List<dynamic>,與我們上面步驟分析的是一樣的,然後通過Student的fromJson方法,去遍歷整個list列表,把list中的每個對象都映射爲對應的Student對象;
對應的實體類:
class A {
String id;
List<Student> students;
A({this.id, this.students});
factory A.fromJson(Map<String, dynamic> json) {
var list = json["students"] as List;
List<Student> stus = list.map((i) => Student.fromJson(i)).toList();
return A(
id : json["id"],
students : stus
)
};
}
5、List中嵌套Map
[
{
"name" : "Jack",
"phone" : "111111"
},
{
"name" : "Tom",
"phone" : "222222"
}
]
在這裏Student對象依舊不變,但是這個整體是一個List<Student>對象,所以創建一個StudentList類對象,包含成員變量List<Student> students;但是在StudentList的fromJson方法中,參數不在是一個Map結構,而是要換成List結構,從數組中取出解析與第5步中相同:
factory StudentList.fromJson(List<dynamic> json) {
List<Student> stus = new List<Student>();
stus = json.map((i) => Student.fromJson(i)).toList();
return StudentList(
students : stus
);
}
更多的複雜結構參考官網或者根據上面的步驟推導;