Mobius Tutorial for Android: Getting Started

Learn about Mobius, a functional reactive framework for managing state evolution and side effects and see how to connect it to your Android UIs. By Massimo Carli.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

The Mobius Workflow

In the previous section, you learned that the main concepts in Mobius are:

  • Models
  • Events
  • Effects
  • 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:

  1. Model or MoFlow (Short for “Mobius Flow”)
  2. Describe
  3. Plan
  4. Build

It’s interesting now to see each of these in detail in the context of the app.

Modeling Your App

Models in Mobius can represent different concepts like:

  • The current state of the app.
  • Events generated by a user action.
  • External events.
  • Events resulting from a side effect’s execution.

Usually, the steps are the following:

  • Define external events.
  • Capture user interactions.
  • Define effects.
  • Define effects feedback events.

Defining External Events

In your case, the app doesn’t handle any external events, but it could. Imagine, for instance, if the game was multiplayer and you received an invitation from a friend. In that case, the app would display a dialog so you could accept or decline the invitation.

To track all the items Mobius needs to implement, you create a table like the following. This is the MoFlow table.

The initial MoFlow

The initial MoFlow

The initial MoFlow

Because you don’t have external events, the table is initially empty. No problem! You’ll deal with user interactions next.

Capturing User Interactions

User interactions represent the possible events you need to handle when the user interacts with the app. In your case, you can start entering the name of the events related to navigation, which will allow you to move from the menu screen to credits or the game screen. When you navigate, you might also need to return to the previews screen. Upon adding these events, the MoFlow table becomes the following:

Navigation Events

MoFlow chart with navigation events

Navigation Events

As you’ll see later, when you select PLAY, you’ll display a screen like the following with all the cards covered:

The Game Screen

The Game Screen with 20 cards

The Game Screen

The game consists of flipping the cards in pairs and trying to find cards with the same value. If the values of the cards are the same, they remain flipped, changing their color. If the values are different, the program flips them back, and the game continues. The game ends when all the cards remain flipped. Every time the player flips a card, the number of moves increases by one. When the player finds a pair, the number of moves decreases by two. The goal is to find all the pairs in the fewest moves.

Understanding how the game works allows you to define new events. In this case, only one is related to user interaction, which you call FlipCard. As you’ll see very soon, the game generates other types of events when you flip a pair of cards, depending on whether you’ve found a matching pair.

At this point, the MoFlow table looks like this:

Game Events

MoFlow table of game events with FlipCard added

Game Events

Here, you have a clear idea of all the actions users can do and how the app should handle them.

Defining Effects

Now, you need to think about the effects the previous events can generate. When players flip a pair of cards, the game needs to understand what to do. If the cards are different, the game waits for a few seconds and flips the cards back to cover them. You can model this behavior with a DelayedWrongPair effect. In the same way, if the cards contain the same value, the game waits some time and sets the pair as found. You model this using a DelayedCompletedPair effect. In this case, the game also needs to check if all the pairs have been found and, if so, end the game. You can model this with the GameFinished effect.

As you’ll see later, you also need an ExitApplication effect to exit from the app when you go back to the initial menu.

With these effects, the MoFlow table becomes:

Game Effects

MoFlow table with Game Effects added

Game Effects

Note: Modeling network requests to an effect is quite intuitive. The case in this tutorial is different since an effect could be similar to an event. As a rule of thumb, you can think of an effect as a way to ask your app to run some task and then send another event to notify its completion. For instance, the GameFinished effect just makes the game wait and then send, as you’ll see later, an EndGame event to signal the end of the game.

Defining Your Model

In this step, you need to define the model as a representation of your app’s view. In the app for this tutorial, you basically need to handle two different aspects:

  1. Navigation
  2. Game State

To handle the navigation, you just need a property of the model that tells the UI what composable function to execute. The game’s state consists of which cards are available as well as which ones and how many of them the player has matched. If the app is big, you can decide to implement different models. In this case, you just have a single model that you implement in the CardGameModel class.

Now, the MoFlow table becomes:

The model for the app

MoFlow table with an entry in Models

The model for the app

As mentioned before, the view of your app will use all the data in the model to render the information it needs.

Defining Effects Feedback Events

Now, you have CardGameModel to keep track of the app’s current state. When the user flips a card, you generate a FlipCard event. If the card you flip is the first, you just need to update the model to update the UI. If the card you flip is the second, the system needs to check if the two cards have the same value. When the cards match, you generate a DelayedCompletedPair effect, which waits a few milliseconds and then flips the cards to a different color. If the cards have different values, you generate a DelayedWrongPair, which also waits a few milliseconds and then flips the cards back.

How do the effects notify the system that some time has elapsed and the cards need to change their state? Each effect has the option to notify its completion by sending an event called an effect feedback event.

In this app, when the cards are equal, the DelayedCompletedPair effect will notify its completion by sending a SetPairAsDone event. If the cards are different, the DelayedWrongPair effect will notify its completion by sending a RestorePair event. Finally, the GameFinished effect will send an EndGame to notify the completion of the game.

These are events, so the last version of the MoFlow for the app is the following:

Feedback Events

MoFlow table showing feedback events

Feedback Events