在Compose的官方指导和示例代码中常常会看到这样的代码android
var count by remember{mutableStateOf(0)}
或者
var count = remember{mutableStateOf(0)}
复制代码
首先须要注意几个问题缓存
Type 'TypeVariable(T)' has no method 'getValue(Nothing?, KProperty<*>)' and thus it cannot serve as a delegatemarkdown
解决方法很简单,导包便可ide
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
也能够直接:
import androidx.compose.runtime.*
复制代码
这个问题多是Compose的一个bug,若是只是 by mutableStateOf(0),也会报错,可是按alt+enter 会提示须要导包,可是加了remember以后,按alt+enter是不提示导包的,很是奇怪。 4. 注意remember 后面是 {} , 不是()函数
进入正题,来看看mutableStateOf 和 remember 都是干吗的spa
class MainActivity : ComponentActivity() {
@ExperimentalMaterialApi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
println("---- clicked onCreated setContent ")
Surface() {
var count = 0 // 无状态
Button(
onClick = { count++ }, modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
.height(50.dp)
) {
Text(
text = "I have been clicked $count times",
modifier = Modifier.align(Alignment.CenterVertically)
)
SideEffect(effect = { println("---- text count = $count ") })
}
SideEffect(effect = { println("---- out count = $count ") })
}
}
}
}
复制代码
点击按钮,数字不变,控制台只有一次打印日志
2021-05-26 10:21:45.248 32194-32194/com.shakespace.compose I/System.out: ---- clicked onCreated setContent
2021-05-26 10:21:45.301 32194-32194/com.shakespace.compose I/System.out: ---- text count = 0
2021-05-26 10:21:45.301 32194-32194/com.shakespace.compose I/System.out: ---- out count = 0
复制代码
var count by mutableStateOf(0) // 改为mutableStateOf
复制代码
点击按钮,数字会不断增长,控制台输出code
2021-05-26 10:26:36.949 16988-16988/com.shakespace.compose I/System.out: ---- clicked onCreated setContent
2021-05-26 10:26:37.002 16988-16988/com.shakespace.compose I/System.out: ---- text count = 0
2021-05-26 10:26:37.002 16988-16988/com.shakespace.compose I/System.out: ---- out count = 0
2021-05-26 10:26:40.511 16988-16988/com.shakespace.compose I/System.out: ---- text count = 1
2021-05-26 10:26:41.141 16988-16988/com.shakespace.compose I/System.out: ---- text count = 2
2021-05-26 10:26:41.792 16988-16988/com.shakespace.compose I/System.out: ---- text count = 3
2021-05-26 10:26:42.828 16988-16988/com.shakespace.compose I/System.out: ---- text count = 4
2021-05-26 10:26:43.596 16988-16988/com.shakespace.compose I/System.out: ---- text count = 5
复制代码
把Button 的padding 改为和count 有关orm
setContent {
println("---- clicked onCreated setContent ")
Surface() {
var count by mutableStateOf(0)
Button(
onClick = { count++ }, modifier = Modifier
.padding(count.dp) // 把Button的padding 改为和count 有关
.fillMaxWidth()
.height(50.dp)
) {
Text(
text = "I have been clicked $count times",
modifier = Modifier.align(Alignment.CenterVertically)
)
SideEffect(effect = { println("---- text count = $count ") })
}
SideEffect(effect = { println("---- out count = $count ") })
}
}
复制代码
点击按钮,数字不会变化,控制台输出内存
2021-05-26 11:49:28.394 19077-19077/com.shakespace.compose I/System.out: ---- clicked onCreated setContent
2021-05-26 11:49:28.450 19077-19077/com.shakespace.compose I/System.out: ---- text count = 0
2021-05-26 11:49:28.450 19077-19077/com.shakespace.compose I/System.out: ---- out count = 0
2021-05-26 11:49:33.240 19077-19077/com.shakespace.compose I/System.out: ---- text count = 0
2021-05-26 11:49:33.240 19077-19077/com.shakespace.compose I/System.out: ---- out count = 0
2021-05-26 11:49:34.123 19077-19077/com.shakespace.compose I/System.out: ---- text count = 0
2021-05-26 11:49:34.123 19077-19077/com.shakespace.compose I/System.out: ---- out count = 0
2021-05-26 11:49:35.776 19077-19077/com.shakespace.compose I/System.out: ---- text count = 0
2021-05-26 11:49:35.776 19077-19077/com.shakespace.compose I/System.out: ---- out count = 0
复制代码
这时候数字不会变化,是由于Surface的直接子组件Button依赖于count这个state,那么count变化的时候,Surface接收的这个Composable函数就会重绘[方法从新调用],每次调用count就会是0,因此数字没有变化。
而前面Button不依赖于count的例子,外部不须要重绘(看日志 out 只打印了一次),count也不会重置,因此数字会增长。
在这种状况下,若是还想记住变量值,就要用到remember
setContent {
println("---- clicked onCreated setContent ")
Surface() {
var count by remember{ mutableStateOf(0)} // 使用remember
Button(
onClick = { count++ }, modifier = Modifier
.padding(count.dp)
.fillMaxWidth()
.height(50.dp)
) {
Text(
text = "I have been clicked $count times",
modifier = Modifier.align(Alignment.CenterVertically)
)
SideEffect(effect = { println("---- text count = $count ") })
}
SideEffect(effect = { println("---- out count = $count ") })
}
}
复制代码
点击按钮,数字会增长,控制台输出:
2021-05-26 11:56:28.675 5449-5449/com.shakespace.compose I/System.out: ---- clicked onCreated setContent
2021-05-26 11:56:28.728 5449-5449/com.shakespace.compose I/System.out: ---- text count = 0
2021-05-26 11:56:28.729 5449-5449/com.shakespace.compose I/System.out: ---- out count = 0
2021-05-26 11:56:36.311 5449-5449/com.shakespace.compose I/System.out: ---- text count = 1
2021-05-26 11:56:36.311 5449-5449/com.shakespace.compose I/System.out: ---- out count = 1
2021-05-26 11:56:36.840 5449-5449/com.shakespace.compose I/System.out: ---- text count = 2
2021-05-26 11:56:36.840 5449-5449/com.shakespace.compose I/System.out: ---- out count = 2
2021-05-26 11:56:37.206 5449-5449/com.shakespace.compose I/System.out: ---- text count = 3
2021-05-26 11:56:37.206 5449-5449/com.shakespace.compose I/System.out: ---- out count = 3
复制代码
外部仍是会重绘,可是每次值都会内存缓存中读取,这就是remember的做用,当当前Composable重绘的时候,能够暂存变量值。
setContent {
println("---- clicked onCreated setContent ")
var count by mutableStateOf(0) // 移到外面,不适用remember
Surface() {
Button(
onClick = { count++ }, modifier = Modifier
.padding(count.dp)
.fillMaxWidth()
.height(50.dp)
) {
Text(
text = "I have been clicked $count times",
modifier = Modifier.align(Alignment.CenterVertically)
)
SideEffect(effect = { println("---- text count = $count ") })
}
SideEffect(effect = { println("---- out count = $count ") })
}
}
复制代码
数字会增长,控制台输出
2021-05-26 12:03:32.605 9375-9375/com.shakespace.compose I/System.out: ---- clicked onCreated setContent
2021-05-26 12:03:32.658 9375-9375/com.shakespace.compose I/System.out: ---- text count = 0
2021-05-26 12:03:32.658 9375-9375/com.shakespace.compose I/System.out: ---- out count = 0
2021-05-26 12:03:35.100 9375-9375/com.shakespace.compose I/System.out: ---- text count = 1
2021-05-26 12:03:35.100 9375-9375/com.shakespace.compose I/System.out: ---- out count = 1
2021-05-26 12:03:38.646 9375-9375/com.shakespace.compose I/System.out: ---- text count = 2
2021-05-26 12:03:38.646 9375-9375/com.shakespace.compose I/System.out: ---- out count = 2
2021-05-26 12:03:39.642 9375-9375/com.shakespace.compose I/System.out: ---- text count = 3
2021-05-26 12:03:39.642 9375-9375/com.shakespace.compose I/System.out: ---- out count = 3
复制代码
这和重绘那个例子是相似的,setContent的参数也是个Composable,Surface做为直接子类,并无依赖于count,因此自己不会重绘,count也不会被重置。
若是咱们把上面的Surface换成Column之类的Composable,其余都不变,结果就不同了
2021-05-26 12:07:16.163 9780-9780/com.shakespace.compose I/System.out: ---- clicked onCreated setContent
2021-05-26 12:07:16.166 9780-9780/com.shakespace.compose I/System.out: ---- text count = 0
2021-05-26 12:07:16.166 9780-9780/com.shakespace.compose I/System.out: ---- out count = 0
2021-05-26 12:07:17.047 9780-9780/com.shakespace.compose I/System.out: ---- clicked onCreated setContent
2021-05-26 12:07:17.050 9780-9780/com.shakespace.compose I/System.out: ---- text count = 0
2021-05-26 12:07:17.050 9780-9780/com.shakespace.compose I/System.out: ---- out count = 0
2021-05-26 12:07:17.883 9780-9780/com.shakespace.compose I/System.out: ---- clicked onCreated setContent
2021-05-26 12:07:17.885 9780-9780/com.shakespace.compose I/System.out: ---- text count = 0
2021-05-26 12:07:17.885 9780-9780/com.shakespace.compose I/System.out: ---- out count = 0
复制代码
数字不变,并且 “clicked onCreated setContent” 每次都打印,说明setContent里面的Composable每次都会重绘
目前所能知道的是,Column、Row、Box之类的组件,传入的Composable参数是给对应的Scope的扩展函数,而Surface接收的就是一个普通的Composable函数,一个可能不够准确的结论是:扩展函数中的直接组件重绘的话,至关于接收这个扩展函数的组件也要重绘。【即Button须要重绘,Column也会重绘】