Android Kotlin中Retrofit2响应存入ArrayList并填充RecyclerView问题
问题解决:Retrofit异步响应填充RecyclerView为空的处理
问题根源
Retrofit的enqueue()是异步执行的:你循环发起的API请求还没拿到响应、往items里添加数据,初始化Adapter和RecyclerView的代码就已经执行完毕,此时items自然是空的。
正确实现方案
1. 优化Adapter,支持动态更新数据
先修改CurrencyRecyclerAdapter,让它支持数据的动态添加或批量更新,避免初始化后无法修改数据:
class CurrencyRecyclerAdapter(private val items: MutableList<ConvertedCurrency>) : RecyclerView.Adapter<CurrencyRecyclerAdapter.ViewHolder>() { // ... 保留你的ViewHolder、onCreateViewHolder、onBindViewHolder等实现代码 ... // 批量更新数据的方法 fun updateData(newItems: List<ConvertedCurrency>) { items.clear() items.addAll(newItems) notifyDataSetChanged() } // 单个添加数据的方法(性能更优,只刷新新增项) fun addItem(item: ConvertedCurrency) { items.add(item) notifyItemInserted(items.size - 1) } }
2. 调整请求逻辑,确保数据返回后更新Adapter
方案一:逐个请求返回后实时更新
先初始化Adapter和RecyclerView,再发起请求,每个请求成功后立即更新Adapter:
val items = mutableListOf<ConvertedCurrency>() // 先完成RecyclerView的初始化 recyclerAdapter = CurrencyRecyclerAdapter(items) currencyRecycler.apply { layoutManager = LinearLayoutManager(context) adapter = recyclerAdapter } // 循环发起API请求 for(curr in targetCurrencies) { val request = ServiceBuilder.buildService(ExchangeRateAPI::class.java) val call = request.getNewCurrency(etCurr.text.toString(), curr, etAmount.text.toString()) call.enqueue(object : Callback<ConvertedCurrency> { override fun onResponse(call: Call<ConvertedCurrency>, response: Response<ConvertedCurrency>) { if (response.isSuccessful) { response.body()?.let { convertedCurrency -> textView.text = "${convertedCurrency.new_amount}${convertedCurrency.new_currency}" // 添加数据并通知Adapter刷新 recyclerAdapter.addItem(convertedCurrency) } } } override fun onFailure(call: Call<ConvertedCurrency>, t: Throwable) { // 必须处理请求失败的情况,避免异常遗漏 t.printStackTrace() } }) }
方案二:等待所有请求完成后批量更新
如果希望等所有请求都返回后再统一刷新RecyclerView,推荐用Kotlin协程实现(需先给Retrofit添加协程支持,将接口方法改为suspend修饰):
// 先修改ExchangeRateAPI接口方法: // suspend fun getNewCurrency(base: String, target: String, amount: String): Response<ConvertedCurrency> val items = mutableListOf<ConvertedCurrency>() // 初始化RecyclerView recyclerAdapter = CurrencyRecyclerAdapter(items) currencyRecycler.apply { layoutManager = LinearLayoutManager(context) adapter = recyclerAdapter } // 用lifecycleScope管理协程,确保页面销毁时自动取消请求 lifecycleScope.launch { val baseCurr = etCurr.text.toString() val amount = etAmount.text.toString() // 并行发起所有请求 val deferredRequests = targetCurrencies.map { curr -> async { runCatching { val request = ServiceBuilder.buildService(ExchangeRateAPI::class.java) request.getNewCurrency(baseCurr, curr, amount) } } } // 等待所有请求完成,处理响应结果 deferredRequests.forEach { deferred -> val result = deferred.await() result.onSuccess { response -> response.body()?.let { items.add(it) } }.onFailure { t -> t.printStackTrace() } } // 所有请求完成后批量更新Adapter recyclerAdapter.updateData(items) }
3. 关键注意事项
- 不要用
response.body() as ConvertedCurrency强制转换,response.body()可能为null,用?.let做安全处理更稳妥。 - 必须实现
onFailure的逻辑,避免请求失败时无任何反馈或引发异常。 - 用
lifecycleScope管理协程,能自动绑定页面生命周期,防止内存泄漏。
内容的提问来源于stack exchange,提问作者ISO
相关产品推荐
相关产品推荐

