Android 第3页-如何在PagingDataAdapter完成刷新且DiffUtil完成差异化后滚动到RecyclerView顶部?
我正在使用带RemoteMediator的分页3,它在从网络获取新数据时显示缓存数据。 当我刷新我的Android 第3页-如何在PagingDataAdapter完成刷新且DiffUtil完成差异化后滚动到RecyclerView顶部?,android,paging,android-paging,android-paging-library,android-paging-3,Android,Paging,Android Paging,Android Paging Library,Android Paging 3,我正在使用带RemoteMediator的分页3,它在从网络获取新数据时显示缓存数据。 当我刷新我的PagingDataAdapter(通过在其上调用refresh())时,我希望我的RecyclerView在刷新完成后滚动到顶部。在中,他们尝试通过以下方式通过loadStateFlow处理此问题: lifecycleScope.launch { adapter.loadStateFlow // Only emit when REFRESH LoadState f
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) }
}
这确实会向上滚动,但在DiffUtil完成之前。这意味着如果在顶部插入了新数据,则RecyclerView不会一直向上滚动。
我知道RecyclerView适配器有一个AdapterDataObserver
回调,在那里我们可以在DiffUtil完成diffing时收到通知。但这将导致适配器加载状态的PREPEND
和APPEND
出现各种竞争条件,这也会导致DiffUtil运行(但这里我们不想滚动到顶部)
一个可行的解决方案是将
PagingData.empty()
传递给PagingDataAdapter
,然后重新运行相同的查询(只调用refresh
将不起作用,因为PagingData
现在为空,没有任何内容可刷新)但是我更愿意让我的旧数据保持可见,直到我知道刷新实际上成功为止。查看一下代码,如果loadtype被刷新,那么条件是什么
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)
}
如果LoadType为refresh清除所有表,则应删除该条件
if (loadType == LoadType.REFRESH) {
repoDatabase.remoteKeysDao().clearRemoteKeys()
repoDatabase.reposDao().clearRepos()
}
我已经设法改进了主题问题中的基本代码片段。 关键是监听
CombinedLoadState
viewLifecycleOwner.lifecycleScope.launchWhenCreated {
adapter?.loadStateFlow
?.distinctUntilChanged { old, new ->
old.mediator?.prepend?.endOfPaginationReached.isTrue() ==
new.mediator?.prepend?.endOfPaginationReached.isTrue()
}
?.filter { it.refresh is LoadState.NotLoading }
..
// next flow pipeline operators
}
其中isTrue
是布尔扩展
fun Boolean?.isTrue() = this != null && this
因此,这里的想法是跟踪mediator.prepend:endOfPagination
标志状态。当mediator完成了当前页面的分页加载部分时,他的prepend
状态不会改变(如果您在向下滚动后加载页面)。
该解决方案在离线和在线模式下都运行良好
若您需要在两个方向上跟踪前置分页或分页,那个么在搜索静态内容等情况下,使用另一个
组合加载状态属性附加,刷新,中介和源是一个很好的起点,我们可以在DiffUtil.ItemCallback
的AreItemsSame
中返回false
,作为解决方法。我也用它来更改排序属性。你找到解决方案了吗?@P1NG2WIN没有,我现在用的是300毫秒的延迟,这有点糟糕:(我将对此提出问题。)then@P1NG2WIN您是否创建了问题?如果是,是否可以链接到此处?