kotlin中Gson解析Json时对于泛型的应用

Gosn解析Json

我们都知道,在使用Gson解析json时,可以通过如下代码将json转为实体类

val user = Gson().fromJson(json, UserBean::class.java)

实体类的定义

而在开发过程中,我们也可能遇到这样的Json数据

//一个登陆接口返回的数据
{
    "data": {
        "admin": false,
        "chapterTops": [],
        "coinCount": 10,
        "collectIds": [],
        "email": "",
        "icon": "",
        "id": 136927,
        "nickname": "17398900708",
        "password": "",
        "publicName": "17398900708",
        "token": "",
        "type": 0,
        "username": "17398900708"
    },
    "errorCode": 0,
    "errorMsg": ""
}
//一个登陆失败的Json
{
    "data": null,
    "errorCode": -1,
    "errorMsg": "账号密码不匹配!"
}

和这样的Json数据

//一个获取首页banner的Json
{
    "data": [
        {
            "desc": "我们支持订阅啦~",
            "id": 30,
            "imagePath": "https://www.wanandroid.com/blogimgs/42da12d8-de56-4439-b40c-eab66c227a4b.png",
            "isVisible": 1,
            "order": 2,
            "title": "我们支持订阅啦~",
            "type": 0,
            "url": "https://www.wanandroid.com/blog/show/3352"
        },
        {
            "desc": "",
            "id": 6,
            "imagePath": "https://www.wanandroid.com/blogimgs/62c1bd68-b5f3-4a3c-a649-7ca8c7dfabe6.png",
            "isVisible": 1,
            "order": 1,
            "title": "我们新增了一个常用导航Tab~",
            "type": 1,
            "url": "https://www.wanandroid.com/navi"
        },
        {
            "desc": "一起来做个App吧",
            "id": 10,
            "imagePath": "https://www.wanandroid.com/blogimgs/50c115c2-cf6c-4802-aa7b-a4334de444cd.png",
            "isVisible": 1,
            "order": 1,
            "title": "一起来做个App吧",
            "type": 1,
            "url": "https://www.wanandroid.com/blog/show/2"
        }
    ],
    "errorCode": 0,
    "errorMsg": ""
}

通过对比我们可以发现,这几个Json具有共性的特点——它们都由data,errorCode,errorMsg这三部分组成,那么他们的实体该怎么书写呢?

像这样的实体,我们可能大概率是,像这样构建两个BaseBean,一个UserBean和一个BannerBean:

//用户基类
data class UserBaseBean (
    @SerializedName("data") val data : UserBean,
    @SerializedName("errorCode") val errorCode : Int,
    @SerializedName("errorMsg") val errorMsg : String
)
//bannar基类
data class BannerBaseBean (
    @SerializedName("data") val data : BannerBean,
    @SerializedName("errorCode") val errorCode : Int,
    @SerializedName("errorMsg") val errorMsg : String
)
//用户类
data class UserBean(...)
//banner类
data class BannerBean(...)

其他写法

那么有没有其他简单的写法呢,我们可能自然而然的会想到泛型,有没有可能存在这样一种写法呢:

data class BaseBean<T>(
    @SerializedName("data") val data: T,
    @SerializedName("errorCode") val errorCode: Int,
    @SerializedName("errorMsg") val errorMsg: String
)

很遗憾,Gson并不支持你做这么高端的操作:

//这种写法会提示类的左边只能是类
val user = Gosn().fromJson(json,BaseBean<UserBean>::class.java)

只要求获取data数据

虽然我们不能采用上面的写法来偷懒 提升开发效率,但在只需要data的数据的情况下,还是有一些提升的手段的:

1.使用JSONObject和Gson配合使用:

//response是请求接口返回的响应
val result = response.body?.string()
val jsonObject = result?.let { JSONObject(it) }
//通过jsonObject,我们可以轻松拿到data的json数据,然后使用gson将其解析
val user = Gson().fromJson(jsonObject.getString("data"),UserBean::class.java)

2.利用kotlin,对gson进行扩展:

我们可以参考如下文章进行操作,大佬写的十分详细

Java/Kotlin: Gson() 泛型转换,解决泛型参数的类型擦除

3.对第二种的方法进行修改:

在看完上述方法后,我也结合1中的方法,对2进行了小幅度的修改,并把它封装放到了一个类中,如下:

class JsonToBean {
    inline fun <reified T> Gson.fromJson2(json: String, type: Type): T? {
        val jsonObject = JSONObject(json)
        val data = jsonObject.getString("data")
        return if (data.isEmpty()) {
            null
        } else {
            fromJson(data, type)
        }
    }

    inline fun <reified T> toBean(json: String): T? {
        val typeT = object : TypeToken<T>() {}.type
        return Gson().fromJson2<T>(json, typeT)
    }
}

使用的方法如下:

//result为上述response.body?.string()得到的值
val user = JsonToBean().toBean<UserBean>(result)

以上就是我对最近在开发中对json解析的一些新的感悟,当然由于我目前还在学习kotlin,对于kotlin理解不够深刻,欢迎有更好的办法的大佬对我不吝赐教

你可能感兴趣的:(安卓三分钟,json,kotlin,android)