读取 LazyListState 会导致零星的重组

问题描述 投票:0回答:1

考虑以下最小可重现代码:

@Composable
fun Sandbox() {
    val state = rememberLazyListState()

    LazyColumn(
        state = state,
        modifier = Modifier.height(200.dp)
    ) {

        // This line of code leads to sporadic recompositions.
        // No recompositions once that line is commented out.
        val test = DoSomething(state)

        items(count = 50, key = {index -> index}) { index ->
            Text(text = "Item: $index")
        }
    }

}

// note that this is not a composable function, that's intended from my side
// as I want to return values (not possible with composable functions)
fun DoSomething(state: LazyListState) : Int? {
    val items = state.layoutInfo.visibleItemsInfo
    return null
}

当我上下滚动列表几次时,这会导致重新组合:

一旦删除对

DoSomething(state)
的呼叫,我就没有这个问题了。为什么读取状态会导致重组?

android kotlin android-jetpack-compose
1个回答
0
投票

当你调用

DoSomething(state)
时,你正在访问
LazyListState
对象,它是一个状态持有者。此访问会导致 Compose 安排重组以确保状态是最新的。

出现此行为的原因是

LazyListState
是一个复杂的状态对象,取决于列表的布局和滚动状态。当您访问其属性(例如
layoutInfo
visibleItemsInfo
)时,Compose 需要确保状态一致且是最新的。

在您的情况下,调用

DoSomething(state)
会触发重组,因为 Compose 需要更新列表的状态。这样做是为了确保任何依赖的可组合项(例如
LazyColumn
及其项目)都能正确更新。

当您删除对

DoSomething(state)
的调用时,不再触发重组,因为不需要更新状态。

考虑实施以下选项:

  1. 使用快照状态:不要直接访问
    LazyListState
    对象,而是使用
    remember
    derivedStateOf
    创建快照状态来存储必要的信息。这将使状态访问与重组分离。
  2. 使用可组合函数:如果可能,将
    DoSomething
    转换为可组合函数,这将允许您使用 Compose 的内置状态管理并避免显式状态访问。
  3. 最小化状态访问:如果需要访问
    LazyListState
    对象,请尝试最小化访问频率或使用更轻量级的替代方案,例如用于简单滚动状态的
    rememberLazyListScrollState

通过应用这些策略,您应该可以立即解决问题!如果这不能解决问题,请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.