【问题标题】:How to restore recyclerview scroll position when using PagingDataAdapter?使用 PagingDataAdapter 时如何恢复 recyclerview 滚动位置?
【发布时间】:2020-11-08 00:19:01
【问题描述】:

我有一个应用程序,它从 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,它解决了这个问题。

我已经尝试过的:

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

characterAdapter.stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY

我期望达到的目标:

能够滚动到列表底部并进行配置更改而不会丢失滚动位置“而无需随着列表变大而增加我的 pageSize

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

【问题讨论】:

    标签: android kotlin android-architecture-components android-paging android-paging-library


    【解决方案1】:

    永远不要从您的 getList 方法返回 Flow&lt;PagingData&gt; 的新实例。

    做这样的事情:

    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 中初始化适配器。

    【讨论】:

      【解决方案2】:

      您要查找的方法是PagingSource.getRefreshKey()。它具有先前的状态 PagingState,其中包含字段 PagingState.anchorPosition,即上次访问的索引(包括占位符)。

      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 实现为你处理这个”)
      • 啊,我没注意到他们在第一句话中说有空间使用 :) alpha07 修复了一些错误,应该可以解决这个问题。
      • “alpha07 发布了一些错误修复,应该可以解决这个问题。”听起来不错!!期待它:)
      【解决方案3】:

      有同样的问题。在我的情况下,我将 PagingConfig enablePlaceholders 更改为 true,并将 initialLoadSize 设置为可除以 pageSize(例如 pageSize=10,initialLoadSize = 20)。

      【讨论】:

        【解决方案4】:

        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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-01
          相关资源
          最近更新 更多