如何在使用PagingDataAdapter时恢复RecyclerView的滚动位置?

7

我有一个应用程序,从API获取了一个包含158个项目的列表,并将其存储在Room中,然后显示给用户。RoomDB是真相的来源。

这是我的ViewModel上获取数据库结果的代码:

private val pagingConfig =
    PagingConfig(pageSize = 20, enablePlaceholders = false, maxSize = 300)

fun getList(filters: Filters): Flow<PagingData<Character>> {
    return Pager(pagingConfig) {
        repository.getCharacters(filters)
    }.flow.map {
        it.asDomainModel()
    }
}

这是我片段中用来填充适配器的代码:
private fun fetchData(filters: Filters) {
    lifecycleScope.launch {
        charactersViewModel.getList(filters).collectLatest { pagedList ->
            characterAdapter.submitData(pagedList)
        }
    }
}

当前行为:

  • 当在我的第60个项目之后发生配置更改时,滚动位置会丢失。我发现将pagingConfig中的pageSize20增加到55可以解决此问题。

我已经尝试过:

由于我是异步获取数据的,因此我尝试使用来自此文章的代码防止在适配器为空时加载数据,但它没有起作用。

characterAdapter.stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY

我希望实现以下目标:

能够在列表底部滚动并进行配置更改,而不会失去滚动位置,无需增加我的pageSize,即使列表变得更大

https://github.com/doilio/DC-Characters

4个回答

3
不要在 getList 方法中每次都返回一个新的 Flow<PagingData> 实例。
应该像这样做:
class YourViewModel: ViewModel() {
   private mPagingData = Flow<PagingData<Character>>? = null;

   fun getList(filters: Filters): Flow<PagingData<Character>> {
      if(mPagingData != null) return mPagingData; //This is important
      else
         mPagingData = Pager(pagingConfig) {
              repository.getCharacters(filters)
         }.flow.map {
              it.asDomainModel()
         }
      return mPagingData;
   }
}

除此之外,请确保您在片段的 onCreate 中初始化适配器。

1
你要找的方法是PagingSource.getRefreshKey()。它接收先前状态PagingState,其中包含字段PagingState.anchorPosition,即最后访问的索引(包括占位符)。请注意保留HTML标签。

https://developer.android.com/topic/libraries/architecture/paging/v3-network-db#refresh-in-place

编辑:我现在看到你正在使用Room的实现。实际上,与Remote REFRESH及其getRefreshKey实现相关的几个错误应该在下一个版本(alpha07)中得到解决。请参见https://issuetracker.google.com/issues/167260236


由于作者使用了Room,我想知道从Room创建的PagingSource是否不能按预期工作?(尽管文档中说“PagingSource实现会为您处理此问题”) - shoheikawano
1
啊,我没注意到他们在第一句话中说他们正在使用房间 :) alpha07 版本中有一些错误修复,应该可以解决这个问题。 - dlam
"alpha07版本将会发布一些修复bug的更新,这听起来很不错!期待它的到来 :)" - shoheikawano

0

PagingDataAdapter有一个名为loadStateFlowflow属性,其中包含已处理数据的状态。

您可以尝试以下操作:

lifecycleScope.launchWhenCreated {
        adapter.loadStateFlow.map { it.refresh }
            .distinctUntilChanged()
            .collect {
                if (it is LoadState.NotLoading) {
                    // reset to position you wanted
                }
            }
    }

LoadState.NotLoadingloadStateFlow 的特定状态,对应于数据处理完成的状态。

LoadState.NotLoading


0

我遇到了同样的问题。在我的情况下,我将PagingConfig中的enablePlaceholders设置为true,并将initialLoadSize设置为可被pageSize整除(例如,pageSize=10,initialLoadSize=20)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接