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
相关产品推荐
相关产品推荐

