ubu
02/07/2020, 11:00 AMViewModel
, I had a basic MVI-inspired state machine implemented in the following way:
/**
* State machine for this view model consisting of [Interactor], [State], [Event] and [Reducer]
* It reduces [Event] to the immutable [State] by applying [Reducer] fuction.
* This [State] then will be rendered.
*/
class Interactor(
private val scope: CoroutineScope,
private val reducer: Reducer = Reducer(),
private val channel: Channel<Event> = Channel(),
private val events: Flow<Event> = channel.consumeAsFlow()
) {
fun onEvent(event: Event) = scope.launch { channel.send(event) }
fun state(): Flow<State> = events.scan(State.init(), reducer.function)
}
interface StateReducer<STATE, EVENT> {
val function: suspend (STATE, EVENT) -> STATE
suspend fun reduce(state: STATE, event: EVENT): STATE
}
But then I was unable to get current state, I could only observe it as a Flow<State>
, so I re-implemented it in the following manner:
class Interactor(
private val scope: CoroutineScope,
private val reducer: Reducer = Reducer(),
private val channel: Channel<Event> = Channel(),
private val events: Flow<Event> = channel.consumeAsFlow()
) {
val state = ConflatedBroadcastChannel<State>()
init {
scope.launch {
events.scan(State.init(), reducer.function).collect { state.send(it) }
}
}
fun onEvent(event: Event) = scope.launch { channel.send(event) }
fun state(): Flow<State> = state.asFlow()
}
I guess it could be improved. Are there any inherent problems to this implementation? Thanks a lot, in advance 💥.Etienne
02/07/2020, 3:00 PMSTATE
typesInteractor
class.Ahmed Ibrahim
02/07/2020, 3:11 PMStateReducer
taking a suspend
lambda, as that would introduce the possibility of performing side effects inside it (e.g Network Requests), which IMO invalidates the purpose of reducers, that are known to be pure functions that takes an Input and gives an Output.Etienne
02/07/2020, 3:12 PMAhmed Ibrahim
02/07/2020, 3:18 PMEtienne
02/07/2020, 3:18 PMubu
02/07/2020, 4:40 PMEtienne
02/11/2020, 4:33 PMchannel
in your 2nd sampleubu
02/26/2020, 7:33 AM