A library that provide an opinionated way to create Android app with MVI pattern. It supports React's-ish time travel debugging and diff render.
In your root build.gradle
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
In your module build.gradle
dependencies {
final karmaVersion = "1.3.0"
implementation "com.github.esafirm.karma:karma-core:$karmaVersion"
implementation "com.github.esafirm.karma:karma-renderer:$karmaVersion"
implementation "com.github.esafirm.karma:karma-timetravel:$karmaVersion"
implementation "com.github.esafirm.karma:karma-timetravel-dashboard:$karmaVersion"
}
The library currently separated into four modules:
- Core
- Renderer
- Time Travel
- Time Travel Dashboard
If we create a dependency tree, it would look like this:
core
___/\___
/ \
renderer time travel
\
time travel dashboard
core
module is standalonerenderer
needs coretime travel
needs coretime travel dasboard
needs core & time travel
Karma core introduce how you can create an MVI-ish application with minimal setup.
To create a screen, what you need is:
- A State
- A Presenter
- An Android Component to bind it all together
State refer to a view state. For example we have this simple state
data class SimpleScreenState(
val textLineOne: String,
val textLineTwo: String
)
Presenter is a place that we call all our action that change a state.
class SimplePresenter : UiPresenter<SimpleScreenState>(action) {
override fun initialState() = SimpleScreenState("a", "b")
// We change textLineOne and retain our current textLineTwo
fun changeLineOne(text: String) = setState {
copy(textLineOne = text)
}
}
To initialize Karma, you need to now os how to bind all the component together
fun <S, P : KarmaPresenter<S>> bind(
lifecycleOwner: LifecycleOwner,
viewModelStoreOwner: ViewModelStoreOwner,
presenterCreator: () -> P,
render: (S, P) -> Unit
)
And this is an example of Karma.bind
called in AppCompatActivity
Karma.bind(
lifecycleOwner = this,
viewModelStoreOwner = this,
presenter = { SimplePresenter() },
render = { state, presenter ->
// do render
}
)
Or, we could use the extension function to make it more simple
bind(
presenter = { SimplePresenter() },
render = renderer::render
)
Renderer enable us to control on how we can render state
renderer<State, Presenter> {
init {
// This will only called once.
// Could be used to intialize some views or setup the listener
}
diff(State::data) {
// This will only be called when state.data is changed
}
event(State::event) {
// This will use special state called SingleEvent<E> that have internal flag
// This can be used for notification state (ex: show toast)
}
always {
// This will be always called
}
}
TBD
TBD
You can find complete usage of Karma in :samples:app
module
MIT @ Esa Firman