Redux (Kotlin)

A predictable state container for Android apps.

What Redux is and how it works?

You can read more about Redux on the official website.

This library is just Kotlin implementation of Redux architecture with Android compatibility in mind.

Redux Components

Action

You can declare your actions as a sealed classes. Make sure you don’t forget to implement Action interface.

sealed class CounterAction : Action {

    object Increment : CounterAction()

    object Reset : CounterAction()
}

Middleware

Middleware represented as a class that implements the Middleware interface (so you can use dependency injection into your middlewares to perform the necessary job).

You can return new action instead of incoming by calling next(action, state).

class ActivityLifecycleMiddleware : Middleware<ApplicationState> {
    override fun handleAction(
        action: Action,
        state: ApplicationState,
        next: Next<ApplicationState>
    ): Action {
        val newAction = when (action) {
            is ActivityLifecycleAction.OnResume ->
                YourNewAction()
            else ->
                action
        }
        return next(newAction, state)
    }
}

Reducer

Reducers also represented as a class that implements the Reducer interface (for testability reasons). Keep in mind that reducer should act as a pure function. All your business logic should be in the middleware.

object CounterReducer : Reducer<Int> {
    override fun reduce(action: Action, state: Int): Int {
        return when (action) {
            CounterAction.Increment ->
                state.inc()

            CounterAction.Decrement ->
                state.dec()

            CounterAction.Reset ->
                0

            else ->
                state
        }
    }
}

State

The application state are typically represented as an immutable data class. It allows to easily performs copy on write operations on that state in the reducers.

Store

Base store implementation available in AbstractStore class. Simply extend it, provide initial state, middlewares, reducers and you’re ready to rock!

class ApplicationStore(
    initialState: ApplicationState = ApplicationState(),
    middlewares: List<Middleware<ApplicationState>> = listOf(ApplicationMiddleware()),
    reducers: List<Reducer<ApplicationState>> = listOf(ApplicationReducer)
) : AbstractStore<ApplicationState>(initialState, middlewares, reducers)

Toolkit

Toolkit package contains utilities to simplify common use cases.

Subscribe to the part of the entire state and filter out subsequent repetitions.

data class ApplicationState(
    val number: Int = 0,
    val flag: Boolean = true,
    val word: String = "Hello, World!"
)

store.subscribe(SubStateSubscription(
    transform = { it.number },
    onStateChange = { number: Int, isInitialState: Boolean -> // Do something with value }
))
store.subscribe(SubStateSubscription(
    transform = { it.flag },
    onStateChange = { flag: Boolean, isInitialState: Boolean -> // Do something with value }
))
store.subscribe(SubStateSubscription(
    transform = { it.word },
    onStateChange = { word: String, isInitialState: Boolean -> // Do something with value }
))

Android compatibility

This library contains Redux-friendly version of AppCompatActivity, which dispatch ActivityLifecycleAction whenever the activity lifecycle is changed. It’s good idea to extend that class in order to use Redux architecture in your application.

Tests

All core components are covered with tests to prevent regressions during future development. Also, if you ever want to write your implementation of the Store or AppCompatActivity it’s a good idea to make sure that these tests also pass for your implementation.

Android Studio integration

This repository contains the Live Templates configuration file for faster code writing for Store, Actions, Middlewares, and Reducers. Copy the ./android-studio/templates/redux.xml file to the templates directory of your IDE configuration (the exact path depends on your OS). After that, you can use the store, action, middleware, and reducer abbreviations to insert the appropriate live template.

License

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

GitHub

View Github