对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的几个方法,如果熟悉这几个方法的话就很容易了。

  1. jsonObj["items"].asJsonArray,因为我们的items字段是一个列表,所以我们把它当一个数组对待。
  2. 对于每一个元素,用asJsonObject把它转成一个对象。
  3. 用["xxx"]的方式取出字段的值。
  4. 用gson对判断出来的类型进行一个解析放进数组里。

四:配置Retrofit

return Retrofit.Builder()
            .baseUrl(ApiUrls.BASE_URL)
            .client(client)
            .addConverterFactory(
                GsonConverterFactory.create(
                    GsonBuilder()
                        .registerTypeAdapter(ConfigList::class.java, AppConfigDeserializer())// 要自定义解析的类,自定义的解析器
                        .create()
                )
            )
            .build()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值