对json用Gson进行自定义解析
一:面对的数据
{ "code": 0, "key": "common_success", "msg": "成功", "data": { "ver": "1", "items": [ { "name": "glt" }, { "data": "229e3b64920042109cf294f3773b6837", "name": "rtck" },
{
"data": 1,
"name": "tuio"
},
{ "data": { "sizeLimit": 30, "interval": 172800000, "url": "https://dldir1.qq.com/weixin/Windows/WeChatSetup.exe" }, "name": "anchor_netspeedcheck" }, { "data": { "ver": "1.0.0", "pkgname": "安卓-AsChat", "always_show": "false", "force": "false", "upgradeContent": "" }, "name": "upgrade" } ] } }
可以看到,后端给回来的Json数据是不规则的,在items这个数组里,元素的name字段是string,但data字段有的是string,有的是int,有的是类。这个时候,给Retrofit配置的Gson转换器已经不适用了。
二:定义数据结构
// 接口的标准格式
data class Response<T>(
val code: Int,
val data: T?,
val key: String,
val msg: String
)
// Retrofit返回的数据结构
@GET(ApiUrls.GetAppConfig)
suspend fun getAppConfig(@Query("ver") ver: Int): Response<ConfigList>
data class ConfigList(
var items: List<ConfigItemBase>,
val ver: String
)
// 父类 open class ConfigItemBase() { var name: String = "" } //各个子类 class ConfigItemStrStr: ConfigItemBase() { var data: String = "" } class ConfigItemStrInt: ConfigItemBase() { var data: Int = 0 } class ConfigItemStrSpeedObject: ConfigItemBase() { var data: SpeedCheckObject = SpeedCheckObject(0,0,"") } class ConfigItemStrUpgradeObject: ConfigItemBase() { var data: UpgradeObject = UpgradeObject("", "", "", "", "") } data class SpeedCheckObject( val interval: Int, val sizeLimit: Int, val url: String ) data class UpgradeObject( val always_show: String, val force: String, val pkgname: String, val upgradeContent: String, val ver: String )
总之,就是把数据结构定义好。因为有不同类型的数据,但他们又有共同的字段,所以我就定义了一个父类,(如果没有相同点的话就用共同的父类Any).
三:具体的解析过程
class AppConfigDeserializer: JsonDeserializer<ConfigList> { override fun deserialize( json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext? ): ConfigList { try { val gson = Gson() // 总的json对象 val jsonObj = json!!.asJsonObject // 先建一个空列表 val itemList = mutableListOf<ConfigItemBase>() // 取出json中的列表 val jsonArray = jsonObj["items"].asJsonArray // 循环 for (item in jsonArray) { try { val tempObj = item.asJsonObject if (tempObj["name"].asString == "translate_type") { itemList.add(gson.fromJson(item, ConfigItemStrInt::class.java)) }else if (tempObj["name"].asString == "anchor_netspeedcheck") { itemList.add(gson.fromJson(item, ConfigItemStrSpeedObject::class.java)) }else if (tempObj["name"].asString == "upgrade") { itemList.add(gson.fromJson(item, ConfigItemStrUpgradeObject::class.java)) }else { itemList.add(gson.fromJson(item, ConfigItemStrStr::class.java)) } }catch (e: Exception) { // NOTE 有item解析错误,说明后台加了新的实体,直接跳过解析错误的 LogUtil.e(item.toString()) } } return ConfigList(itemList, jsonObj["ver"].asString) } catch (e: Exception) { // 能来到这里的报错,说明最外层data为”“ return ConfigList(emptyList(), "0") } } }
重点是认识json的几个方法,如果熟悉这几个方法的话就很容易了。
- jsonObj["items"].asJsonArray,因为我们的items字段是一个列表,所以我们把它当一个数组对待。
- 对于每一个元素,用asJsonObject把它转成一个对象。
- 用["xxx"]的方式取出字段的值。
- 用gson对判断出来的类型进行一个解析放进数组里。
四:配置Retrofit
return Retrofit.Builder() .baseUrl(ApiUrls.BASE_URL) .client(client) .addConverterFactory( GsonConverterFactory.create( GsonBuilder() .registerTypeAdapter(ConfigList::class.java, AppConfigDeserializer())// 要自定义解析的类,自定义的解析器 .create() ) ) .build()
本文作者:ou尼酱~~~
本文链接:https://www.cnblogs.com/--here--gold--you--want/p/16295383.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步