Flutter中的Json解析-原生方式

96
丿北纬91度灬
0.9 2019.04.19 09:17 字数 1139

在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
    );
}

更多的复杂结构参考官网或者根据上面的步骤推导;

Android笔记
Web note ad 1