改造 API 调用返回 null

Posted

技术标签:

【中文标题】改造 API 调用返回 null【英文标题】:Retrofit API call returns null 【发布时间】:2021-10-28 01:39:59 【问题描述】:

这是我尝试使用的 API/JSON 数据:https://pogoapi.net/api/v1/pokemon_names.json

问题是当我尝试解析 JSON 响应时,只返回 null。

型号:

data class ListOfReleasedPokemon(
    val releasedPokemon: List<PokemonResponse>
)

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

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

API 调用:

interface PogoApi 
    @GET("released_pokemon.json")
    suspend fun getReleasedPokemon(): ListOfReleasedPokemon

应用模块:

@Module
@InstallIn(SingletonComponent::class)
object AppModule 
    @Singleton
    @Provides
    fun providePokemonRepository(
        pogoApi: PogoApi
    ) = PokemonRepository(pogoApi)

    @Singleton
    @Provides
    fun providePogoApi(): PogoApi
//        val gson = GsonBuilder()
//            .registerTypeAdapter(ReleasedPokemonModel::class.java, JsonDeserializer())
//            .create()
        return Retrofit.Builder()
            .baseUrl(POGO_API_BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(PogoApi::class.java)
    

存储库(发现错误的位置):

@ActivityScoped
class PokemonRepository @Inject constructor(
    private val pogoApi: PogoApi
)
    suspend fun getReleasedPokemonList(): Resource<ListOfReleasedPokemon> 
        val response = try
            pogoApi.getReleasedPokemon()
//          Returns null
         catch(e: IOException)
            return Resource.Error("Please check your internet connection")
         catch(e: HttpException)
            return Resource.Error("Unexpected response")
        
        Log.d("MainActivity", "GetPokemonReleasedList Run with no errors")
        return Resource.Success(data = response)
    

任何帮助将不胜感激!

【问题讨论】:

我看到API中的列表项实际上不是列表,它是一个常规对象,里面包含其他对象。也许您应该查看您的数据响应。 如果它是这种格式,我有办法解析它吗? 【参考方案1】:

哦,我现在才注意到您似乎有一个与此 Json 解析器相关的问题。

好吧,在此评论中,我将详细指导您的这个项目。 因为上一个问题您只问了如何使用未定义的键解析 Json。

首先,创建一个自定义的 Json Deserializer。因为这里你的数据 api 有一个未定义的键。在这里,我将使用自定义 Json Deserializer 创建 1 个 gson。如下:

口袋妖怪反应

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)
        
    

接下来,将这个 Gson 提供给你的 Dagger 或 Hilt。

AppModule.kt

@Module
@InstallIn(SingletonComponent::class)
object AppModule 

    @Provides
    fun provideGson(): Gson = GsonHelper.create()
    ...

然后你修改你的addConverterFactory如下:

AppModule.kt

@Module
@InstallIn(SingletonComponent::class)
object AppModule 

    @Provides
    fun provideGson(): Gson = GsonHelper.create()

    @Singleton
    @Provides
    fun providePogoApi(gson: Gson): PogoApi = Retrofit.Builder()
        .baseUrl(POGO_API_BASE_URL)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build()
        .create(PogoApi::class.java)

PogoApi中,将getReleasedPokemon()的返回类型改为PokemonResponse

interface PogoApi 
    @GET("released_pokemon.json")
    suspend fun getReleasedPokemon(): PokemonResponse

最后,在您的存储库中,编辑以下内容:

PokemonRepository.kt

@ActivityScoped
class PokemonRepository @Inject constructor(
    private val pogoApi: PogoApi
)
    suspend fun getReleasedPokemonList(): Resource<PokemonResponse> = try 
        val response = pogoApi.getReleasedPokemon()
        Log.d("MainActivity", "list: $response")
        Resource.Success(data = response)
     catch(e: IOException)
        Resource.Error("Please check your internet connection")
     catch(e: HttpException)
        Resource.Error("Unexpected response")
    

【讨论】:

以上是关于改造 API 调用返回 null的主要内容,如果未能解决你的问题,请参考以下文章

改造获取请求返回 null

改造 - 是不是可以避免从应用程序拦截器调用实际 api 并返回硬编码响应?

Rxjava 2 - 使用领域和改造获取数据

改造 2:从响应正文中获取 JSON

改造返回错误 307,在 android 中调用 web 服务

如何从包含android中API响应的缓存中获取改造缓存数据