Flutter中的Json解析-原生方式
在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 ); }
更多的複雜結構參考官網或者根據上面的步驟推導;