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

RecyclerView Adapter依赖两个Room数据源重复触发notifyDataSetChanged报错如何解决

解决方案

这里提供两种落地方式,优先推荐第一种从DAO层解决,实现成本最低也最高效:

方案1:Room 关联查询一次性返回带状态数据(最优)

直接通过SQL关联查询,让Room返回单个数据源,从根源避免多数据源同步问题:

  1. 先定义用于列表展示的POJO类:
data class PageWithControlState(
    @Embedded val page: PageEntity,
    val isControlledByCurrentUser: Boolean
)
  1. 在DAO层写关联查询语句,传入当前登录用户ID即可:
@Query("SELECT p.*, CASE WHEN up.userId IS NOT NULL THEN 1 ELSE 0 END AS isControlledByCurrentUser FROM PageEntity p LEFT JOIN User_Page_Entity up ON p.pageId = up.pageId AND up.userId = :currentUserId")
fun getAllPagesWithControlState(currentUserId: Long): LiveData<List<PageWithControlState>>
  1. 仅观察这一个LiveData即可,每次数据库变更只会触发一次回调,直接把返回数据交给Adapter渲染,不存在多次调用notifyDataSetChanged的问题。

方案2:用MediatorLiveData合并双数据源(通用场景)

如果确实需要维护两个独立的数据源,可通过MediatorLiveData合并两个源的变更,只有两个源都返回过数据后才触发下游刷新:

// 定义合并后的LiveData
val mergedPageLiveData = MediatorLiveData<List<PageWithControlState>>()

// 缓存两个源的最新数据
private var pageList: List<PageEntity>? = null
private var userControlList: List<User_Page_Entity>? = null

// 添加两个数据源作为观察源
mergedPageLiveData.addSource(pageLiveData) { list ->
    pageList = list
    mergeDataIfReady()
}
mergedPageLiveData.addSource(userControlLiveData) { list ->
    userControlList = list
    mergeDataIfReady()
}

// 数据就绪后合并
private fun mergeDataIfReady() {
    val pages = pageList ?: return
    val controls = userControlList ?: return
    // 生成带状态的页面列表
    val controlledPageIds = controls.map { it.pageId }.toSet()
    val result = pages.map { page ->
        PageWithControlState(page, controlledPageIds.contains(page.pageId))
    }
    mergedPageLiveData.postValue(result)
}

仅观察mergedPageLiveData即可,每次两个数据源任意更新,只会触发一次合并后的回调,避免多次刷新的冲突。

额外优化建议

替换全量刷新的notifyDataSetChanged为DiffUtil做差量更新,既可以提升列表性能,也能彻底避免ViewHolder重复detach的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 16:30:01