Taming state in Android with Elm Architecture and Kotlin, Part 1

Developing Android apps with MVP/MVVM/MVC patterns helps you separate your business logic from interactions with the view layer and Android framework dependent classes. Writing unit tests for business logic and refactoring is also easier.
But when the app’s codebase grows, presenters become more and more bloated, with lots of callbacks for async work and local variables for mutating state in different places. Flow of data and logic become tricky and especially hard to test.
In this series of three blog posts, I will show how we can manage complex UI logic with The Elm Architecture.
In Part 1 I will describe basic terms and concepts of Elm Architecture
In Part 2 I will show the implementation of the Elm Architecture in Android and how we can use it with MVP pattern. If you are familiar with Elm, you can skip the first part, and go straight to Part 2.
In Part 3 we will see how we can integrate Elm Architecture with Clean Architecture and discuss how to deal with navigation and how to implement time-travel.
Also, it’s quite noticeable, that there are a lot of similar ideas in the wild, like what Jake Wharton described in his talk Managing State with RxJava or Model-View-Intent architecture by Hannes Dorfmann, and also great presentation by Christina Lee and Brandon Kase
The Elm Architecture
So, what is Elm? And what is more interesting, The Elm Architecture?
Elm is a statically typed, pure functional programming language, which is compiled to Javascript and runs in Web Browser.
The Elm Architecture(TEA) is an approach to building web applications, with several key aspects:
- Unidirectional dataflow
- Immutable state
- Managed side effects
If you are familiar with javascript libraries like Redux or Cycle.js, you will find many similar concepts and even term names, and this is not a coincidence, because Redux state management pattern is actually inspired by the Elm Architecture

The core concept of TEA really boils down to only three core types (or classes in OOP) and three functions:
Model (aka State in Redux) — this is the type for describing the state of your app or screen. From now on, I will refer it as State, because this better expresses what it is used for, as the term Model has so many definitions and has became very bloated.
Msg (short for Message, aka Actions in Redux) — base type for all events happening during interaction with UI (such as button click, text inputs, etc)
Cmd (short for Command) — type for side-effects. If you create Cmd, that means you want to execute a particular side effect (http request or other blocking IO operation). When executed, the command will return new Msg with resulting data.
Function Update (aka reduce in Redux) — function Update takes Msg and State as input, and returns a pair of two values — new State and Cmd, or simply speaking, what side effect you want to execute for incoming Msg. The main aspect of this function is that it is a pure function. That means there must be no side effects inside this function.
Function View (aka render in Redux) — takes State as an input, and renders view (HTML in case of Elm) in declarative manner. I will name this function in Redux manner, as the term View is already heavily used in Android Framework.
Function Init — here we define our initial values for State, and, if necessary, return first Cmd, for initial HTTP request for example.
And this is basically all you need to know about The Elm Architecture!
Don’t be confused by the ‘architecture’ word. As an Android dev you can see TEA as Design Pattern which can be implemented in presentation layer, or simply speaking in your presenter
The best way to learn new things is to examine them by example. Let’s take a look into at a simple login screen, with input fields for login and password, and a button for sending http request. The following code snippets will be in Kotlin language, as this post is primarily addressed to Android Developers.
Why Kotlin?
Kotlin has several very powerful constructs, built in it’s type system.
Sealed classes (or enum on steroids). Sealed class is a somewhat close implementation of Union Types from functional languages. They allow us to build class hierarchies in a very clear and concise way. Moreover, with sealed class you gain extra power of pattern matching with when expressions.
Data classes. Data classes allow us to create classes for expressing Msg and Cmd types with one liners, and, again, use the power of pattern matching.
TEA Concepts in practice
Let’s go through the key aspects of TEA:
1. Immutable state
We keep our application state in one immutable class and we cannot mutate it.
data class LoginState(val login : String, val password : String, val auth : Boolean = false, val isLoading : Boolean = false) : State()
If we want to change some value in state, we create new state
loginState.copy(login = "name")
All changes happen in function Update. This concept is often referred to as Single Source of Truth, meaning that we know, that if the state changes, this change happens only in one place.
2. Unidirectional Data Flow
For example, a user types his username and password, and we need to express these interactions in terms of TEA.
data class LoginInput(val login : String) : Msg()
data class PasswordInput(val password : String) : Msg()
The messages come from the view, and are forwarded to the Update function
LoginInput(“J”) -> Update(state.copy(login=”J”)) -> Render(state)
LoginInput(“Jo”) -> Update(state.copy(login=”Jo”)) -> Render(state)
…
PasswordInput(“q”) -> Update(state.copy(password=”q”)) -> Render(state)
PasswordInput(“qw”) -> Update(state.copy(password=”qw”)) -> Render(state)
…
You can see that the data flow follows a cycle, going from the view (or from the outside world in the case of side effects) to the Update function, and then to the Render function.
3. Managed side effects
One of the greatest things in Elm(and hence in TEA) is the runtime’s management of side effects. If you need to do some asynchronous task, you just tell the Elm Runtime what to do, and what Msg to return with the result of this task. The Elm Runtime will do all the work and will return result to function Update.
How can we achieve this behavior in the Android multithreaded environment?
This is where RxJava comes in handy. More of that I will discuss in the next post. For now, I’ll just show how the cycle looks with a side effect:
data class AuthClick : Msg()
data class AuthResult(val token: String?, val error : Throwable?) : Msg()data class Auth(val login: String, val password: String) : Cmd()
AuthClick() -> Update(state.copy(loading=true)) -> Render(state) -> (execute Auth) -> AuthResult(token) -> Update(state.copy(loading=false, token=authResult.token)
RxJava’s declarative style of controlling multithreading helps here!
Update 02.04.2019
If you liked the ideas of Elm Architecture and want to try it out in Android app, we release it as library RxElm. You can find it on github.
You are very welcome to try it out, file an issues, and submit PRs ;-)
To be continued...
In the next post, I will show how we can implement TEA pattern in a simple Android app with the Kotlin programming language and RxJava.
Resources for further learning:
- Official guide into The Elm Architecture
- Great explanation with examples and illustrations
- Principles of Redux
- Great presentation by Jake Wharton on managing state with RxJava
- Hannes Dorfmann’s blog post series on MVI
- Approach for implementing Cycle.js in Kotlin by Cristina Lee and Brandon Kase