Sep 19, 2016
The article is part of series aboutReductor library –Redux implementation for Android.
InPart 0 we made simple TODO application using immutable state and self-written state container. We found that mutable data structures can lead to uncontrolled data changes that could be the root of the unpredictable behaviour.After some code changes, we showed that mutations can be avoided by keeping only one immutable object with mutable reference.
In this article, we will cover how Redux can help with this problem and reimplement our application using Reductor.
Here is our TodoStore (class that manage the state) we end up with last time:
This “Store” pattern looks nice for a particular case.It can help to isolate mutations and make state change testable.But how can we reuse it and decrease the amount of boilerplate code needed every time we want to add and manage any new dataset.And that’s whereRedux andReductor will help us.
Reductor is a minimalistic library that reimplements Redux (Javascript library for state management) in Java. It was created with Android in mind but can be used in any Java application. The main idea is to embrace the power of immutable data structures and functional composition to provide a sophisticated approach to developing rich client-side applications.
Here is how Redux works (fromhere):

The whole idea is really simple:
Store object holds and maintains the stateStoreStore computenew state using pure functionf(s, a) (calledreducer)Store replace current state withnew stateAnd that’s it! Though it looks elementary this approach is really powerful.To illustrate this will reimplement our TODO application using this approach with Reductor.But don’t worry, there will be not so many changes from our original example.
So, let’s start!
First of all, we need to add Reductor as a dependency.FollowInstallation for more details.
When added,Store,Reducer andAction classes should be available in the classpath.
Before writing any code, we need to choose how our state should look like. As we only need to store a list ofTodoItem, for our simple example that will beList<TodoItem>.
You may wonder: What if we need to store not a single object but a few of them? Can I store 2, 3 or 42 objects with different types inStore? – Yes and No.
Store is designed to store one particular state object of the arbitrary type. However what we can do is to compose several “substates” into one object. We will talk about how to do this in the next article.
As said before, wemutate change our state by dispatching actions.Actions are dispatched byactioin type – string identifier that denotes the action which will be applied to the state.
We can define them just as constants.
However, to handle an action we need a bit more information than just a name.That’s why in ReductorAction is predefined type with two fields:
type is String action type we just defined abovevalue is payload you can attach to an action if necessaryAdditionally, we can defineaction creators – helper functions to create actions.This step is not required but is strongly suggested to keep code clean.
Basically, that’s our contract. We defined all possible operations we can perform with a state.
As we defined actions, we need to define the way we will react to them.To do this we need to implementReducer interface.
So the idea is really simple behind this signature.You define a pure function (method)reduce that will apply an action to a state to compute a new state.
Let’s check what we have here:
reduce that takes our state and action. This method does a few things:action.typeaction.type is unknown for this Reducer)We defined our state reducer. As you can see we still keep the principle of using only pure functions to compute a new state.That means that this class is still well testable.
Note: our implementation of
reducemethod contain some unsafe operations like type casting. Do not worry about this boilerplate code now, as we will get rid of it using annotations later.
After we created our Reducer, we can create our state container –Store.
We do it by calling static methodStore.create
Store<List<TodoItem>>todoStore=Store.create(newTodoReducer(),Collections.emptyList());Store.create takes at least two arguments:
Once created,Store API is really simple:
getState() is useddispatch(action)StateChangeListener to be notified when state updates by callingsubscribe methodHaving this in mind we can rewrite our MainActivity:
As you can see changes are minimal. The structure is the same.The main difference is action dispatching.
As you can see, to create state container we only need to define two things: Reducer and actions.However, as I mentioned before, there is a bit of ‘untyped’ code in reducer and in action creators.This is because we want to pack different data types into theAction.value. Here is our Reducer again:
But actually, if we decompose the logic ofreduce method into sub-methods per each action (as we did before), the logic ofreduce becomes really straightforward.
So why do we need to write it every time? Let computer do it for us! And that is why Reductor containsMagic Annotation processor.
First, we need to ensure thatreductor-processor dependency is added. FollowInstallation for more information.
Then we need to simplifyTodoReducer as followed:
What did we do here?:
reduce method in childTodoReducerImpl class.@AutoReducer annotation.@AutoReducer.Action and provided Action type as annotation valuecreate to instantiate generated classNice! Our code is clean and fancy. All the boilerplate is written by a machine.But that’s only the half of the story. What about action creators? Reductor generates them too!
This full generated class out of our Reducer:
Now our actions and Reducer are type-safe, even though all of them are dispatched asAction objects.
In this article, we used Reductor library to implement our TODO example app. The main interaction point isStore object which use user-definedReducer to change the state.
Reductor library was designed to bring Redux experience into the Java and Android world without sacrificing type safety.That’s why there are such features as auto-generated@AutoReducer.
In next article, we will cover how to compose a state and reducers with Reductor.
Stay tuned.To be continued…