我想在协程完成后启动一个 LaunchedEffect。
val dataStore = StoreAppSettings(ctx)
val scope = rememberCoroutineScope()
scope.launch {
dataStore.getCycleStart.collectLatest { vm.cycleStart = it }
dataStore.getSmartCycle.collectLatest { vm.smartCycle = it }
scope.cancel()
}
if (vm.categories.isNotEmpty() && !scope.isActive) {
LaunchedEffect(key1 = ctx){
vm.updateTransactionState()
}
}
我尝试取消范围并检查范围是否处于活动状态,但显然它不起作用
Compose 是基于状态的,因此您不必等待某些协程完成,而是您的异步代码会更新状态,以便您的可组合项可以在状态发生变化时重新组合。
所有非 UI 特定的异步代码(例如,从数据存储中读取值)都属于视图模型。从那里它作为一个 StateFlow 公开,可以在您的可组合项中观察到更改。
视图模型中的
cycleStart
和 smartCycle
属性应如下所示:
private val dataStore = StoreAppSettings(applicationContext)
val cycleStart: StateFlow<Boolean?> = dataStore.getCycleStart.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = null,
)
val smartCycle: StateFlow<String?> = dataStore.getSmartCycle.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = null,
)
由于从您的代码中不清楚数据存储首选项是什么类型,我只是假设在此示例中它们是布尔值和字符串。将其更改为实际情况。
这些属性现在是可以在可组合项中收集的流:
val cycleStart by vm.cycleStart.collectAsStateWithLifecycle()
val smartCycle by vm.smartCycle.collectAsStateWithLifecycle()
为此,您需要 gradle 依赖项
androidx.lifecycle:lifecycle-runtime-compose
。
这些变量现在始终使用数据存储中的当前内容进行更新。当发生变化时,这些变量将立即更新并触发重组,以便您的 UI 可以对新值做出反应。
您的 UI 代码应该只描述根据变量的当前内容应该发生什么。它们将包含
null
,直到检索到的数据存储读取首选项,因此您可以简单地使用 if (cycleStart != null)
之类的内容来显示对于给定 cycleStart
应该可见的 UI。
但是,您应该不触发某些视图模型逻辑作为响应。这应该由视图模型本身来完成。
无论
vm.updateTransactionState()
做什么,这可能应该由视图模型响应新的流量值来完成。为此,您可以使用流运算符,例如 mapLatest
、flatMapLatest
、onEach
等。将它们应用到 stateIn
之前的流中。如果需要both流的值,也可以用combine
将它们合并到on流中。