Getting Started
This page outlines the various Mobius.kt components in their simplest form, view the reference pages for additional details.
Creating a Loop
(See Reference > Mobius Loop)
Let's create a simple Counter to see the various Mobius.kt components.
The first step in creating a loop is to define our Model
, Event
s, and Effect
s.
Model
(See Reference > Model)
For simplicity, our Model will just be an Int
:
Events
(See Reference > Event)
Next we need Events to update our model:
Effects
(See Reference > Effect)
Effects will be covered later, so we'll just use Unit
for now:
Update Function
(See Reference > Update)
Now that we have a model and some events to handle, let's add some counter logic in an Update
function.
val update = Update<Model, Event, Effect> { model, event ->
when (event) {
Event.ADD -> next(model + 1)
Event.SUB -> next((model - 1).coerceAtLeast(0))
Event.RESET -> next(0)
}
}
Effect Handler
(See Reference > Effect Handler)
This example doesn't use any Effects, so we'll just define a no-op Effect Handler for now.
no-op effect handler (Click to expand)
Starting the Loop
That's it! We've defined everything we need to construct a MobiusLoop
.
The last thing we need is to construct a MobiusLoop
instance with out components.
Here are two approaches to create the MobiusLoop
, send it events, and handle model changes.
Manual
Using Mobius.loop
, we create a MobiusLoop.Factory
which can create a running MobiusLoop
.
val loopFactory: MobiusLoop.Factory = Mobius.loop(update, effectHandler)
val loop: MobiusLoop = loopFactory.startFrom(0)
This is the simplest form of a MobiusLoop
, it only has two states: running
and disposed
.
Manual Loop Example
// Attach an Observer to handle model updates
val observerRef: Disposable = loop.observer { model ->
println("Model: $model")
}
// Send some events to our loop
loop.dispatchEvent(Event.ADD) // Model: 1
loop.dispatchEvent(Event.ADD) // Model: 2
loop.dispatchEvent(Event.SUB) // Model: 1
loop.dispatchEvent(Event.RESET) // Model: 0
loop.dispatchEvent(Event.SUB) // Model: 0
// Cleanup our resources
loop.dispose()
Controller
Alternatively a loop can be managed with a MobiusLoop.Controller
, giving the loop a flexible lifecycle.
This example includes some imaginary UI details for demonstration, this could apply to Android UI, iOS UIKit, or any
other UI framework.
Loop Controller Example
// Create a controller that lives of our UI container
val loopController = Mobius.controller(loopFactory, 0)
// When our UI container is created, connect our buttons and outputs
loopController.connect { output ->
buttonAdd.onClick { output.accept(Event.ADD) }
buttonSub.onClick { output.accept(Event.SUB) }
buttonReset.onClick { output.accept(Event.RESET) }
object : Consumer<Model> {
override fun accept(value: Model) {
counterLabel.text = value.toString()
}
override fun dispose() {
buttonAdd.removeOnClick()
buttonSub.removeOnClick()
buttonReset.removeOnClick()
}
}
}
// When the UI is presented: start the loop
loopController.start()
// When we click our buttons, the counterLabel will be updated with the new model
// When the UI is no longer presented: Stop the loop to prevent UI updates or events
loopController.stop()
// Loop could be started with `loopController.start()` when the UI is presented again
// When the UI is destroyed: Dispose the loop and release references to UI elements
loopController.disconnect()