开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情
上图是官网上面的一张关于compose如何工作的图,从今天一个screen开始,根据条件的变化,compose进行0次到多次的重组。今天就看看重组相关的知识。
- 什么情况下发生重组
其实总的一句话那就是当状态发生改变的时候发生重组,我们最多使用的就是MutableState。下面看一个简单的例子:
Column() {
var count by remember {
mutableStateOf(0)
}
Log.i("test","log count:$count")
Text(text = "count:$count")
Button(onClick = { count++ }) {
Text(text = "Add")
}
}
写了一个列表,列表里面有一个text和button,当点击button的时候text上面显示的内容会不断的发生变化,看看效果:
这里的count必须使用remember,如果不使用remember那边在发生重组的时候这个值也会被相应的重置。使用remember之后compose会记住上次更新过的值,而不会在重组的时候重新赋值。那大家想想上面的log会打印几次呢?看看运行结果:
2022-12-04 08:27:14.546 I/test: log count:1
2022-12-04 08:27:14.895 I/test: log count:2
2022-12-04 08:27:15.181 I/test: log count:3
2022-12-04 08:27:15.631 I/test: log count:4
2022-12-04 08:27:15.863 I/test: log count:5
2022-12-04 08:27:16.181 I/test: log count:6
2022-12-04 08:27:16.446 I/test: log count:7
2022-12-04 08:27:16.712 I/test: log count:8
可以看出,这个值发生了多少次变化,这个log就会打印多少次,这就说明重组了多少次。如果把上面的代码变化一下:
fun ShowText(){
Text(text = "I'm another test")
Log.i("test","ShowText")
}
Column() {
var count by remember {
mutableStateOf(0)
}
Log.i("test","log count:$count")
Text(text = "count:$count")
Button(onClick = { count++ }) {
Text(text = "Add")
}
ShowText()
}
我又加了一个ShowText项,但是这个是另外一个可组合函数,那么输出结果是什么样子呢?
2022-12-04 08:38:56.251 14373-14373/com.laworks.recomposableexample I/test: log count:0
2022-12-04 08:38:56.269 14373-14373/com.laworks.recomposableexample I/test: ShowText
2022-12-04 08:38:59.396 14373-14373/com.laworks.recomposableexample I/test: log count:1
2022-12-04 08:39:00.168 14373-14373/com.laworks.recomposableexample I/test: log count:2
2022-12-04 08:39:00.919 14373-14373/com.laworks.recomposableexample I/test: log count:3
2022-12-04 08:39:01.596 14373-14373/com.laworks.recomposableexample I/test: log count:4
2022-12-04 08:39:02.929 14373-14373/com.laworks.recomposableexample I/test: log count:5
可以看出Showtext的log只打印了一次,总结一下就是Composable只会影响当前的可组合函数。 另外我们在使用动画的时候也会发生相应的重组,例如:
Column {
var count by remember {
mutableStateOf(0)
}
Log.i("test","log count:$count")
ShowText()
var colorChange by remember {
mutableStateOf(false)
}
val colors = animateColorAsState(targetValue = if(colorChange) Color.Red else Color.Blue, animationSpec = tween(1000))
Box(modifier = Modifier
.background(colors.value)
.size(100.dp))
LaunchedEffect(key1 = Unit ){
while (true){
colorChange = !colorChange
count++
delay(2000)
}
}
}
打印log如下:
2022-12-04 09:02:16.752 I/test: log count:1
2022-12-04 09:02:16.780 I/test: log count:1
2022-12-04 09:02:16.799 I/test: log count:1
2022-12-04 09:02:16.813 I/test: log count:1
2022-12-04 09:02:16.832 I/test: log count:1
2022-12-04 09:02:17.346 I/test: log count:1
2022-12-04 09:02:17.362 I/test: log count:1
2022-12-04 09:02:17.746 I/test: log count:1
2022-12-04 09:02:18.762 I/test: log count:2
2022-12-04 09:02:19.762 I/test: log count:2
2022-12-04 09:02:20.762 I/test: log count:3
2022-12-04 09:02:20.828 I/test: log count:3
2022-12-04 09:02:20.845 I/test: log count:3
2022-12-04 09:02:21.762 I/test: log count:3
2022-12-04 09:02:22.764 I/test: log count:4
2022-12-04 09:02:23.765 I/test: log count:4
2022-12-04 09:02:24.779 I/test: log count:5
2022-12-04 09:02:25.779 I/test: log count:5
从log来看,动画会导致composable走很多次。但是当count为1的时候打印的次数最多,而后面的相对打印次数比较少,次数也不一定相同,所以说虽然执行的条件是一样的,但是重组的次数也是有差别的,所以不要妄图使用composable的重组来达到某种附带效应,这种做法的结果是不可预期的,还是老老实实的使用remember比较好一点。 从上面的例子可以看出,重组函数重组的调用点就是一个节点,state影响的也是当前的节点,所以尽量不要把所有的组件都写在一个composable函数里面,使用一级一级组装的形式来进行是比较好的一种方式,在官网里面也是这个建议使用的。