Jetpack compose 经典学习之甜甜圈跳过
发布时间:
Jetpack Compose 经典学习之甜甜圈跳过
Compose 的甜甜圈理论堪称是 compose ui 理论基石,对于每一个 compose 的使用者来说是必须掌握的知识。在此我也来从多个角度来分析 compose 的甜甜圈跳过。
第一步上代码。
@Preview
@Composable
fun MyComponent(modifier: Modifier = Modifier.padding(56.dp)) {
var counter by remember { mutableStateOf(0) }
LogCompositions("JetpackCompose.app", "MyComponent function")
val readCounter = counter
Box(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
contentAlignment = Alignment.Center
) {
CustomButton(onClick = {
counter++
}) {
LogCompositions("JetpackCompose.app", "CustomButton scope")
CustomText(
text = "Counter: $counter",
modifier = Modifier
.clickable {
counter++
},
)
}
}
}
@Composable
fun CustomText(
text: String,
modifier: Modifier = Modifier.padding(top = 46.dp),
) {
LogCompositions("JetpackCompose.app", "CustomText function")
Text(
text = text,
modifier = modifier.padding(32.dp),
style = TextStyle(
fontSize = 20.sp,
textDecoration = TextDecoration.Underline,
fontFamily = FontFamily.Monospace
)
)
}
@Composable
fun CustomButton(
onClick: () -> Unit,
content: @Composable () -> Unit
) {
LogCompositions("JetpackCompose.app", "CustomButton function")
Button(onClick = onClick, modifier = Modifier.padding(16.dp)) {
LogCompositions("JetpackCompose.app", "Button function")
content()
}
}
class Ref(var value: Int)
@Composable
inline fun LogCompositions(tag: String, msg: String) {
val ref = remember { Ref(0) }
SideEffect { ref.value++ }
Log.d(tag, "Compositions: $msg ${ref.value}")
}
留一秒钟猜一猜 log 是什么
Compositions: MyComponent function 0
Compositions: CustomButton function 0
Compositions: Button function 0
Compositions: CustomButton scope 0
Compositions: CustomText function 0
点击一下看看?
可以看到第一次重组的时候,所有 composable 的 function 都被调用了。这个时候如果我点击了按钮,想想会发生什么?
Compositions: MyComponent function 1
Compositions: CustomButton scope 1
Compositions: CustomText function 1
可以看到只有 MyComponent function-> CustomButton scope-> CustomText function, 这时候 CustomButton func 并没有参与重组,是不是很奇怪?这就是 compose 独特,神奇的一面,他不像以往的框架,会最小化重绘最小树,compose 会智能的跳过不需要重组的方法与范围。那么 compose 是如何知道哪个地方需要重组,那个地方不需要重组呢,我们暂且放下,先看下一个 case。
改一下看看?
// val readCounter = counter
然后我们正常点击一下看看log
... 同上
// 点击一下
Compositions: CustomButton scope 1
Compositions: CustomText function 1
可以看到 MyComponent 并没有发生重组,这之间重组的秘密到底是什么?具体原理我总结在这篇文章里面了。
再改一点试试看
text = "text",
我们把 text 改一下看看结果如何
... 同上
Compositions: CustomButton scope 1
Compositions: CustomText function 1
奇怪为什么 CustomText 为什么会发生重组?让我们看看到底是什么原因?现在我们回头看下 CustomText 的调用处。
CustomText(
text = "Counter: $counter",
modifier = Modifier
.clickable {
counter++
},
)
我们看到有 2 个地方分别使用了 counter,那到底是哪个地方引起的呢,我们分别注释调看看,
注释掉 text = “Counter”,
这个时候我们会发现怎么点,所有重组都没了,这是为什么呢?
...
想想为什么?
许久沉思之后我们想到上面提到了,如果能捕获重组必须得建立 read 依赖,才能够触发重组,如果注释 counter 使用,目前没有一个 read 依赖,所以也就不会触发重组了。
注释掉另一个呢,
.clickable {
counter++
}
... 同上
Compositions: CustomButton scope 1
显示 scope 里面被使用,但是方法没有被调用,为什么呢,
最后一个问题 composable lambda 和普通 lambda 到底有何不同?
##

发表评论