Jetpack Compose中Canvas场景为何无需使用remember?
Jetpack Compose中Canvas未用remember/MutableState却能更新角度的原因
在Jetpack Compose开发中,我们常规认知是:需要用remember在重组间缓存值,借助MutableState实现值的可观察性,这样状态变化才能触发重组更新UI。但使用Canvas可组合项时,却出现了例外情况——比如下面这段代码,既没把angle用remember缓存,也没声明为MutableState,点击Canvas时却依然能每次更新旋转角度:
DrawingTheme { var angle = 0f Canvas( modifier = Modifier .fillMaxSize() .clickable { angle += 20 } ) { rotate( degrees = angle ) { /* 绘制具体内容 */ } } }
针对这个现象,我们来解答两个疑问:
A1:是否因为触发onDraw lambda时Canvas未重组,angle并未丢失?clickable修饰符是否会触发onDraw?
没错,核心原因就在这里:
- 这段代码里的
angle是可组合函数内部的局部变量,当前场景下整个可组合函数并没有发生重组——因为没有MutableState这类可观察状态的变化触发重组,所以angle不会被重新初始化为0f,修改后的值会一直保留在内存中。 - 当你点击Canvas时,
clickable修饰符的lambda执行后,会主动触发Canvas的重绘请求,这会让Canvas的绘制lambda(也就是DrawScope里的代码)重新执行,此时读取的就是修改后的angle值,所以能看到旋转角度更新。简单说:clickable触发的是Canvas重绘而非重组,而局部变量在未重组的情况下不会被重置。
A2:是否因为DrawScope提供了无需维护底层Canvas状态的声明式无状态API,导致DrawScope中使用的变量被自动缓存和观察?
完全不是。DrawScope只是一个封装了绘制API的作用域,它本身没有自动缓存或观察变量的能力,本质就是一个无状态的绘制上下文。
你看到的现象和DrawScope的特性无关,还是源于之前说的逻辑:局部变量在可组合函数未重组时保留了修改后的值,加上点击触发了重绘,才让新值被用于绘制。如果此时触发了可组合函数的重组(比如父组件有状态变化导致这个组件重新执行),angle会被重新初始化为0f,之前的所有修改都会丢失——这也能反过来证明angle并没有被自动缓存或观察。
内容的提问来源于stack exchange,提问作者Nigini
相关产品推荐
相关产品推荐

