使用改造对 JSON 数据建模的更有效方法 - Kotlin

More efficient way to model JSON data using retrofit - Kotlin

我要使用的数据具有以下结构:

{
    "1": {
        "id": 1,
        "name": "Bulbasaur"
    },
    "2": {
        "id": 2,
        "name": "Ivysaur"
    },
    "3": {
        "id": 3,
        "name": "Venusaur"
    }
}

注: 标记每个对象的数字与 Pokémon 的 id 匹配,而不是 Pokémon 的数量

我的问题是,当我尝试为此创建数据 classes 时,它最终会为每个对象创建一个数据 class。没有一个数据 class 适合每个对象。我相信这是由于标记对象(神奇宝贝)的数字对于每个对象都是不同的。

有没有一种方法可以将此数据格式化为一个或两个数据 classes 而不是超过 800 个?

理想情况下,我希望数据的结构像这样,但在 运行 时它不起作用。

data class ReleasedPokemonModel(
    val id: Int,
    val name: String
)

问题是那里没有 JSON 数组。它实际上是一个 JSON 对象,每个 Pokemon 都列为 属性。我建议您事先将 JSON 重新格式化为如下所示:

[
    {
        "id": 1,
        "name": "Bulbasaur"
    },
    {
        "id": 2,
        "name": "Ivysaur"
    },
    {
        "id": 3,
        "name": "Venusaur"
    }
]

然后你可以这样建模:

data class ReleasedPokemonModel(
    val id: Int,
    val name: String
)

data class Response(
    val items: List<ReleasedPokemonModel>
)

And see here for discussion about reformatting the data before handing it to Retrofit.

你可以像下面这样使用Map来存储key

data class PokemonResponse(
    val pokemonMap:Map<String,ReleasedPokemonModel>
)

data class ReleasedPokemonModel(
    val id: Int,
    val name: String
)

在使用这种特殊情况将 Json 解析为 Object 时,您应该自己自定义 Json 反序列化器。

这里我使用Gson库将Json解析为Object.

首先,使用 Gson 创建自定义 Json 反序列化器。如下:

PokemonResponse.kt

data class PokemonResponse(
    val pokemonMap: List<StringReleasedPokemonModel>
)

data class ReleasedPokemonModel(
    val id: Int,
    val name: String
)

GsonHelper.kt

object GsonHelper {
    fun create(): Gson = GsonBuilder().apply {
        registerTypeAdapter(PokemonResponse::class.java, PokemonType())
        setLenient()
    }.create()

    private class PokemonType : JsonDeserializer<PokemonResponse> {
        override fun deserialize(
            json: JsonElement?,
            typeOfT: Type?,
            context: JsonDeserializationContext?
        ): PokemonResponse {
            val list = mutableListOf<ReleasedPokemonModel>()
            // Get your all key
            val keys = json?.asJsonObject?.keySet()
            keys?.forEach { key ->
                // Get your item with key
                val item = Gson().fromJson<ReleasedPokemonModel>(
                    json.asJsonObject[key],
                    object : TypeToken<ReleasedPokemonModel>() {}.type
                )
                list.add(item)
            }
            return PokemonResponse(list)
        }
    }
}

接下来我将创建一个 GsonConverterFactory 以便我可以 addConvertFactory 进行改造。

val gsonConverterFactory = GsonConverterFactory.create(GsonHelper.create())

现在我将添加改造。

val retrofit = Retrofit.Builder()
    // Custom your Retrofit
    .addConverterFactory(gsonConverterFactory) // Add GsonConverterFactoty
    .build()

最后在 ApiService 中,您的响应现在 return 类型 PokemonResponse

interface ApiService {
    @GET("your_link")
    suspend fun getGenres(): PokemonResponse
}