【问题标题】:How to save paging state of LazyColumn during navigation in Jetpack Compose如何在 Jetpack Compose 导航期间保存 LazyColumn 的分页状态
【发布时间】:2021-12-12 18:30:59
【问题描述】:

我正在使用 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(...)
           }
       }
   }
}

【问题讨论】:

    标签: android android-jetpack-compose android-paging android-paging-3


    【解决方案1】:

    我找到了解决办法!

    @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, ...) {
                    ...
                }
            }
        }
        ...
    
    

    我刚刚发现使用Paging时的问题。

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

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

    这是 UI 混乱的地方,因为 pager 有 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}")
    

    在导航返回时,您应该会看到一条日志行,说明完全相同的first_visibleoffset,但使用amount items=0。 紧随其后的行将显示first_visibleoffset 被重置为0

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

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

    【讨论】:

    • 谢谢!它对我有用
    【解决方案2】:

    将列表状态保存在视图模型中,并在导航回包含列表的屏幕时重新加载。您可以在视图模型中使用LazyListState 来保存状态并将其作为参数传递到您的可组合组件中。像这样的:

    class MyViewModel: ViewModel() {
       var listState = LazyListState()
    }
    
    @Composable
    fun MessageListHandler() {
    
       MessageList(
          messages: viewmodel.messages,
          listState = viewmode.listState
       )
    }
    
    @Composable
    fun MessageList(
       messages: List<Message>,
       listState: LazyListState) {
    
        LazyColumn(state = listState) {
    
        }
    }
    

    如果您不喜欢 Navigation Compose 给您带来的限制,您可以尝试使用 Jetmagic。它允许您在屏幕之间传递任何对象,甚至以一种更容易从任何可组合访问它们的方式管理您的视图模型:

    https://github.com/JohannBlake/Jetmagic

    【讨论】:

    • 这不能与 PagingSource 一起使用。
    猜你喜欢
    • 2022-11-07
    • 2021-09-28
    • 1970-01-01
    • 2021-07-12
    • 2021-06-01
    • 1970-01-01
    • 2022-09-26
    • 2021-11-09
    • 1970-01-01
    相关资源
    最近更新 更多