對json用Gson進行自定義解析
阿新 • • 發佈:2022-05-21
一:面對的資料
{ "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
二:定義資料結構
// 介面的標準格式
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()