我们都知道,在使用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的数据的情况下,还是有一些提升的手段的:
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理解不够深刻,欢迎有更好的办法的大佬对我不吝赐教