Compose的一些小Tips - 可组合项的生命周期
Compose的一些小Tips - 可组合项的绘制(本文)
Compose的一些小Tips - 列表的优化
本系列介绍Compose的一些常识,了解这些tips并不会让人摇身一变成为大佬,但可以帮助到一些学习Compose的安卓开发者避免一些误区,也是对Compose入门详解中遗漏的一个补充。本文介绍可组合项的绘制
在说可组合项之前,我们先说说原生view的绘制过程,面试时也经常问到,并且可组合项的展现和view的绘制过程非常的相似。
我们简单复习下原生view的三个主要的阶段,值得注意的是,每一个view的绘制,都会经历这必不可少的三个阶段
ps:可以看到onMeasure会进行一次测量,onLayout也会进行一次测量,这是二次测量,有兴趣的可以自行了解,因为和本文内容不相关
可组合项的展现到屏幕前的三个阶段分别为
Compose会根据跟踪可组合项中的状态智能的跳过重组时不必要(没发生过变化)的阶段,这也是Compose对性能的优化。
对于view来说onMeasure这些方法都是view的实现方法,而可组合项中好像也没有叫Composition 的方法暴露出来,这是因为Compose都是基于可组合项和它的状态来绘制的,因此三个阶段的具体方法也是二者的结合。并且因为单向数据流的关系,可能会因为对组合的状态的监听而影响到测量和绘制阶段(也可能不影响,下面会举例),所以下面的例子都是讲的直接影响这个阶段的作用域,并不是只影响这个阶段的作用域,希望读者不要误解。
@Composable 函数或 lambda 代码块中的状态改变时,Compose会监听到状态的改变并开始重组(重新绘制),这也涉及到可组合项的生命周期相关知识,如果不了解的可以去看下Compose的一些小Tips - 可组合项的生命周期,我这边直接说结论,就是状态如果改变了内容则组合会发生改变,影响可组合项的绘制,而内容如果没发生改变,则会跳过重组。
我们可以来看一个简单的例子
var state by remember {
mutableStateOf(0)
}
Column() {
Text(text = "重组$state")
Text(text = "不重组")
}
在上诉例子中第一个Text会因为state 的改变而进行重新进行组合这个阶段,因此重新进行绘制,如果state 从 0 变为1 ,则在理想情况下第一个Text会经历组合和绘制阶段,但因为Text的大小和位置都没有发生变化,所以会跳过测量阶段,而第二个Text因为不涉及状态的变化,会跳过所有的阶段。
我们可以再来看一个简单的例子理解影响到测量阶段的值
var width by remember {
mutableStateOf(10.dp)
}
var offsetX by remember { mutableStateOf(8.dp) }
Text(
text = "位置和大小发生变化",
modifier = Modifier
.width(width)
.offset {
IntOffset(offsetX.roundToPx(), 0)
}
)
在上诉的简单代码示例中,影响到可组合项大小的width 状态和影响到可组合项位置的offsetX 状态会使Compose进行可组合项的测量阶段,然后再进行绘制阶段。
而绘制阶段的最明显的作用范围用最简单的话来说就是每一次从屏幕上肉眼可见的变化,都经历了绘制阶段,包括上面两段示例代码,都经历了绘制阶段。
为什么说View的绘制是约等于可组合项的绘制而不是等于呢,上面其实已经吧答案说过了
这是原生xml和Compose除了写法以外,原理的不同。
上面已经说过,Compose的可组合项会根据状态智能的跳过不需要的阶段,以优化性能,而这个智能就很有嚼头,如果写法对了,就会智能的跳过,如果写的不对,就会造成额外的开销,甚至因为Compose的代码还在发展中,还不够成熟,会比原生xml更消耗性能,这也是一些不愿意学习的读者所说的,“我跑起来性能就是比原生差,跨平台还不如选flutter,哪儿哪儿都不行,再看两年吧”。在写法错误情况下,Compose的性能确实不如原生xml的。