Android RxJava Reducer with the Visitor Pattern
Tags: android, java, rxjava, redux
Published: 2020-10-26 21:03:12



# Introduction

It is always a good idea to work on different projects and different technologies, as it provides a good source of knowledge for different parts of components of applications. Technologies used in the Frontend do not usually use the same tools or concepts as technologies on the Backend, and that is precisely the reason why working on both is a good idea. You can incorporate some ideas from one to the other. With this experience, in this article I develop a “RxJava Reducer” that can be used in Android applications.

# The code

All the app code is in the repo:

[Recycler State](https://github.com/marcelo-s/recycler-state)

# Main Idea

The idea is simple:

We have an activity where the user triggers some action, such as clicking on an element, and as a result we move into another activity, the destination activity, in order to show the result of that action. The actions are usually async actions (database calls, api calls, etc.) that fetch some data that is going to be displayed to the user.

This process can involve different states on the destination activity. For instance, we could have the following states:

* Loading
* Loaded
* Error

We need to update the state of the destination activity according to the result of the async action.

RxJava is used for processing the async actions and to manage the subscription of the destination activity, so it can be updated with the results of the async call.

# Libraries/Dependencies

The following are the main dependencies that are used:

* **RxJava** for handling async calls
* **Room** for database
* **Navigation component** for application flow
* **ViewModel** to manage UI data
* **LiveData** to handle the data on the ViewModel
* **Hilt** for dependency injection
* **Java 8+** (Desugaring for using Java8+ API, full lambda!)

# Application architecture

**Single activity app**. Given the recent updates on the android environment, it is recommended to use this new architecture for apps.

I recently had the experience of migrating a multi activity application to a single activity app and it wasn’t pain free. I think most of the time went into deciding how to move code out of the activities and how to structure the application using the navigation graphs. This was an important step as I decided to jump into all new android architecture components. Meaning: **single activity app + architecture components (room, livedata, viewmodel) + navigation components**. Before the migration, my app only had Room database, none of the other new features.

You can read more about these concepts here: [Android Architecture Components](https://developer.android.com/topic/libraries/architecture)

![Android Architecture Components](https://dev-to-uploads.s3.amazonaws.com/i/5oxgwnzh4p5d4xk47ofc.png)

I have to say that I really liked the final product. Using all these tools really *forces you* to think in terms of the architecture of your app and how you organize the code. The result is usually a very clean code/architecture with separation of concerns which makes it easy to change/update your app in the future. But you will probably have to spend a good amount of time understanding what works best for your specific functionality in your app and also reading a lot about the different ways you can conceive what you want using these new tools.

# UI/View model

The app uses a typical pattern that you can see in almost any app: **Master/Detail**, but it seems this has been renamed to **Primary/Detail** Flow. I will use the terms *master/detail* as you can find much more information on the web under this name.

Basically you have a **master** view with a list of items. And when you click on one item you go to another view that displays the specific information of that item, that is the **detail** view.  

# Mapping of concepts

There is no exact mapping between the concepts of Redux to Android but we can define some similarities according the the main function of the concepts.

**1. Store**

The application state resides in the ViewModel. The ViewModel is the closest in terms of the Redux store, it handles the actions, which in turn can call an API or database.

**2. Action**

These are defined as methods within the ViewModel. For instance, the *loadItem* method. Any other components in the application can call(dispatch) these methods in the ViewModel.

```java
public class ItemsViewModelImpl extends ViewModel {
    public void loadItem(long itemId) {
        setItemDetailState(ItemDetailLoadingState.getInstance());
        removeSubscriptionFromCompositeDisposable(getItemSubscription);
        getItemSubscription = itemRepository.getItem(itemId)
                .delay(2, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        this::onItemLoaded,
                        onItemDBError(DBOperation.GET)
                );
        compositeDisposable.add(getAllItemsSubscription);
    }
}
```

As you can see we use RxJava for handling the async calls. In this sense we can say that *RxJava* takes the place of the *Thunk function*.

**3. Reducers**

These are defined as methods within a Fragment. The *ListDetailFragement*. Which also acts as a subscriber of the changes. This is a main difference in respect to Redux, where a reducer is defined independently of the component that uses the result of the reduction process.

**4. State**

The state is modeled using Polymorhphism. There is an interface named “ItemDetailState’ which has 3 different implementations: ItemDetailErrorState, ItemDetailLoadingState, ItemDetailLoadedState. This is explained in detailed in the next section. Just keep in mind we have the following classes:

* IItemDetailState (Interface)
* ItemDetailErrorState
* ItemDetailLoadingState
* ItemDetailLoadedState

# Reduction and update of the state of the application

Now here comes the fun part. Usually with Redux we would have a function with a switch statement to define the reducer. But instead of using a plain switch statement we can use one of the most powerful tools in object oriented programming: “Polymorphism”. Not only that but we can use a very “rare” pattern: “The visitor pattern”.

The main problem we have is the following: 

> We have a list of items in the *ListMasterFragment*, and we want to see the data of a specific item in the *ListDetailFragment*.

> However we need some data to update the view of the *ListDetailFragment*, this is the data of a specific Item.

> The data is not in the *ListDetailFragment*. The data is in the *ItemDetailState*.

> The *ItemDetailState* is an interface representing the state of an Item in the view, therefore, we may have multiple implementations, each with different state. We need to handle each state differently.

# Solution

## 1st Idea

Use “instanceOf”(similar to the switch statement to reduce in Redux) to determine the actual type of the ItemDetailState implementation and get the required data. 

The drawback of this approach is that we would need to update the instance of with more states whenever we add a new state. Needless to say, having multiples *if* or *switch* statements is a code smell. Moreover, we can actually bypass or forget to handle a new state. We are not enforcing correct behaviour and this could lead to bugs.

## 2nd idea: *The Visitor Pattern*

We can use the Visitor Pattern to solve our problems. If you need to know more about the pattern you can read a good introduction here:

[Visitor Pattern](https://refactoring.guru/design-patterns/visitor)

As with all the patterns, they serve as a guideline to solve common problems. Each problem is different and you can use the patterns as you may seem appropriate. In this case we are not using all the advantages of the pattern,such as the [double-dispatch](https://en.wikipedia.org/wiki/Double_dispatch), as we only need to use polymorphism at the method argument level, not the receiver level.

You can read more about the double dispatch here: [Visitor Pattern - Double dispatch] (https://medium.com/@darrenwedgwood/visitor-pattern-and-double-dispatch-part-1-e8d83426a0e7)

The implementation of the Visitor Pattern for the reducer is done in the following steps:

1. We start by defining the Visitor interface:

```java
public interface ItemDetailVisitor {

    void handleItemDetailLoadingState(ItemDetailLoadingState itemDetailLoadingState);

    void handleItemDetailLoadedState(ItemDetailLoadedState itemDetailLoadedState);

    void handleItemDetailErrorState(ItemDetailErrorState itemDetailErrorState);
}
```

2. The *ListDetailFragment* implements this interface:

```java
public class ListDetailFragment extends Fragment implements ItemDetailVisitor {

    @Override
    public void handleItemDetailLoadingState(ItemDetailLoadingState itemDetailLoadingState) {
        showProgressBarLoading();
    }

    @Override
    public void handleItemDetailLoadedState(ItemDetailLoadedState itemDetailLoadedState) {
        setItemDetailData(itemDetailLoadedState);
        setItemDataOnView();
        hideLoadingProgressBar();
        Snackbar.make(requireView(), R.string.toast_loaded_successfully, Snackbar.LENGTH_SHORT).show();
    }

    @Override
    public void handleItemDetailErrorState(ItemDetailErrorState itemDetailErrorState) {
        hideLoadingProgressBar();
        Toast.makeText(getActivity(), R.string.toast_error_loading_item, Toast.LENGTH_SHORT).show();
    }
}
```

3. We subscribe to changes on the *ItemDetailState*, which we get using the subscription provided by RxJava. This data is handled in the *ViewModel* using *LiveData*:

```java
    private void setItemData() {
        itemsViewModel.getItemDetailState().observe(getViewLifecycleOwner(), this::onItemDetailStateChange);
    }

    private void onItemDetailStateChange(IItemDetailState itemDetailState) {
        itemDetailState.accept(this);
    }
```

* 4. We define the abstract **accept** method on the IItemDetailInterface:

```java
public interface IItemDetailState {
    void accept(ItemDetailVisitor itemDetailVisitor);
}
```

* 5. Finally we implement the *accept* method on the concrete classes:

```java
// On the ItemDetailStateError
    @Override
    public void accept(ItemDetailVisitor itemDetailVisitor) {
        itemDetailVisitor.handleItemDetailErrorState(this);
    
// On the ItemDetailLoadedState
    @Override
    public void accept(ItemDetailVisitor itemDetailVisitor) {
        itemDetailVisitor.handleItemDetailLoadedState(this);
    }

// On the ItemDetailLoadingState
    @Override
    public void accept(ItemDetailVisitor itemDetailVisitor) {
        itemDetailVisitor.handleItemDetailLoadingState(this);
    }
```

In order to understand better how the problem is solved we can take a look at the data flow of the application.

## Data flow

* An item on the list is selected. *ListMasterFragment* triggers the loading of the selected item in the *ViewModel* and moves the view to the *ListDetailFragment*:

```java
    @Override
    public View.OnClickListener seeItemButtonListener(ItemsRecyclerViewAdapter.ItemViewHolder holder, Item item) {
        return view -> goToItemDetail(view, item);
    }

    private void goToItemDetail(View view, Item item) {
        itemsViewModel.loadItem(item.getId());
        NavDirections toItemDetail = ListMasterFragmentDirections.actionListMasterFragmentToListDetailFragment();
        Navigation.findNavController(view).navigate(toItemDetail);
    }
```

* The ItemsViewModel receives the call to load the item and updates the ItemDetailState to "Loading", meanwhile, it does an async call to get the item details:

```java
    public void loadItem(long itemId) {
        setItemDetailState(ItemDetailLoadingState.getInstance());
        removeSubscriptionFromCompositeDisposable(getItemSubscription);
        getItemSubscription = itemRepository.getItem(itemId)
                .delay(2, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        this::onItemLoaded,
                        onItemDBError(DBOperation.GET)
                );
        compositeDisposable.add(getAllItemsSubscription);
    }
```

The setItemDetails is as follows:

```java
    private void setItemDetailState(IItemDetailState itemDetailState) {
        this.itemDetailStateLiveData.setValue(itemDetailState);
    }
```

Basically it updates the LivaData instance variable, which will notify any subscriber of this LiveData. Remember that the *ListDetailFragment* is subscribed to this LiveData:

```java
// On the ListDetailFragment

    private void setItemData() {
        itemsViewModel.getItemDetailState().observe(getViewLifecycleOwner(), this::onItemDetailStateChange);
    }

    private void onItemDetailStateChange(IItemDetailState itemDetailState) {
        itemDetailState.accept(this);
    }
```
So it will call the "accept" method on the "ItemDetailStateLoading" with the ListDetailFragment as an argument. Because this method is polymorphic on the argument type, it can call any concrete implementation of the interface! In this case the concrete implementation is the ItemDetailLoadingState.

* The *ItemDetailLoadingState* receives the call and calls the corresponding method on the *ListDetailFragment*, which implements the *ItemDetailVisitor* interface:

```java
// On the ItemDetailLoadingState
    @Override
    public void accept(ItemDetailVisitor itemDetailVisitor) {
        itemDetailVisitor.handleItemDetailLoadingState(this);
    }
```

* The *ListDetailFragment* calls the *handleItemDetailLoadingState* method:

```java
    @Override
    public void handleItemDetailLoadingState(ItemDetailLoadingState itemDetailLoadingState) {
        showProgressBarLoading();
    }
```

* After some time, the result is obtained from the RxJava async call on the *ViewModel*:

```java
    private void onItemLoaded(Item item) {
        setItemDetailState(ItemDetailLoadedState.of(item));
    }
```
This will again update the LiveData, but this time with an instance of the ItemDetailLoadedState, which contains the data of the item that was loaded.

* Again, the *ListDetailFragment* receives the update and calls the "accept" method, but this time in the ItemDetailLoadedState, thanks to the polymorphic method ":

```java

// On the ListDetailFragment

    private void onItemDetailStateChange(IItemDetailState itemDetailState) {
        itemDetailState.accept(this);
    }

// On the ItemDetailLoadedState
    @Override
    public void accept(ItemDetailVisitor itemDetailVisitor) {
        itemDetailVisitor.handleItemDetailLoadedState(this);
    }
```

* Finally, the ListDetailFragment handles the call, and updates the View:

```java
   @Override
    public void handleItemDetailLoadedState(ItemDetailLoadedState itemDetailLoadedState) {
        setItemDetailData(itemDetailLoadedState);
        setItemDataOnView();
        hideLoadingProgressBar();
        Snackbar.make(requireView(), R.string.toast_loaded_successfully, Snackbar.LENGTH_SHORT).show();
    }
```

Basically we define the handler methods on the Visitor interface, and the implementation, in this case the ListDetailFragment decide how to implement them, updating the view according to the state. 

With this approach, we can leverage the polymorphic types of the state and provide a solid architecture that handles beautifully the changes in the view.

# Conclusions

This was a small proof of concept of how you can use the idea from other frameworks/libraries in different part of an application. In this case I took the Reducer idea from Redux, a frontend library, which can be quite useful for handling state changes using async calls in an Android application.

There might be better approaches but I found this one particularly interesting because it makes use of polymorphism to solve the reduction problem of multiple states. 

I am planning on making several articles based on the same app as it has several interesting implementation details. For instance why using an interface for the State istead of having one state with "type" as a field. Also the RxJava subscription handling.