Mobius Tutorial for Android: Getting Started
- Getting Started
- Understanding Mobius Principles and Concepts
- Mobius Update Function
- The Mobius Workflow
- Modeling Your App
- Defining External Events
- Capturing User Interactions
- Defining Effects
- Defining Your Model
- Defining Effects Feedback Events
- Describing Your App
- Memory Game Update Function
- Implementing Back-Out Functionality
- Handling Effects
- Mobius and Android
- Where to Go From Here?
Choosing the proper architecture for your project is one of the most important steps in the development process. It impacts the maintainability and testability of the software you create and, therefore, its cost. In this tutorial, you’ll learn about Mobius, a unidirectional architecture defined as:
A functional reactive framework for managing state evolution and side-effects, with add-ons for connecting to Android UIs and RxJava Observables. It emphasizes separation of concerns, testability, and isolating stateful parts of the code.
A unidirectional architecture is simple because, as the name says, it allows the data to flow in a single direction from a single source of truth to the UI.
This definition contains some important functional programming concepts you’ll learn in this tutorial, along with:
- What the Mobius loop is and how it works.
- What the Mobius workflow is and how to apply it to a real case.
- How Mobius handles side effects.
- How Mobius works with Android.
You’ll do this by creating a simple Mobius version of the popular game Memory. :]
Download the materials for this tutorial using the Download Materials button at the top or bottom of this page. Open the project using Android Studio 2021.1.1 or above. Here’s the structure of the project:
The project has a very simple structure. In the previous image, you see three main packages:
MobiusModulewith all the main bindings Dagger needs.
- mobius: with the Mobius-specific code for the app. This is where you’ll write most of the code.
- ui: contains the UI code with composable functions and some reusable visual components.
Build and run the app, and after a splash screen, you’ll get the following:
If you click the PLAY or CREDITS buttons, nothing happens because you need to add some code. Before that, you need to understand how Mobius works and what it means to implement an application with this framework.
Understanding Mobius Principles and Concepts
To understand how Mobius works, just think about a typical mobile app. You have some UI that displays information. You usually interact with the UI by pressing buttons or providing input. This triggers actions to access, for instance, a server, fetch some data and show it in the UI. This might look like an overly simplified description of what usually happens, but the reality isn’t far off. You can represent the flow like this:
This image has numerous interesting concepts you can understand by following the flow described earlier.
When you launch your app, you see a UI, which is usually a composition of views, like
Buttons and so on. You can think of a view as a way to represent data. When the data changes, the UI usually changes. This is important because you can think of the data as the UI’s current state. The data you want to display with the UI is usually represented as the model.
Think about the app’s initial screen, which is the main menu. If what you see is the visual representation of a model, the model will probably contain a property that says what the current screen is. Rendering a screen in place of another with Jetpack Compose will simply consist of executing one composable function instead of another based on that property of the model.
As mentioned earlier, the user interacts with the UI by pressing buttons or providing data as input. Mobius models these actions as events. An event is what makes an app interesting. Some events just update the UI, creating a new model to display. Others are more complicated because they trigger a request to the server or access a database. Using the same navigation example, tapping the PLAY or CREDITS buttons will trigger an event that changes the property of the model representing the current state, and so, the UI.
Mobius Update Function
To handle both use cases, Mobius provides an
Update function. It receives the current model and the input event, and returns the new model and an optional description of a side effect. It’s crucial to see how the
Update function lives in the Pure section of the diagram. The
Update function is pure because:
- The new model just depends on the input model/state and event.
- It returns a description of the side effects you need to execute eventually.
This makes the
Update function very easy to test. Not represented in the image is the
Init is a version of
Update that generates the first state and, optionally, the first set of effects to generate.
Now, Mobius sends the new model to the UI and the optional effects to some effect handlers. These are what actually execute the side effects, usually in a background thread. It’s also interesting to see that effect handlers notify the outcome using events and how they go through the same flow you saw earlier for the events from the UI.
Update function is invoked, and a new state/model is created along with other optional side effect descriptions.
Finally, an event source represents a generic component able to generate events even without a specific interaction from the user. Think about the events related to the battery level or your device going offline and then back online again.
The previous architecture is straightforward and gives each component a clear responsibility, as the separation of concerns principle suggests. This also allows the implementation of a process named the Mobius workflow.
The Mobius Workflow
In the previous section, you learned that the main concepts in Mobius are:
- Init function
- Update function
This implies that creating an app with Mobius means defining these same concepts in the domain of the app itself. This leads to a sequence of steps you can follow every time in the design and implementation of your app. The process has a name: the Mobius workflow. It consists of the following four steps:
- Model or MoFlow (Short for “Mobius Flow”)
It’s interesting now to see each of these in detail in the context of the app.