Navigation in a modular Android project

Sergey Lapin
Sep 9, 2018 · 2 min read

Even though AAC’s Navigation Component seems to be able to handle navigation in modular android project, for those who would like to implement it in a more old-fashion way, I would try to provide some thoughts on how to do it.

On app structure

Sample modules structure

As basis of architecture we’ll pick feature-per-module principle with some base modules (like Core and Core UI) and delegate navigation between features to Mediator module.

Core

In the core module we will define our flows as Kotlin’s sealed class to achieve the goal of transparency in what data we have to pass to another flow.

Also here, in core, we’ll define Mediator interface in the following way:

And finally we’ll make some additions to Cicerone’s SupportFragmentNavigator to make it able to handle flows as separate unit. (In case you haven’t heard about this great library, then you should definitely check it out!)

And then core module DI will look like this:

Here I use Koin as DI framework, which I find the most concise way to show DI in article cause it’s synthax is self-explanatory and you don’t have to be a Dagger Master to understand how dependencies are provided somewhere. But you can of course use framework of your choice.

Mediator

In the mediator module we’ll define couple of interfaces which will determine a contract by which features will provide entry points to them.

Basic interfaces from which all feature intent providers can inherit

Also we’ll implement Mediator interface.

And finally Mediator module’s DI:

Core UI

Moving on to Core UI, here we’ll stop to define Base Activity in following way:

Main Flow

Finally let’s see how it will work inside some feature module, main flow, for example. First we’ll implement MainFlowIntentProvider like this:

This will provide a place where Mediator will seek for Intent for this specific flow. Here getFlowIntentFor is a simple extension function to cover basic Android Intent creation.

And, finally to make it all work we need to override Navigator inside of our MainActivity

So, now, when we’re inside this flow and we’ll call router to start new flow we’ll go to this place, ask mediator to find intent by flow and then mediator will call some specific flow intent provider implementation to get this flow-based intent that we’re looking for. To make it all work, last thing we need is provide our MainFlowIntentProviderImpl.


That’s it. By adding this Mediator layer we can achieve separation of features so that they don’t know about each other and we can navigate between them by using this Flow concept in the way where we can, for example, force user of our feature to pass some input data without which we aren’t able to start our flow.

Thanks for reading till the end. I hope this article will be usefull for you in some way.

Sergey Lapin

Written by

Android Developer at Tochka Bank

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade