如何使用GSON库将指定JSON转换为Pokemon列表?适配Retrofit接口
解决Retrofit解析键值对JSON为Pokemon列表的问题
这个场景很常见——后端返回的是键值对结构的JSON,但我们的业务需要的是列表形式的Pokemon集合。下面给你三种可行的解决办法,按需选择:
方案1:修改接口返回类型,手动转换(最直观简单)
后端返回的JSON本质是一个Map<String, Pokemon>,我们先让Retrofit直接解析成Map,再提取值转成List即可:
- 调整Retrofit接口的返回类型:
@GET("/pokemon") fun getPokemon(): Call<Map<String, Pokemon>>
- 调用接口时转换为列表:
val call = apiService.getPokemon() call.enqueue(object : Callback<Map<String, Pokemon>> { override fun onResponse(call: Call<Map<String, Pokemon>>, response: Response<Map<String, Pokemon>>) { if (response.isSuccessful) { // 提取Map中的所有值,转成List val pokemonList = response.body()?.values?.toList() ?: emptyList() // 这里就拿到了你需要的[Pokemon@1, Pokemon@2, Pokemon@3] } } override fun onFailure(call: Call<Map<String, Pokemon>>, t: Throwable) { // 处理请求失败逻辑 } })
方案2:自定义Gson TypeAdapter,自动转换(一劳永逸)
如果你的项目中经常需要这种“键值对转列表”的解析,可以自定义Gson的适配器,让它自动完成转换,不用每次手动处理:
- 编写自定义TypeAdapter:
class PokemonListTypeAdapter : TypeAdapter<List<Pokemon>>() { override fun write(out: JsonWriter, value: List<Pokemon>?) { // 我们只需要解析JSON,不需要序列化列表,所以直接抛出不支持异常即可 throw UnsupportedOperationException("序列化列表为键值对JSON暂不支持") } override fun read(`in`: JsonReader): List<Pokemon> { val pokemonList = mutableListOf<Pokemon>() `in`.beginObject() // 遍历JSON对象的所有键值对,跳过键名,只解析值为Pokemon对象 while (`in`.hasNext()) { `in`.nextName() // 跳过Pikachu、Pichu这类键名 val pokemon = Gson().fromJson(`in`, Pokemon::class.java) pokemonList.add(pokemon) } `in`.endObject() return pokemonList } }
- 创建Retrofit实例时注册这个适配器:
// 配置Gson,注册自定义适配器 val customGson = GsonBuilder() .registerTypeAdapter( object : TypeToken<List<Pokemon>>() {}.type, PokemonListTypeAdapter() ) .create() // 初始化Retrofit val retrofit = Retrofit.Builder() .baseUrl("你的BaseUrl") .addConverterFactory(GsonConverterFactory.create(customGson)) .build()
- 保持原接口定义不变:
@GET("/pokemon") fun getPokemon(): Call<List<Pokemon>>
之后调用接口时,Gson会自动把后端的键值对JSON解析成你需要的List<Pokemon>。
方案3:手动解析ResponseBody(无侵入式)
如果不想修改Gson配置或接口返回类型,也可以直接获取原始的ResponseBody手动解析:
- 修改接口返回类型为
ResponseBody:
@GET("/pokemon") fun getPokemon(): Call<ResponseBody>
- 手动解析JSON字符串:
val call = apiService.getPokemon() call.enqueue(object : Callback<ResponseBody> { override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) { if (response.isSuccessful) { val jsonString = response.body()?.string() jsonString?.let { val gson = Gson() // 先解析成Map,再转成List val pokemonMap = gson.fromJson(it, object : TypeToken<Map<String, Pokemon>>() {}.type) val pokemonList = pokemonMap.values.toList() // 得到目标列表 } } } override fun onFailure(call: Call<ResponseBody>, t: Throwable) { // 处理失败逻辑 } })
内容的提问来源于stack exchange,提问作者diAz
相关产品推荐
相关产品推荐

