Reputation: 65
I would like to start a LaunchedEffect after the coroutine is finished.
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()
}
}
I tried to cancel the scope after and check if the scope is active, but apparently its not working
Upvotes: 0
Views: 146
Reputation: 15698
Compose is state-based, so you do not wait for some coroutines to finish, instead your asynchronous code updates the state so your composables can recompose when that changes.
All asynchronous code that isn't UI-specific (for example, reading values from a data store) belongs in the view model. From there it is exposed as a StateFlow that can be observed in your composables for changes.
The cycleStart
and smartCycle
properties in your view model should look like this:
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,
)
Since from your code it isn't clear what type the data store preferences are, I just assumed for this example that they would be Boolean and String. Change that to what they actually are.
The properties are now flows that can be collected in the composables:
val cycleStart by vm.cycleStart.collectAsStateWithLifecycle()
val smartCycle by vm.smartCycle.collectAsStateWithLifecycle()
You need the gradle dependency androidx.lifecycle:lifecycle-runtime-compose
for that.
These variables are now always updated with the current content in the data store. When something changes there, these variables will update immediately and a recomposition is triggered so that your UI can react to the new values.
Your UI code should just describe what should happen depending on the current content of the variables. They will contain null
until the data store retrieved the preferences, so you can simply use something like if (cycleStart != null)
to display the UI that should be visible for a given cycleStart
.
You should, however, not trigger some view model logic in response. That should be done by the view model itself.
Whatever vm.updateTransactionState()
does, that should probably be done by the view model in reaction to a new flow value. For that you can use flow operators like mapLatest
, flatMapLatest
, onEach
and so on. Apply them to the flows just before stateIn
. If the values of both flows are needed at the same time, you can also combine them into one flow with combine
.
Upvotes: 0