使用Retrofit调用API后RecyclerView数据不更新问题排查
RecyclerView调用notifyDataSetChanged()不更新的问题解决
问题原因
- UI更新线程错误:RecyclerView的通知更新操作必须在主线程执行,你当前在
Dispatchers.Default后台协程中调用notifyDataSetChanged(),导致更新指令无法被UI线程处理,列表自然不会刷新。 - 潜在空指针风险:异步API请求如果意外提前返回(如缓存命中),可能会出现
orderAdapter尚未初始化就调用!!强制解包的情况,引发崩溃。
解决方案
1. 强制在主线程执行UI更新
使用withContext(Dispatchers.Main)将notifyDataSetChanged()包裹,确保更新操作在主线程运行。
2. 优化数据更新逻辑
给适配器添加封装的updateData方法,内部处理列表替换和通知,避免直接操作数据源的强制类型转换,同时降低空指针风险。
3. 替换GlobalScope(推荐)
GlobalScope的生命周期不受Activity管理,易引发内存泄漏,改用lifecycleScope(需依赖androidx.lifecycle:lifecycle-runtime-ktx)绑定Activity生命周期。
修正后的代码
主Activity代码
class OrderHistoryActivity : AppCompatActivity() { lateinit var recyclerView: RecyclerView var orderAdapter: OrderAdapter? = null var models: MutableList<OrderModel> = ArrayList() // 直接初始化,避免可空 lateinit var prefs: Prefs override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_order_history) recyclerView = findViewById(R.id.orderRecyclerView) prefs = Prefs(this@OrderHistoryActivity) // 初始化静态测试数据 for (i in 0..7) { models.add(OrderModel("#14524$i", "Nov 3, 2022", "Completed")) } // 初始化RecyclerView与适配器 recyclerView.layoutManager = LinearLayoutManager(this) orderAdapter = OrderAdapter(this, models) recyclerView.adapter = orderAdapter Log.d("FUNCTION", "RESULT -> STATIC DATA") // 使用lifecycleScope发起异步请求,绑定Activity生命周期 lifecycleScope.launch(Dispatchers.IO) { runCatching { Log.d("FUNCTION", "API TO GET ORDERS INIT ${prefs.token} ${prefs.userId}") val response = withTimeout(REST_API_TIMEOUT) { RetrofitClient(this@OrderHistoryActivity).getApi().getOrders( prefs.token, prefs.userId, "get" ).execute().parseResult<OrdersResponse>() } Log.d("FUNCTION", "API TO GET RESULTS -> RESPONSE ${Gson().toJson(response)} ") response.lastReadDate = System.currentTimeMillis() // 转换API数据为OrderModel列表 val newOrders = mutableListOf<OrderModel>() response.data.forEach { data -> val orderId = data.id val orderStatus = data.status Log.d("FUNCTION", "API TO GET IND RESULT -> RESPONSE ${orderId} ${orderStatus}") newOrders.add(OrderModel("${orderId}", "Nov 20, 2024", "${orderStatus}")) } // 切换到主线程更新UI withContext(Dispatchers.Main) { models.clear() models.addAll(newOrders) orderAdapter?.notifyDataSetChanged() // 使用安全调用避免空指针 Log.d("FUNCTION", "API TO GET IND RESULT MODELS -> RESPONSE ${models}") } }.onFailure { ex -> when (ex) { is RestApiException -> { val err = OnApiErrorEvent(ex.message ?: ex.toString()) Log.d("FUNCTION", "rest exp") Log.d("FUNCTIONwwr", "${err}") } is CancellationException -> { // 处理请求超时逻辑 } else -> { val err = OnApiErrorEvent(ex.message ?: ex.toString()) // 处理其他异常逻辑 } } }.finally { withContext(Dispatchers.Main) { // viewModel.progress.set(false) } } } } }
适配器优化(可选)
给OrderAdapter添加封装的更新方法,让数据更新更安全优雅:
class OrderAdapter(private val context: Context, private val orders: MutableList<OrderModel>) : RecyclerView.Adapter<OrderAdapter.ViewHolder>() { // ... 保留原有的ViewHolder、onCreateViewHolder、onBindViewHolder、getItemCount实现 // 封装数据更新方法 fun updateData(newOrders: List<OrderModel>) { orders.clear() orders.addAll(newOrders) notifyDataSetChanged() } }
此时Activity主线程的更新代码可替换为:
orderAdapter?.updateData(newOrders)
内容的提问来源于stack exchange,提问作者user1001176
相关产品推荐
相关产品推荐

