Paging 3 - PagingDataAdapter 完成刷新并且 DiffUtil 完成比较后如何滚动到 RecyclerView 顶部?

Flo*_*her 11 paging android android-paging android-paging-library android-paging-3

我将 Paging 3 与 RemoteMediator 结合使用,它在从网络获取新数据的同时显示缓存的数据。当我刷新我的PagingDataAdapter(通过调用refresh()它)时,我希望我的 RecyclerView 在刷新完成后滚动到顶部。在代码实验室loadStateFlow中,他们尝试通过以下方式处理这个问题:

lifecycleScope.launch {
    adapter.loadStateFlow
            // Only emit when REFRESH LoadState for RemoteMediator changes.
            .distinctUntilChangedBy { it.refresh }
            // Only react to cases where Remote REFRESH completes i.e., NotLoading.
            .filter { it.refresh is LoadState.NotLoading }
            .collect { binding.list.scrollToPosition(0) }
    }
Run Code Online (Sandbox Code Playgroud)

这确实会向上滚动,但在 DiffUtil 完成之前。这意味着如果顶部确实插入了新数据,RecyclerView将不会一直向上滚动。

我知道 RecyclerView 适配器有一个AdapterDataObserver回调,当 DiffUtil 完成比较时我们可以收到通知。但这会导致适配器的各种竞争条件和PREPEND加载APPEND状态,这也会导致 DiffUtil 运行(但这里我们不想滚动到顶部)。

一种可行的解决方案是传递PagingData.empty()PagingDataAdapter并重新运行相同的查询(仅调用refresh是行不通的,因为PagingData现在是空的并且没有任何内容可以刷新),但我更愿意保持旧数据可见,直到我知道刷新实际上成功了。

jak*_*edo 0

看一下代码,加载类型刷新的条件。

repoDatabase.withTransaction {
            // clear all tables in the database
            if (loadType == LoadType.REFRESH) {
                repoDatabase.remoteKeysDao().clearRemoteKeys()
                repoDatabase.reposDao().clearRepos()
            }
            val prevKey = if (page == GITHUB_STARTING_PAGE_INDEX) null else page - 1
            val nextKey = if (endOfPaginationReached) null else page + 1
            val keys = repos.map {
                Log.e("RemoteKeys", "repoId: ${it.id}  prevKey: $prevKey nextKey: $nextKey")
                RemoteKeys(repoId = it.id, prevKey = prevKey, nextKey = nextKey)
            }
            repoDatabase.remoteKeysDao().insertAll(keys)
            repoDatabase.reposDao().insertAll(repos)
        }
Run Code Online (Sandbox Code Playgroud)

如果LoadType 是刷新清除所有表,则应删除该条件。

if (loadType == LoadType.REFRESH) {
            repoDatabase.remoteKeysDao().clearRemoteKeys()
            repoDatabase.reposDao().clearRepos()
        }
 
Run Code Online (Sandbox Code Playgroud)