在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
);
}
更多的复杂结构参考官网或者根据上面的步骤推导;