handleMeter.uiState.collectAsState() 和记住 Kotlin 中的 { handleMeter.uiState } 之间有什么不同?

What are differents between handleMeter.uiState.collectAsState() and remember { handleMeter.uiState } in Kotlin?

uiStateMutableStateFlow 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 函数中。