You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Retrofit结合协程调用PokeApi异常,RecyclerView无法加载宝可梦数据

问题分析与修复方案

你的RecyclerView始终为空的核心原因是异步请求时序错误,加上适配器更新逻辑缺失,具体问题和修复步骤如下:

1. 异步请求未完成就更新适配器

obtenerPokemons中循环发起30个异步协程请求,但循环结束后立刻调用pokemonAdapter.setPokemons(pokemons)——此时所有网络请求都还在后台执行,pokemons集合是空的,自然没有数据展示。

2. 添加数据后未通知适配器更新

就算后续请求成功把数据加入pokemons,你也没有调用适配器的更新方法,适配器不知道数据变化,不会刷新UI。

3. 潜在空指针风险

call.body()可能返回null(比如请求成功但数据解析失败),直接pokemons.add(pokemonsResp)会导致空指针异常,需要判空。

4. 协程未绑定生命周期

直接使用CoroutineScope(Dispatchers.IO)会导致Activity销毁后协程仍在运行,引发内存泄漏,建议改用lifecycleScope(需依赖androidx.lifecycle:lifecycle-runtime-ktx)。

5. Retrofit接口写法不规范

用@Url拼接路径不如用@Path参数化清晰,避免手动拼接字符串出错。


修复后的代码示例

MainActivity修正部分

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    initRecycler()
    obtenerPokemons()
}

private fun initRecycler(){
    pokemonAdapter = PokemonAdapter(pokemons)
    linearLayoutManager = LinearLayoutManager(this)
    binding.recyclerpokemon.apply {
        setHasFixedSize(true)
        layoutManager = linearLayoutManager
        adapter = pokemonAdapter
    }
}

private fun obtenerPokemons() {
    lifecycleScope.launch(Dispatchers.IO) {
        // 并发请求所有数据,等待全部完成后统一更新UI
        val deferredList = mutableListOf<Deferred<Pokemon?>>()
        for (i in 1..30) {
            deferredList.add(async { searchByName(i) })
        }
        // 等待所有请求完成,过滤掉null结果
        val results = deferredList.awaitAll().filterNotNull()
        // 切回主线程更新数据和适配器
        withContext(Dispatchers.Main) {
            pokemons.clear()
            pokemons.addAll(results)
            pokemonAdapter.notifyDataSetChanged()
        }
    }
}

private fun getRetrofit(): Retrofit {
    return Retrofit.Builder()
        .baseUrl("https://pokeapi.co/api/v2/")
        .addConverterFactory(GsonConverterFactory.create())
        .build()
}

private suspend fun searchByName(query: Int): Pokemon? {
    return try {
        val call = getRetrofit().create(PokemonService::class.java).getPokemon(query)
        if (call.isSuccessful) {
            call.body()
        } else {
            null
        }
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

PokemonService修正

interface PokemonService {
    @GET("pokemon/{id}")
    suspend fun getPokemon(@Path("id") id: Int): Response<Pokemon?>
}

实体类补充空安全

data class Pokemon (
    @SerializedName("id") var id: Int,
    @SerializedName("name") var name: String,
    @SerializedName("sprites") var sprites: Sprites
)

data class Sprites (
    @SerializedName("back_default") var backDefault: String?,
    @SerializedName("front_default") var frontDefault: String?
)

额外优化建议

  • 不要一次性发起30个并发请求,PokeAPI有请求频率限制,可以加入延迟或者分页加载(比如一次请求20个,滚动到底部再加载下一页)。
  • 适配器中使用DiffUtil做局部更新,比notifyDataSetChanged()更高效。
  • 加入加载状态提示(比如ProgressBar),让用户知道正在加载数据。

内容的提问来源于stack exchange,提问作者CuadCode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 17:45:40