MVICore¶
What's this?¶
MVICore is a modern, Kotlin-based MVI framework:
- Scaling with complexity: operate with a single Reducer if needed, with the option of having the full power of additional components to handle more complex cases
- Event handling: A solution to handling events that you don’t want to store in the state
- Reactive component binding: A super simple API to bind your reactive endpoints to each other with automatic lifecycle handling
- Custom Middlewares: for every single component in the system, with flexible configuration options
- Logger: An out-of-the-box logger Middleware
- Time Travel Debugger: for ALL of your reactive components (not just your state machine!) with UI controls for recording and playback
The big picture¶
1. Create your state machine¶
class SimpleFeature : ReducerFeature<Wish, State, Nothing>(
initialState = State(),
reducer = ReducerImpl()
) {
// Define your immutable state as a Kotlin data class
data class State(
val counter: Int = 0
)
// Define the ways it could be affected
sealed class Wish {
object IncreaseCounter : Wish()
data class MultiplyBy(val value: Int) : Wish()
}
// Define your reducer
class ReducerImpl : Reducer<State, Wish> {
override fun invoke(state: State, wish: Wish): State =
// Leverage the power of exhaustive when over Kotlin sealed classes
when (wish) {
// Create the next state based on the current one
IncreaseCounter -> state.copy(
counter = state.counter + 1
)
// Create the next state based on the current one
is MultiplyBy -> state.copy(
counter = state.counter * wish.value
)
}
}
}
Note
Feature
has additional components to solve problems like side-effects, events, initialisation, internal jobs in a standardised way. For a full list check Features section to see what's possible.
2. Your state machine is reactive¶
val feature = SimpleFeature()
// Now you can observe and subscribe to its state changes:
Observable.wrap(feature).subscribe { state -> TODO() }
// And it's also a Consumer of Wishes. Trigger some state changes:
Observable.just(Wish.IncreaseCounter).subscribe(feature)
Actually, don't use it the above way! We can do so much better:
3. Use the Binder¶
For connecting your reactive components. Comes with automatic lifecycle handling and invoking transformations:
val binder = Binder(lifecycle)
binder.bind(view to feature using ViewEventToWish)
binder.bind(feature to view using StateToViewModel)
Download¶
Available through jitpack.
Add the maven repo to your root build.gradle
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
Add the dependencies:
-
Framework:
implementation 'com.github.badoo.mvicore:mvicore:{latest-version}'
-
Helper classes for Android:
implementation 'com.github.badoo.mvicore:mvicore-android:{latest-version}'
-
ModelWatcher for efficient view updates
implementation 'com.github.badoo.mvicore:mvicore-diff:{latest-version}'
-
Time Travel Debugger controls in a DebugDrawer module (You need to add the dependencies to DebugDrawer and configure it yourself before you can use this):
implementation 'com.github.badoo.mvicore:mvicore-debugdrawer:{latest-version}'