Need help with reductor?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

457 Stars 24 Forks Apache License 2.0 150 Commits 10 Opened issues


Redux for Android. Predictable state container library for Java/Android

Services available


Need anything else?

Contributors list

No Data

Reductor: Redux for Android

Download Android Arsenal Build Status Codecov

Redux inspired predictable state container library for Java/Android.

Reductor can help you make your state mutations easier to read, write and reason about. It leverages annotation processing to validate correctness and generate boilerplate code at compile time, allowing you to express state reducers in a concise way as pure java functions. As Redux it's based on three principles (from Redux documentation):

  • Single source of truth
  • State is read-only
  • Changes are made with pure functions

Key point of this implementation was to keep the original concept of Redux to reuse most of existing approaches but provide nice Java API and preserve types as much as possible.

Reductor advantages:

  • Lightweight
  • Do not use reflection
  • Follow implementation of Redux
  • Allow to compose a state with @CombinedState
  • Allow to define Reducers in typesafe way with @AutoReducer

Note: This version is still under development, API may change till version 1.0

Blog posts


repositories {

dependencies { compile 'com.yheriatovych:reductor:x.x.x' apt 'com.yheriatovych:reductor-processor:x.x.x' }

Apt dependency on

is only necessary if you want to use features as @CombinedState and @AutoReducer

Getting started

First example: Simple counter

//state will be just integer
//define actions
interface CounterActions {
    String ADD = "ADD";

Action increment();

Action add(int value);


//Define reducer
@AutoReducer abstract class CounterReducer implements Reducer { @AutoReducer.InitialState int initialState() { return 0; }

        value = CounterActions.INCREMENT,
        from = CounterActions.class)
int increment(int state) {
    return state + 1;

        value = CounterActions.ADD,
        from = CounterActions.class)
int add(int state, int value) {
    return state + value;

public static CounterReducer create() {
    return new CounterReducerImpl(); //Note: usage of generated class


//Now you can create store and dispatch some actions public static void main(String[] args) { //Now you can create store and dispatch some actions Store counterStore = Store.create(CounterReducer.create());

//you can access state anytime with Store.getState()
System.out.println(counterStore.getState());             //print 0  

//no need to implement CounterActions, we can do it for you
CounterActions actions = Actions.from(CounterActions.class);

//you can subscribe to state changes 
counterStore.subscribe(state -> System.out.println(state));

counterStore.dispatch(actions.increment()); //print 1  

counterStore.dispatch(actions.increment()); //print 2  

counterStore.dispatch(actions.add(5));      //print 7



Main point of interaction with state is

is actually container for your state.

There are two ways of accessing the state inside the

: * Call
to get the state
holds at the moment * Call
store.subscribe(state -> doSomething(state))
. Calling subscribe will notify provided listener every time state changes

And only one way how to change the state: * Call

to deliver and process it by corresponding

Advanced use

Combine Reducers

For one store you need one Reducer, however usually state is complex and it's good practice to separate logic to separate it into multiple reducers.

You can do it manually by creating Reducer which delegate reducing logic to 'smaller' reducers

 //Complex state
 class Todo {
     List items;
     String searchQuery;

 public Todo(List<string> items, String searchQuery) {
     this.items = items;
     this.searchQuery = searchQuery;


//define reducer per sub-states class ItemsReducer implements Reducer> { @Override public List reduce(List strings, Action action) {...} }

class QueryReducer implements Reducer { @Override public String reduce(String filter, Action action) {...} }

//define combined reducer class TodoReducer implements Reducer { private ItemsReducer itemsReducer = new ItemsReducer(); private QueryReducer queryReducer = new QueryReducer();

 public Todo reduce(Todo todo, Action action) {
     //composing new state based on sub-reducers
     return new Todo(
             itemsReducer.reduce(todo.items, action),
             queryReducer.reduce(todo.searchQuery, action)


This approach works but requires developer to write a bit of boilerplate of dispatching sub-states to sub-reducers. That's why Reductor can do boring work for you. Just use

to generate corresponding
//Complex state
interface Todo {
    List items();
    String searchQuery();

//define reducer per sub-states class ItemsReducer implements Reducer> { @Override public List reduce(List strings, Action action) {return null;} }

class QueryReducer implements Reducer { @Override public String reduce(String filter, Action action) {return null;} }

public static void main(String[] args) { //Using generated TodoReducer Reducer todoReducer = TodoReducer.builder() .itemsReducer(new ItemsReducer()) .searchQueryReducer(new QueryReducer()) .build(); }

Note that

annotated class needs to be interface or
abstract class.


Consider following

which manages

Note: PCollections library is used as implementation of persistent collections.

class ItemsReducer implements Reducer> {
    public List reduce(List items, Action action) {
        switch (action.type) {
            case "ADD_ITEM": {
                String value = (String) action.value;
                return TreePVector.from(items)
            case "REMOVE_ITEM": {
                String value = (String) action.value;
                return TreePVector.from(items)
            case "REMOVE_BY_INDEX": {
                int index = (int) action.value;
                return TreePVector.from(items)
                return items;

This way of writing reducers is canonical but have some disadvantages: * Boilerplate code for switch statement * Unsafe casting

to expected type

That's why Reductor has

to help developer by generating
//AutoReducer annotated class should be abstract class which implement Reducer interface
abstract class ItemsReducer implements Reducer> {

//Each 'handler' should be annotated with @AutoReducer.Action
List<string> add(List<string> state, String value) {
    return TreePVector.from(state)

List<string> remove(List<string> state, String value) {
    return TreePVector.from(state)

List<string> removeByIndex(List<string> state, int index) {
    return TreePVector.from(state)

static ItemsReducer create() {
    //Note: ItemsReducerImpl is generated class
    return new ItemsReducerImpl();


annotation supports declaring action creator. That will check at compile time if there is such action creator with the same parameters. Example: interface, usage.

Defining action creators

In Reductor, an action is represented with class

. It contains two fields: - type: defines action id or name. - values: arrays of arbitrary objects that can be added as payload.

You can create this Actions ad-hoc, just before dispatching. However usually it's more natural and readable way to encapsulate it into "Action creator" function, like:

Action addItemToCart(int itemId, String name, int price) {
    return Action.create("CART_ADD_ITEM", itemId, name, price);

But that's not fun to write code for just bundling arguments inside. That's why Reductor lets you define all your action creators as just interface functions.

interface CartActions{
    Action addItem(int itemId, String name, int price);

Action removeItem(int itemId);


Reductor will generate implementation. To get the instance just call

CartActions cartActions = Actions.from(CartActions.class);
store.dispatch(cartActions.addItem(42, "Phone", 350));

The information about actions structure is also used to check if

reducer actions have the same structure and name.


  • Support Kotlin data classes to use with
  • Better documentation
  • Minimize usage of generated code from a source code
  • Add more example:
    • Async actions
    • Time-traveling
    • Dispatching custom actions with Middleware
    • Using Rx with store

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.