Is there a way to only run the molecule when its being collected? #225
-
We have molecule in a view model that is kept alive even when navigating to other tabs, for smooth tab navigation. The compose UI is not shown when going to another tab and will stop collecting, but the molecule in the view model continues to recompose. The molecule is collecting an upstream flow that emits periodically. The compose UI collectes the molecule state flow with collectAsState, and the molecule is launched on viewModelScope with frame clock |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 8 replies
-
Today you would have to do this with a custom frame clock which wrapped a real one and did not send frames while no one was collecting. I'm not sure we want to do this generally. One problem is has is that when you start collecting again the initial value is going to be wildly out-of-date which might not be what some want, and probably not something that could be the default. Maybe it could be a flag that you set when creating the |
Beta Was this translation helpful? Give feedback.
-
@joakimtall I wrote an extension based on fun <T : Any> CoroutineScope.launchActiveMolecule(
clock: RecompositionClock = RecompositionClock.ContextClock,
body: @Composable () -> T
): StateFlow<T> {
var mutableStateFlow: MutableStateFlow<T>? = null
var localBody by mutableStateOf<(@Composable () -> T)?>(value = null)
launchMolecule(
clock = clock,
emitter = { value ->
val outputFlow = mutableStateFlow
if (outputFlow != null) {
outputFlow.value = value
} else {
mutableStateFlow = MutableStateFlow(value).flowWhileActive { localBody = if (it) body else null }
}
},
body = {
localBody?.invoke() ?: mutableStateFlow?.value ?: body()
}
)
return mutableStateFlow!!
}
context (CoroutineScope)
@OptIn(ExperimentalCoroutinesApi::class)
fun <T> MutableStateFlow<T>.flowWhileActive(
started: SharingStarted = SharingStarted.WhileSubscribed(stopTimeoutMillis = 5000),
onSubscriptionChanged: (Boolean) -> Unit = {}
): MutableStateFlow<T> {
val mutableStateFlow = MutableStateFlow(value = value)
launch {
started.command(mutableStateFlow.subscriptionCount)
.mapLatest {
when (it) {
SharingCommand.START -> true
SharingCommand.STOP, SharingCommand.STOP_AND_RESET_REPLAY_CACHE -> false
}
}
.distinctUntilChanged()
.collectLatest { onSubscriptionChanged(it) }
}
launch {
started.command(mutableStateFlow.subscriptionCount)
.distinctUntilChanged()
.flatMapLatest {
when (it) {
SharingCommand.START -> this@flowWhileActive
SharingCommand.STOP, SharingCommand.STOP_AND_RESET_REPLAY_CACHE -> emptyFlow()
}
}
.collect(mutableStateFlow)
}
return mutableStateFlow
} |
Beta Was this translation helpful? Give feedback.
We don't have anything like that, no. That's somewhat out of our control since Compose is the one collecting flows.