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

Kotlin中Room插入数据后如何刷新Paging3列表?

解决Paging3在Room数据变更时刷新列表的方案

方法一:利用Room数据监听自动触发PagingSource失效

1. 修改自定义ContactPagingSource,添加表监听

通过Room的InvalidationTracker监听ContactLocalModel表的变化,数据变更时标记PagingSource失效,触发重新加载:

class ContactPagingSource(
    private val contactDao: ContactDao,
    private val query: String,
    private val sort: SortingEnum = SortingEnum.ByName,
    private val appDatabase: AppDatabase // 传入Room数据库实例
) : PagingSource<Int, ContactLocalModel>() {

    private val tableObserver = object : InvalidationTracker.Observer("ContactLocalModel") {
        override fun onInvalidated(tables: MutableSet<String>) {
            invalidate() // 数据变更时触发Paging重新加载
        }
    }

    init {
        appDatabase.invalidationTracker.addObserver(tableObserver)
    }

    override fun getRefreshKey(state: PagingState<Int, ContactLocalModel>): Int? {
        // 优化刷新位置,回到当前页面附近
        return state.anchorPosition?.let { anchorPos ->
            state.closestPageToPosition(anchorPos)?.prevKey?.plus(1)
                ?: state.closestPageToPosition(anchorPos)?.nextKey?.minus(1)
        }
    }

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, ContactLocalModel> {
        val page = params.key ?: 0
        return try {
            Timber.d("load:  + $page")
            Timber.d("onQueryTextChange ContactPagingSource $query")
            val entities = if (query.isNotBlank()) {
                contactDao.getContactPagination(
                    params.loadSize,
                    page * params.loadSize,
                    query = query,
                    isOrderByName = sort.ordinal == SortingEnum.ByName.ordinal
                )
            } else {
                contactDao.getContactPagination(
                    params.loadSize,
                    page * params.loadSize,
                    query = "%",
                    isOrderByName = sort.ordinal == SortingEnum.ByName.ordinal
                )
            }
            if (page != 0) delay(1000)
            LoadResult.Page(
                data = entities,
                prevKey = if (page == 0) null else page - 1,
                nextKey = if (entities.isEmpty()) null else page + 1
            )
        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }

    override fun invalidate() {
        appDatabase.invalidationTracker.removeObserver(tableObserver)
        super.invalidate()
    }
}

2. ViewModel中传入Database实例

创建Pager时传入AppDatabase,让PagingSource能监听表变化:

val randomContactPostFlow = Pager(
    PagingConfig(
        pageSize = 10,
        enablePlaceholders = false,
        initialLoadSize = 10,
    )
) {
    val text = searchPaginationName.value ?: ""
    Timber.d("onQueryTextChange text $text")
    ContactPagingSource(contactDao, query = text, sort = enumVal, appDatabase = appDatabase)
}
    .flow
    .cachedIn(viewModelScope)

方法二:通过触发查询条件变化刷新列表

如果不想监听数据库表,可在数据插入完成后,通过更新查询条件LiveData,让switchMap重新创建Pager:

1. ViewModel中添加刷新方法

确保searchPaginationName是MutableLiveData,提供刷新触发方法:

val searchPaginationName = MutableLiveData("")

// 插入数据完成后调用此方法
fun refreshContacts() {
    searchPaginationName.value = searchPaginationName.value ?: ""
}

2. 页面插入数据后触发刷新

从网页插入数据到Room完成后(比如返回联系人页面时),调用ViewModel的刷新方法:

// 示例:网页返回后执行
viewModel.refreshContacts()

此时searchPaginationName值变化会触发switchMap重新创建PagingSource,加载最新数据。

方法三:使用Room原生分页支持(推荐)

Room支持直接返回PagingSource,自动监听数据变化,无需自定义PagingSource:

1. 修改Room Dao查询

移除LIMIT和OFFSET,让Room自动处理分页:

@Query("SELECT * FROM ContactLocalModel WHERE name LIKE '%'||:query||'%' " +
        "OR pttNo LIKE :query " +
        "OR furigana LIKE :query ORDER BY " +
        "CASE WHEN :isOrderByName = 1 THEN LOWER(name) END ASC, " +
        "CASE WHEN :isOrderByName = 0 THEN  pttNo END ASC, " +
        "id ASC"
)
fun getContactPagingSource(query: String, isOrderByName: Boolean? = true): PagingSource<Int, ContactLocalModel>

2. ViewModel中直接使用Room的PagingSource

简化代码,Room会自动监听数据变更:

val randomContactPostFlow = searchPaginationName.switchMap { query ->
    Pager(PagingConfig(
        pageSize = 10,
        enablePlaceholders = false,
        initialLoadSize = 10,
    )) {
        contactDao.getContactPagingSource(query, sort.ordinal == SortingEnum.ByName.ordinal)
    }.flow
}.cachedIn(viewModelScope)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 18:55:12