如何在 Jetpack Compose 中导航期间保存 LazyColumn 的分页状态

Dam*_*ioo 4 android android-paging android-jetpack-compose android-paging-3

我正在使用androidx.paging:paging-compose(v1.0.0-alpha-14)和Jetpack Compose(v1.0.3),我有一个PagingSource负责从后端提取项目的自定义。我还使用撰写导航组件。

问题是我不知道如何在通过 NavHostController 导航到不同屏幕和返回之间保存寻呼机流程的状态(滚动状态和缓存项目)。我试图通过保存状态,rememberSaveable但无法完成,因为它不是可以放入 Bundle 的东西。有一个快速/简单的步骤来做到这一点吗?

我的示例代码:

@Composable
fun SampleScreen(
   composeNavController: NavHostController? = null,
   myPagingSource: PagingSource<Int, MyItem>,
) {
   val pager = remember { // rememberSaveable doesn't seems to work here
       Pager(
           config = PagingConfig(
               pageSize = 25,
           ),
           initialKey = 0,
           pagingSourceFactory = myPagingSource
       )
   }
   val lazyPagingItems = pager.flow.collectAsLazyPagingItems()

   LazyColumn() {
       itemsIndexed(items = lazyPagingItems) { index, item ->
           MyRowItem(item) {
               composeNavController?.navigate(...)
           }
       }
   }
}
Run Code Online (Sandbox Code Playgroud)

Seb*_*uez 13

我找到了解决办法!

@Composable
fun Sample(data: Flow<PagingData<Something>>):
    val listState: LazyListState = rememberLazyListState()
    val items: LazyPagingItems<Something> = data.collectAsLazyPagingItems()

    when {
        items.itemCount == 0 -> LoadingScreen()
        else -> {
            LazyColumn(state = listState, ...) {
                ...
            }
        }
    }
    ...

Run Code Online (Sandbox Code Playgroud)

我刚刚在使用时发现了问题所在Paging

导航时不记住列表滚动位置的原因归结Paging为引擎盖下方发生的情况。它看起来像这样:

  1. 创建了可组合的LazyColumn
  2. 我们从寻呼机异步请求列表数据。当前寻呼机列表项计数 = 0。
  3. UI 绘制了一个包含 0 个项目的lazyColumn。
  4. 寻呼机以数据响应,例如 10 个项目,并且 UI 被重新组合以显示它们。
  5. 例如,用户一直向下滚动并单击底部项目,这会将它们导航到其他地方。
  6. 用户使用例如后退按钮向后导航。
  7. 呃哦。由于导航,我们的可组合项LazyColumn被重新组合。我们再次从异步请求寻呼机数据开始。注意:寻呼机项目计数再次 = 0!
  8. rememberLazyListState被评估,它告诉 UI 用户一直向下滚动,所以现在应该返回到相同的偏移量,例如第五项。

这就是 UI 极度混乱的地方,因为分页器有 0 个项目,所以lazyColumn 有 0 个项目。UI 无法处理第五项的滚动偏移。滚动位置设置为仅从第 0 项开始显示,因为只有 0 个项目。

接下来发生什么:

  1. 寻呼机响应再次出现例如 10 个项目,导致另一次重组。
  2. 重组后,我们再次看到列表,滚动位置从第 0 项开始。

要确认您的代码是否属于这种情况,请在调用上方添加一个简单的日志语句LazyColumn

Log.w("TEST", "List state recompose. " +
            "first_visible=${listState.firstVisibleItemIndex}, " +
            "offset=${listState.firstVisibleItemScrollOffset}, " +
            "amount items=${items.itemCount}")
Run Code Online (Sandbox Code Playgroud)

first_visible返回时,您应该会看到一条日志行,其中的内容与 和完全相同offset,但带有amount items=0。紧接其后的行将显示first_visibleoffset重置为0

我的解决方案有效,因为它会跳过使用listState直到寻呼机加载数据。加载后,正确的值仍驻留在 中listState,并且滚动位置将正确恢复。

来源: https: //issuetracker.google.com/issues/177245496