I'm Building Taskito
I'm Building Taskito
Get it on Google Play Download on the App Store

Write your own Redux implementation in Kotlin


In the previous articles, I talked about Redux architecture and the Role of middleware in Redux. There’s no better way to learn something than implementing it yourself. We are going to write a very lightweight implementation of Redux architecture in Kotlin which can be used for our android app.

redux logo

Quick Recap

Redux is an architecture for predictable state container and state management. It is inspired from Flux and uses some of its components. Let’s go through the important components of Redux in brief.

State

State in Redux describes your app’s state at any given time. State is an immutable object which holds the information about the ‘current state’ of the app.

Action

Action is an object which describes a change in the state. Action may have some payload which is used to update the state.

Reducer

Reducer is a pure function which changes the app state from State A to State B for a given action.

Store

Store is at the center of Redux architecture. A store stores the app state and manages it. Once an action is dispatched, the stores updates the app state with the help of reducers.

Listener

A listener subscribes to the store to receive updates when the app state is updated. In your android app, a typical listener is your Activity, Fragment or View which receives the updated state and renders a new UI.

Middleware

Middleware are essential in Redux architecture to handle side effects which include logging, IO calls, network calls, etc. When an action is dispatched, the store sends the action to the middleware. The middleware does something (api call, etc) and updates the action and sends it back to the store.

For more details about the components of Redux, I would recommend that you check out the previous articles in the series.

Now that we are familiar with Redux, let’s start writing our own implementation.

Implement Redux Architecture in Kotlin

Kotlin is a feature rich language which gives it significant advantage over Java. Kotlin is now an official language for Android application development so it make sense to learn more about it and start writing our apps in Kotlin.

Let’s begin by defining our components. For convenience and ease of writing the code, we are going to use Kotlin’s higher order functions to represent some of the components.

In Kotlin, Type aliases provide alternative names for existing types. If the type name is too long you can introduce a different shorter name and use the new one instead. So we are going to use typealias to define Reducer.

Define components

interface Action
typealias Reducer<State> = (State, Action) -> State
typealias Subscription<State> = (State) -> Unit

interface Store<State> {
  fun getState(state: State)
  fun dispatch(action: Action)
  fun subscribe(subscription: Subscription)
  fun unsubscribe(subscribe: Subscription)
}

Breakdown

  • Action is just an interface. All our actions will implement the empty interface.
  • Reducer is a pure function. So we use typealias to define a method definition which takes State and Action as input and returns State.
  • Subscription is a typealias for a function which takes State as input parameter. It does not return anything. This will be our render function.
  • We defined an interface for Store with a generic State. In Redux, the whole app will have one instace of store and one App state tree object.

Store implementation

Let’s implement the store.

Breakdown

  • SimpleStore is an abstract class which takes generic State. To initialize a new instance, we pass an initial state and a list of reducers.
  • When a subscription subscribes to the store, we add it to the list of subscriptions and notify it of the current state.
  • When an action is dispatched to the store, the store reduces the current state with the help of reducers and notifies all the subscriptions if there’s a change in the state.

Example

Let’s see an example of how our Redux architecture is going to work. For this example, I have chosen to go with an app that searches for movies. It has a SearchFragment where user can enter a query in the edit text and press a button to begin the search. While, the search is ongoing, the screen will show a spinner and disable the search button. Once the results are available, the screen will hide the spinner and show the list of movies. To keep it simple, we are not going to focus on errors at the moment.

Let’s define a state for the search fragment. The actions associated with it and a reducer.

  • SearchState consists of loading - whether the app is loading results or not, query - query that the user entered, movies - list of movies when the results are loaded.
  • ClearSearch - action is dispatched when user clicks on the clear button.
  • Search - action is dispatched when user clicks on the search button. The action has query as the payload.
  • LoadingSearch - action is dispatched when the api starts loading results. This action will be dispatched by middleware, we’ll implement it later.
  • SearchResultsLoaded - action is dispatched when the api returns results. It has payload of list of movies.
  • reduceSearchState is our reducer function associated with this state and the screen. You may have multiple reducers for one state. Typically, we would write a reducer for that state, eg. SearchState. But here, we have written it for AppState which is main state tree object and it contains SearchState.

