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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 04:40:55