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

Kotlin协程:IO线程完成后在主线程收集Room数据并解决越界异常

解决Room Flow数据收集时机导致的IndexOutOfBoundsException问题

你的代码运行时触发java.lang.IndexOutOfBoundsException: Index: 0, Size: 0,原因正如你排查的:在Resource.Success分支中,IO线程的数据库插入操作还没执行完,就开始收集Room的productFlow,此时数据库里还没有数据,Flow返回空列表,后续操作(比如访问response.data[0]或Adapter处理空数据)就会抛出越界异常。

修改方案

核心思路是等待IO线程的数据库插入任务完全完成后,再在主线程中收集Room的Flow数据,同时增加数据非空判断规避潜在风险:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    lifecycleScope.launch(Dispatchers.Main) {
        networkviewModel.productist.collectLatest {
            when (it) {
                Resource.Empty -> {
                    Log.e("product", "empty")
                }
                is Resource.Failure -> {
                    Log.e("product", "failure")
                }
                Resource.Loading -> {
                    LoadingUtils.showDialog()
                }
                is Resource.Success -> {
                    val response = it.value
                    Log.e("test", "success response")
                    // 先判断接口返回数据是否为空,避免后续越界
                    val products = response.data.takeIf { it.isNotEmpty() } ?: run {
                        Log.e("product", "response data is empty")
                        LoadingUtils.hideDialog()
                        return@collectLatest
                    }
                    val variants: List<Variants> = products.map { it.variants }.flatten()
                    
                    // 启动IO线程执行插入任务,并保存Job对象
                    val insertJob = lifecycleScope.launch(Dispatchers.IO) {
                        productRoom.insertProducts(products)
                        productRoom.insertVariants(variants)
                        val subcategoryid = SubCategoryList(products[0].subcategory_id!!.toInt())
                        productRoom.insertSubCat(subcategoryid)
                    }
                    // 等待IO插入任务完成,主线程挂起直到任务结束
                    insertJob.join()

                    subcat_id = products[0].subcategory_id!!.toInt()
                    
                    // 数据库已写入数据,再收集Flow更新UI
                    roomviewModel.productFlow.collectLatest { roomProducts ->
                        Log.e("test", "flow success from network room")
                        LoadingUtils.hideDialog()
                        // 检查Room返回数据非空后再更新Adapter
                        if (roomProducts.isNotEmpty()) {
                            proadapter.setMutableArraylist(roomProducts)
                            proadapter.notifyDataSetChanged()
                        } else {
                            Log.e("product", "room data is empty after insert")
                        }
                    }
                }
            }
        }
    }
}

关键修改点说明

  • 用join()等待IO任务完成:将IO线程launch返回的Job对象保存,调用join()会让当前主线程挂起,直到所有插入操作执行完毕,确保Room数据库已有数据。
  • 增加数据非空判断:在访问response.data[0]和更新Adapter前检查列表是否为空,覆盖接口返回空列表但标记为Success的异常场景。
  • 完善加载弹窗逻辑:在Resource.Loading分支显示弹窗,让加载状态逻辑更完整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 04:10:34