As you can see, the reducer is not at all tied with the view and it’s so much easier to write unit tests since it does not even depend on anything Android related.

Let’s define our store which we will use in the app. There should be only one instance of the store so we are going to use a singleton.

  • AppState is our state tree object which contains the whole state of the app.
  • We create a new class AppStore which works with AppState. We provide an initial state and a list of reducers. We include reduceSearchState reducer in the list.

Let’s move on to our View and write a render function.

  • We subscribe to the store in onViewCreated and unsubscribe in onDestroyView.
  • render method takes the state and updates the view.
  • The view sends appropriate actions when user performs some action.

We just created an implementation of Redux architecture in Kotlin. It’s not complete, but we are getting there. Let’s make it look more like Javascript? I never know if this is a good idea or not.

Make the store more closed

Any piece of code can access Store.instance and dispatch some action or get the current state to update something else. This breaks the unidirectional flow of Redux. It would become difficult for debugging so it’s better that we restrict the access to the store and its properties.

  • Dispatch: We want our store be a bit more restrictive and don’t want it to be accessed from some corner of the app. Let’s define Dispatch. It’s a higher order function passed by the store to its subscribers.
  • Unsubscribe: Similarly, we do not want some other part of the code to call unsubscribe() to some other subscriber.
  • We also restrict the code to access the state. If some component wants to access the state, it can subscribe to the store.
typealias Dispatch: = (Action) -> Unit
typealias Subscription<State> = (State, Dispatch) -> Unit
typealias Unsubscribe = () -> Unit

interface Store<State> {
  fun subscribe(subscription: Subscription<State>): Unsubscribe
}
  • We updated the definition of Subscription. The method now takes Dispatch as a parameter which the store will pass to its subscribers.
  • When the view wants to unsubscribe from the store, it can just call Unsubscribe() or Unsubscribe.invoke().
  • To dispatch an action, the component can now use Dispatch(action) or Dispatch.invoke(action).

Implement the new store

We have updated the definition of store and made it more restrictive. Let’s modify the implementation.

With this new definition of the Redux store, we just need to update somethings in our View and render function. The rest of the code does not change.

Update the View

Store.dispatch(action) method is no longer accessible, but the store sends Dispatch function reference when it sends updates regarding the state. So let’s update our render function to have a reference of Dispatch.

  • The fragment keeps a reference to Dispatch and uses it to dispatch actions. It chucks away the reference in onDestroyView().
  • The fragment invokes Unsubscribe in onDestroyView lifecycle method to stop getting events from the store.

Summary

We have a working implementation of Redux architecture. If you see the implementation of Store, it’s very simple and tiny. That is why I like this architecture. It may seem complex at first, but actually it’s really easy once you get your head around it.

If we revisit the flow, the view subscribes to the store for the state updates. The view dispatches actions to the store. The store sends the action and the current state to the reducer. The reducer updates the state if necessary. Once the store receives the updated state, it notifies the view of the update.

We are still missing a crucial component in this implementation - Middleware. Without middleware, we could not make network calls, log some stuff, or do anything on the background thread. We’ll modify our implementation of the store to include Middleware and write an example of a middleware which makes an api call to get the search results.

Redux architecture series

  1. Introduction: Redux architecture for android apps
  2. Middleware: Introduction and implementation
  3. Write your own Redux implementation in Kotlin
  4. Add Middleware to your Redux implementation
  5. Build Battleship Game with Redux - Groundwork
  6. Implement the Battleship gameplay with Redux

Redux architecture and Android

Learn the Redux architecture and implement the clean architecture it in your Android codebase. This series of posts explores the depth of Redux and guides you through implementing the architecture in Kotlin for your android app.

Read next