如何优化 JetPack Compose 列表性能?

Max*_*tin 4 android android-jetpack android-jetpack-compose

我有一个简单的可组合函数,其中包含 LazyColumn:

@Composable
fun MyScreen(itemList: List<Item>) {
    LazyColumn {
        intems(itemList) {
            ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

一切都很好,但是itemList当滚动到达某个位置索引时,我的 ViewState( ) 应该改变。这就是为什么我将以下行添加到可组合函数中:

@Composable
fun MyScreen(itemList: List<Item>) {
    val lazyListState = rememberLazyListState()
    viewModel.onPositionChanged(lazyListState.firstVisibleItemIndex)
    LazyColumn(state = lazyListState) {
        intems(itemList) {
            ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

一切都按我的预期进行,但性能明显下降。我该如何修复它?

Phi*_*hov 13

你这里有两个问题:

  1. 您直接在可组合项中读取状态lazyListState.firstVisibleItemIndex,这会导致持续重新组合 - 每次lazyListState更改的任何部分,例如在每个滚动像素上。
  2. viewModel.onPositionChanged直接从可组合项进行调用。建议从特殊的副作用函数中进行此类调用,请阅读撰写和副作用文档中的思考中有关该主题的更多信息。

在这种情况LaunchedEffect下,snapshotFlow可以像这样使用:

LaunchedEffect(Unit) {
    snapshotFlow { lazyListState.firstVisibleItemIndex }
        .collect(viewModel::onPositionChanged)
}
Run Code Online (Sandbox Code Playgroud)

当您需要根据列表状态更新视图时,您也可能面临同样的问题。在这种情况下derivedStateOf应该使用:只有当计算值实际发生变化时才会导致重组。

val firstVisibleItemIndex by remember {
    derivedStateOf {
        lazyListState.firstVisibleItemIndex
    }
}
Run Code Online (Sandbox Code Playgroud)