Seth Madison
09/06/2023, 5:36 AMbinding has started collecting. I have code along the lines of:
binder = bind {
renderer.events.map { it.toIntent() } bindTo store
}.apply { start() }
But I have no way to know when it is safe to call renderer.dispatch because the call to start() is asynchronous, and non-blocking.
It would be nice to provide an API similar to stateIn, which offers a default implementation that launches a job to start sharing, and a secondary suspending stateIn() function that blocks until the sharing has begun.
In MVIKotlin we could offer suspending start() that would block until the flows are all actively collecting.
Thoughts? Am I missing something?Seth Madison
09/06/2023, 5:36 AMbind(Dispatchers.Main.immediate), but that won’t work on all platforms.Seth Madison
09/06/2023, 5:50 AMprivate val scope: CoroutineScope = CoroutineScope(Dispatchers.Main)
private val isReady: MutableStateFlow<Boolean> = MutableStateFlow(false)
binder = bind {
renderer.events.map { it.toIntent() } bindTo store
flowOf(true) bindTo ::handleReady
}.apply { start() }
fun handleReady(isReady: Boolean) {
scope.launch { isReady.emit(isReady) }
}
fun dispatch(event: Event) {
scope.launch {
isReady.first { it }
renderer.dispatch(event)
}
}Arkadii Ivanov
09/06/2023, 8:06 AMrenderer?Seth Madison
09/06/2023, 1:16 PMBaseMviViewArkadii Ivanov
09/06/2023, 1:23 PMSeth Madison
09/06/2023, 1:28 PMBaseMviView, which has an events property. https://github.com/arkivanov/MVIKotlin/blob/master/mvikotlin/src/commonMain/kotlin/com/arkivanov/mvikotlin/core/view/BaseMviView.kt#L22Arkadii Ivanov
09/06/2023, 1:58 PMBaseMviView doesn't have any magic, it's events subscription fully synchronous. The sync behaviour comes from the binder, which launches a coroutine. I think that having suspend fun start wouldn't help, because you would still have to launch a coroutine. So I think there are multiple possible solutions.
1. Actually use Dispatchers.main.immediate as you suggested. It should be supported on Android, JavaFx, Swing and Apple (Darwin) platforms.
2. Try creating your own BaseMviView backed by MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE)
3. Don't use binder and just collect manually.Arkadii Ivanov
09/06/2023, 1:59 PMBinder is not affected by this issue, because it always subscribes synchronously.Seth Madison
09/06/2023, 3:01 PMArkadii Ivanov
09/06/2023, 3:12 PMArkadii Ivanov
09/06/2023, 3:12 PMSeth Madison
09/06/2023, 3:25 PMBaseMviView to use a MutableSharedFlow with infinite buffer.
I’m targeting JS as well as JVM and Darwin, and so immediate is not an option for me.
I agree that you’d need to be a bit careful with the shared flow approach, but it does solve the issue, and it provides the same behavior as the Rx implementation.Arkadii Ivanov
09/06/2023, 3:28 PMbut it does solve the issueAs I mentioned, it solves the issue only for the first subscriber. Subsequent subscribers may still miss emissions.
and it provides the same behavior as the Rx implementationNope. Rx doesn't require any buffering, because it always subscribes synchronously. In fact, buffering may add undesired behaviour, e.g. outdated events are still buffered.
Arkadii Ivanov
09/06/2023, 3:29 PMArkadii Ivanov
09/06/2023, 3:36 PMSeth Madison
09/06/2023, 6:07 PMCommon.
homer disappearSeth Madison
09/06/2023, 6:07 PMArkadii Ivanov
09/06/2023, 6:15 PM