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 PMBaseMviView
Arkadii 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