handleMeter.uiState.collectAsState() 和记住 Kotlin 中的 { handleMeter.uiState } 之间有什么不同?
What are differents between handleMeter.uiState.collectAsState() and remember { handleMeter.uiState } in Kotlin?
uiState
是 MutableStateFlow
in ViewModel()
,代码 A 和代码 B 可以根据流的最新值自动更新 UI。
1:Kotlin中的handleMeter.uiState.collectAsState()
和remember { handleMeter.uiState }
有什么区别?
2:代码C错误,我不能用remember
包裹handleMeter.uiState.collectAsState()
,为什么?怎么才能记住流量的最新值?
代码A
@Composable
fun Greeting(handleMeter: HandleMeter,lifecycleScope: LifecycleCoroutineScope) {
Column(
modifier = Modifier.fillMaxSize()
) {
var dataInfo = handleMeter.uiState.collectAsState()
Text(text = "My ${dataInfo.value}")
}
..
}
class HandleMeter: ViewModel() {
val uiState = MutableStateFlow<Int>(10)
...
}
代码B
@Composable
fun Greeting(handleMeter: HandleMeter,lifecycleScope: LifecycleCoroutineScope) {
Column(
modifier = Modifier.fillMaxSize()
) {
var dataInfo = remember { handleMeter.uiState }
Text(text = "My ${dataInfo.value}")
}
..
}
//The same
代码C(错误)
@Composable
fun Greeting(handleMeter: HandleMeter,lifecycleScope: LifecycleCoroutineScope) {
Column(
modifier = Modifier.fillMaxSize()
) {
var dataInfo = remember { handleMeter.uiState.collectAsState() }
Text(text = "My ${dataInfo.value}")
}
..
}
//The same
尝试直接从 Composable 检索状态流值会导致以下错误:
StateFlow.value
should not be called within compose.
您不应忽略此错误。原因是当流中有新值时,Compose 将无法重组。唯一可以在 Compose 中触发重组(不算调用 setContent
)的是更新状态持有者。
collectAsState
引擎盖下的函数收集流并更新底层状态持有者,这会在更新流值时导致重组。
collectAsState
的基本实现如下所示。它实际上更优化了,但这段代码应该让您了解幕后发生的事情。
@Composable
fun<T> StateFlow<T>.collectAsState() : State<T> {
val state = remember { mutableStateOf(value) }
LaunchedEffect(Unit) {
collect {
state.value = it
}
}
return state
}
最清晰的方式就是使用委托,这样就不需要加上.value
:
val dataInfo by handleMeter.uiState.collectAsState()
Text("My $dataInfo")
不需要记住它,因为它会记住引擎盖下所有必要的数据持有者。
假设您需要构建一些逻辑,当某些操作发生时应该更新这些逻辑 - 在这种情况下 collect
会产生一个新值。您必须使用 remember
来记住可变状态持有者,因此您的函数必须使用 @Composable
进行注释。这意味着你不能从另一个 remember
调用它,但你不需要,因为你需要记住的一切都已经在你的 remember
函数中。
uiState
是 MutableStateFlow
in ViewModel()
,代码 A 和代码 B 可以根据流的最新值自动更新 UI。
1:Kotlin中的handleMeter.uiState.collectAsState()
和remember { handleMeter.uiState }
有什么区别?
2:代码C错误,我不能用remember
包裹handleMeter.uiState.collectAsState()
,为什么?怎么才能记住流量的最新值?
代码A
@Composable
fun Greeting(handleMeter: HandleMeter,lifecycleScope: LifecycleCoroutineScope) {
Column(
modifier = Modifier.fillMaxSize()
) {
var dataInfo = handleMeter.uiState.collectAsState()
Text(text = "My ${dataInfo.value}")
}
..
}
class HandleMeter: ViewModel() {
val uiState = MutableStateFlow<Int>(10)
...
}
代码B
@Composable
fun Greeting(handleMeter: HandleMeter,lifecycleScope: LifecycleCoroutineScope) {
Column(
modifier = Modifier.fillMaxSize()
) {
var dataInfo = remember { handleMeter.uiState }
Text(text = "My ${dataInfo.value}")
}
..
}
//The same
代码C(错误)
@Composable
fun Greeting(handleMeter: HandleMeter,lifecycleScope: LifecycleCoroutineScope) {
Column(
modifier = Modifier.fillMaxSize()
) {
var dataInfo = remember { handleMeter.uiState.collectAsState() }
Text(text = "My ${dataInfo.value}")
}
..
}
//The same
尝试直接从 Composable 检索状态流值会导致以下错误:
StateFlow.value
should not be called within compose.
您不应忽略此错误。原因是当流中有新值时,Compose 将无法重组。唯一可以在 Compose 中触发重组(不算调用 setContent
)的是更新状态持有者。
collectAsState
引擎盖下的函数收集流并更新底层状态持有者,这会在更新流值时导致重组。
collectAsState
的基本实现如下所示。它实际上更优化了,但这段代码应该让您了解幕后发生的事情。
@Composable
fun<T> StateFlow<T>.collectAsState() : State<T> {
val state = remember { mutableStateOf(value) }
LaunchedEffect(Unit) {
collect {
state.value = it
}
}
return state
}
最清晰的方式就是使用委托,这样就不需要加上.value
:
val dataInfo by handleMeter.uiState.collectAsState()
Text("My $dataInfo")
不需要记住它,因为它会记住引擎盖下所有必要的数据持有者。
假设您需要构建一些逻辑,当某些操作发生时应该更新这些逻辑 - 在这种情况下 collect
会产生一个新值。您必须使用 remember
来记住可变状态持有者,因此您的函数必须使用 @Composable
进行注释。这意味着你不能从另一个 remember
调用它,但你不需要,因为你需要记住的一切都已经在你的 remember
函数中。