在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也會重繪】