How to implement Redux in Kotlin Part 1: the basics

Liviu Coman
The Startup
Published in
6 min readJul 14, 2019

During my past two articles we saw how we can look at views as a function of state and how we can decouple our application’s business logic from the views themselves in order to create more modular and SOLID code.

Throughout those articles, I mentioned Redux quite a lot — and how it inspired me to think about views as local stores of some state. That’s no accident. In the past few years, Redux has been fundamental about changing the way I think about big front-end systems and has been my default tool for making sense and simplifying complicated problems.

The beauty of Redux is that it solves one problem really well, and it does so by being dead simple.

The problem: how do you organise and make sense of your app’s state and business logic?

The solution: enforce a strict unidirectional data flow and a single source of truth for all your app’s state.

For all its simplicity though, a lot of Redux tutorials can be daunting, especially if you’re used to traditional front end patterns like MVVM, MVP or MVC. On top of all the new concepts you have to familiarise yourself with, like Store, Action or Reducer, by far the hardest thing is to get in the mindset of unidirectional data flow.

This is what this two part series aims to explore. First, we’ll create all the building blocks for applying the Redux pattern in the classic counter app. We won’t stop there, though. Redux is meant to simplify complex systems. The kinds that both junior and experienced engineers find hard getting their heads around. So in the second part we’ll apply Redux to a real life example: the contacts app we developed in the first two articles.

Building blocks

Let’s begin by getting an idea of the simple counter app we want to build:

and the code we start out with:

We want to get to a point where, using the Redux pattern, we can increment and decrement the counter by using the two buttons available to us.

In order to do that, we can begin with the first fundamental concept in Redux, the State.

In simple terms, State is defined as the overall data and values that make your app work. In the second part of this series we’ll explore more advanced state trees but for now our counter app’s State is just an integer value. We can wrap that value inside a data class and call it our CounterState.

Now we need a way to operate on this State. This is where Redux starts showing its way of thinking. I mentioned earlier that Redux enforces, by design, a unidirectional data flow. What does that mean? To answer that question let us look at how Redux doesn’t want us to change State.

The above is, obviously, code that works. But is has drawbacks, chief amongst them being that we’re letting our click listeners manipulate state directly and also dictate business logic by incrementing and decrementing values.

That makes the whole Activity harder to test and adds additional responsibilities to our code.

Redux solves this by introducing a new concept, called the Action.

An Action is an intent we use in Redux to signal a state change. It’s an indirect way of specifying how we want our whole system to change. For our simple example, we need three CounterActions:

So our code should become something similar to this:

Of course, we don’t have all the building blocks in place right now. What does it mean to dispatch an Action? And how does anything change on screen when we do that?

Before we can answer those questions, we need to introduce another concept, called the Reducer.

Mutating state

Okay, so we’ve talked about State and we’ve talked about Actions. Clearly, those two entities need to be linked somehow. The way we link them is through a Reducer. A Reducer is simply a pure function that takes in an old State and an Action and returns a new State. Reducers are the worker bees of Redux. They are the only way through which we change State in our system and thus drive all the business logic of our app. There should be no exceptions to this rule.

We can define a generic Reducer as follows:

And from that we can create a CounterStateReducer to:

  • create a new default CounterState when the Init action passes through
  • create a new incremented CounterState when the Increment action passes through
  • create a new decremented CounterState when the Decrement action passes through

As promised, we’ve moved all of the business logic and all of the state mutation associated with our CounterActivity into this specialised entity we’ve implemented as a free function. Not only have we separated concerns pretty well, but we can unit test this in a straight forward manner.

The power to unit test complex pieces of business logic in a simple way is one of the things I like about Redux.

Okay — we’ve learned about State, Actions and Reducers — how do all of these fit together? What binds them? The answer is the last piece of the Redux puzzle, the Store.

Tying it all together

First of all, what is a Store in Redux?

In short, it’s the single source of truth for your whole application. Meaning:

  • it alone holds a reference to the whole application State
  • it alone can change State when an Action gets dispatched through it
  • and it alone notifies subscribers when there’s been a State change

Following this definition and looking from the outside, we’ll need a way to dispatch Actions to the Store and a way to register subscribers.

Dispatching is clear. Let’s think about Store subscribers. They need to be an entity that can be injected with the most up to date State. The simplest Subscriber is just a function that takes in State and returns Unit.

and thus our Store definition transitions to this, where we’ve also bound it to a generic parameter of type State.

From here we can create the actual concrete implementation of Store, which we’ll name DefaultStore, and start filling in the details.

Adding or removing subscribers is pretty simple and we can start with that. We’ll need a data structure to hold them all. A Set or List will do just fine.

In order to dispatch actions we’ll first need to create an internal reference to our state and initialise it with an injected value:

Once we’ve done that, we can use a Reducer to implement the dispatch method. Here’s how that looks like:

And this is how the whole DefaultStore looks like:

We’ve built a fully functioning Store in under 25 lines of code. That’s pretty amazing. Now it’s time to use it.

Usage

First, we can put our Store in a Dependency Injection system as a singleton. This is important, because we only want one Store per app.

We can obviously use Dagger2 or any other DI system that’s available to us.

Next we can replace the decrement and increment button click listeners with calls to dispatch actions to the Store:

and finally we can subscribe to the Store and render the screen each time the State changes:

With this setup we can clearly see the unidirectional data flow that Redux prefers. Any change we want to effect on the state we do so by dispatching an Action to the Store. Anything we want to render on screen only happens when the Store tells us State has changed, via the Subscriber.

To sum up, let’s look at all the code we’ve written so far:

A fully functioning Redux-powered app in less than 100 lines of code!

This article is one of a multi-part series exploring State, UI and Redux and how we can leverage knowledge of these topics to write more modular and testable code.

--

--

Liviu Coman
The Startup

Enthusiast of all things mobile and functional. Building a safer internet for kids as Engineering Lead @SuperAwesome.