使用改造对 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
}
我要使用的数据具有以下结构:
{
"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
}