Compose的一些小Tips - 列表的优化

系列文章

Compose的一些小Tips - 可组合项的生命周期
Compose的一些小Tips - 列表的优化(本文)

前言

本系列介绍Compose的一些常识,了解这些tips并不会让人摇身一变成为大佬,但可以帮助到一些学习Compose的安卓开发者避免一些误区,也是对Compose入门详解中遗漏的一个补充。列表的优化

项键

Compose的一些小Tips - 列表的优化_第1张图片

用官方的话来说,默认情况下,每个列表项的状态均与该项在列表或网格中的位置相对应。但是,如果数据集发生变化,这可能会导致问题,因为位置发生变化的列表项实际上会丢失任何记忆状态。想象一下 LazyColumn 中的 LazyRow 场景,如果某个行更改了项位置,用户将丢失在该行内的滚动位置。

为了解决上面的问题,官网推荐我们为每个列表项提供一个稳定的唯一键,为 key 参数提供一个块。提供稳定的键可使项状态在发生数据集更改后保持一致

示例代码:

Column() {

    LazyColumn(content = {

        items(count = persons.value.size
            , key = {
                persons.value[it].id
            }
        )
        {
            var time by remember {
                mutableStateOf(0)
            }
            if (persons.value[it].id == 50){
                Button(onClick = { time += 1 }) {
                    Text(text = persons.value[it].name+time)
                    Log.d(TAG, "我重组了: $time")
                }
            }
            Person(person = persons.value[it])
        }
    })
}

上面的示例代码重点在于与

 key = { persons.value[it].id}

我使用的是
implementation platform(‘androidx.compose:compose-bom:2022.10.00’)

但是实际调试发现重组的情况和官网描述的不一样,无论我加不加key这一参数都是最优重组,这让我有些困惑,点进源码才看见描述的变化
Compose的一些小Tips - 列表的优化_第2张图片
也就是说,在2022.10.00的版本过后这个key已经有默认值就是列表中的位置,在没有特殊情况下,无需开发者优化。

单独item的合理使用

在Column中,子可组合项的重组基本上是独立的,一个可组合项的重组并不会影响到同级的另一个可组合项
代码:

 var state by remember {
        mutableStateOf(0)
    }
    Column() {
        Text(text = "重组$state")
        Text(text = "不重组")
    }

示例图
Compose的一些小Tips - 列表的优化_第3张图片
而在LazyColumn中,我们使用item或者items来将可组合项包裹,和Column不同一个可组合项的重组会影响到在一个item中包裹的同级的另一个可组合项,并使其重组

示例图

Compose的一些小Tips - 列表的优化_第4张图片
可以预见的是,当同一个item包裹的可组合项过多,在该item重组时会造成一定的性能问题,官方文档描述,还会对scrollToItem() 和 animateScrollToItem()方法进行干扰;因此,当使用单个item包裹可组合项时应尽可能的少且合理。

建议添加 contentType

正如上文所述,在LazyColumn中,我们使用item或者items来将可组合项包裹,因此在不同的item之间也需要进行区分,Compose提供了contentType用以区分不同的item,设置了不同contentType的item将不会在重组时被视为是同一个类型的item,减少重组计算的开销(ps:我简单试了下没体验出什么开销和优化,我理解为这是一个规范的范例,人话就是,不加也行)

Compose的一些小Tips - 列表的优化_第5张图片

启用 R8编译器

这个其实是所有的Compose写的代码都使用R8编译器,并且在生产环境看性能,对于延迟布局来说,也是一样的。人话就是说,在debug和调试环境下你已经写了规范的代码还是遇到的卡顿等问题,其实都不是问题,只有打一个生产包出来试试才能知道是不是真的有问题。新版本android studio(使用 Android Gradle 插件 3.4.0 或更高版本构建项目)默认是使用R8编译器的。

总结

列表的优化主要是讲延迟列表LazyColumn只是一个例子,LazyRow和其他延迟组件都是一样的。

你可能感兴趣的:(Compose的一些小Tips,android)