Flutter中的Json解析-原生方式

作者: 若邪 | 来源:发表于2019-04-19 09:17 被阅读17次

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

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

    相关文章

      网友评论

        本文标题:Flutter中的Json解析-原生方式

        本文链接:https://www.haomeiwen.com/subject/lhbfgqtx.html