Redux + (RxKotlin | RxSwift) == Awesome Native Mobile Apps — Router — Part 6

Mohanraj Karatadipalayam
AndroidPub
Published in
6 min readJul 9, 2018

These libraries can be a boon for native app developers. See how they change the developer experience in part six of this series.

We have learned about the unit testing in Part 5, now let’s learn about the router.

Why we need the Router?

When there is a need to change the flow or introduce a new screen in the existing flow in an app, the changes are cumbersome. To understand that let’s work an example, say we have a simple app that has 4 screens

Now we have a need to introduce a new screen in the existing flow such as

Think about the changes we need to make.

Both in iOS and Android, we need to make the changes in the classes that trigger the new screens, typically those classes are Activity or Fragment in Android, ViewController in iOS. Also, we need to carry and forward the data which screen B sending to screen C when we introduce a new screen B1.

This needs a lot of code changes. Painstaking work.

Using Redux

If the App is built using the Redux, you may not need to pass the data between the screens, as the data can be stored as the state(s).

Want to learn more about Redux in Native apps — refer here

Now we achieved the greater level of separation of concerns (SOC) with help of Redux, let’s move the routing logic out of Activities/Fragments or ViewControllers, respecting the principle of SOC.

What are the libs we have to achieve the same?

We will use rekotlin-router or ReSwift-Router , depending upon the platforms.

Redux helps the Routing or Navigation

Redux Router takes advantage of the redux state to define the navigation. It uses a state called NavigationState. Using the NavigationState, the router externalizes the logic of navigation, moved the code out of Activities/Fragment or ViewControllers.

Android developers, the examples used in this post uses Activity for the sake of simplicity, you can achieve the same routing when the app uses Fragments as well, it will be explained later, Hang on…

How does Router work?

Router in action

When the RoutingAction is dispatched by Activity/Fragment or ViewController, it is intercepted by the navigationReducer provided by the Router.

The Router uses the Routableof the dispatching Activity or ViewController to derive the next possible Activity or ViewController. Routable apart from creating the Activity or ViewController, it creates the Routable for the next Activity or ViewController.

For example, when an ActivityA dispatches a RoutingAction that has two routes ActivityA, ActivityB, Router creates an instance of ActivityB and the routable for ActivityB namely RoutableB. Now ActivityB is the active Activity in your App

Routable creating another Activity and Routable

What happens when ActivityB decides to change the screen?

When ActivityB dispatches a routing change, it will be the responsibility of RoutableB to decide the next possible Activity.

Yes, each Activity or ViewController must have a Routable Class defined. Routable class separates the navigation logic from the Activity or ViewController class.

Show me the code

Let’s start with adding the dependencies as shown below

implementation 'org.rekotlinrouter:rekotlin-router:0.1.9'

iOS developers, refer here

Let’s update the state to implement the interfaceNavigationState

Once the navigation state is defined in the AppState, we need to create an object of Router. TheRouter takes care of the navigation, as long as the Routable is defined for each Activity or ViewController.

In order for Routable to work, we need to create an instance of Router and initialize the same.

Where should we do that?

Remember where we did create the Store as a global variable in part 2 of this series?

Yes, we create them in AppController, let’s update the class to accommodate the Router

Router initialization takes three inputs

  • store
  • root routable
  • A lambda expression that describes how to access the navigationState of the application state

What is Root Routable?

It is the first routable in the series of Routable's that takes care of the navigation. It is routable for the first Activity or the ViewController that is presented by the app.

Routable

Now let’s look at the Routable interface

The Router works with routes that are defined, similar to URLs, as a sequence of identifiers e.g. ["Home", "User", "UserDetail"]. It uses Routable to implement that interaction.

Each route segment is mapped to one responsible Routable. The Routable needs to be able to present a child, hide a child or replace a child with another child.

Now when we add the routes, for example from ["Home"] to ["Home", "User"] Router will execute the function pushRouteSegment of Routable Home.

pushRouteSegment working

when the opposite happens, for example when the route changes from ["Home", "User"] to ["Home"], Router will execute the function popRouteSegment of Routable User.

popRouteSegment working

The code pretty much does nothing, as Android takes care of the dismissing the current Activity. You may have some post dismissing work in completionHandler

In case of iOS, you dismiss the current ViewController

What happens when we want to change the routes for example from ["Home", "User"] to ["Home", "Detail"]?

The Router will execute the function changeRouteSegment of Routable User.

changeRouteSegment

Want to see the complete example using Router, refer to AndroidExample using Activity here and iOS example here. You may like to clone the projects and run it.

Router using Fragments

You can dispatch the actions that invoke the Fragments similar to Activity.

The function SetRouteSpecificData passes the data to Router to create the fragment.

We need the reference of Activity to create the Fragments. We will pass the Activity as WeakReference

We will use a class FragmentDataValue to pass such data

Routable that creates Fragments

Let’s override the functions to create the Fragments, exactly similar to how we do it when using Router with Activity

Let’s use the WeakReference of Activity to create the Fragment

It does the following

  • get the current route from navigationState
  • From the current route, get the fragment’s intentData
  • With the intentData, get the activity from its WeakReference and Boolean value whether to add to the stack.
  • Call the function addFragment, helper method to create the fragment.

Want to see the example of Android using Fragments, refer here.

Conclusion

I hope you are able to appreciate the fact, the routing logic is externalized completely using the Redux and Redux-Router, achieving the SOC.

Links to the series

--

--

Mohanraj Karatadipalayam
AndroidPub

Polyglot developer, Engineering manager for iOS and Android apps, Amadeus Labs