Cicerone and Dagger2 — Managing BottomNavigation with Fragments

[EDIT] At the time of this edit, the Google Navigation Architecture Component is a better alternative to this and is the recommended approach for managing BottomNavigation apps.
The use of a BottomNavigation bar is becoming more and more popular in Android apps. Apparently it engages users more than the hamburger menu, so if you haven’t been asked to implement something like this yet, it is just a matter of time.
It is pretty easy to set up if you only need one initial Fragment in each tab that leads to a flow of Activities (because they have their own Android managed backstack), but it can become tricky fast if you need to keep the BottomNavigation bar visible as the user navigates. For that you will probably need to use fragments.
What makes this hard is that each tab needs to have a separate flow (backstack) of Fragments. You probably could do this without any libraries using some fragment handling copypasta, but if you are already using Dagger2 it becomes really easy to add Cicerone to help you do this. There are many libs that handle fragment and activity flow, but I like Cicerone the most in this case because I don’t have to change the app’s architecture to fit it in. It can hold a backstack (FragmentManager) and handle all the navigation with a single Cicerone object, and that is all we need to make it smooth with Dagger.
Cicerone is pretty simple to use, so I will not focus on that. Take a look at their github and the sample they provide and you’re probably good to go. Can’t say the same about Dagger though, but if you already have it running then it will be easy.
Having that in mind, this how i set up this demo:
There is one activity that has the BottomNavigation bar and a fragment container. Into this container we inflate a parent fragment (depending on the selected tab) that will have another container inside to inflate fragments of that particular tab’s flow. If the user navigates inside a tab, we inflate the next fragments in the inner container. If the user switches tabs, we switch the fragment in the outer container.

We already had a global AppComponent and a bunch of SceneComponents for each Scene of the app (a scene in this context is a fragment with its presenter, viewmodels, etc). The Scene component depends on the AppComponent (not really in the demo, but it usually does as the project grows) for things like repositories and data sources. The trick is to simply create an intermediary scope @PerFlow that our FlowComponent will live in, and make the SceneComponents depend on it instead.
The FlowComponent will be instantiated once per tab (in a parent fragment), and it will hold an instance of a Cicerone object. This same instance will be shared between all the child fragments in that tab. That is possible because the SceneComponents will get it from the FlowComponent. Another advantage of doing this is that we can now have other objects reused in multiple fragments of a flow without having to make it global.

The Cicerone’s sample app also shows how to set up this kind of behavior, but I think this makes better use of dagger’s capabilities by giving each tab one scope and component to share dependencies within.
Note that if you are trying to do this without dagger, you would simply get the Cicerone instance from the parent fragment directly, instead of injecting it. What does the whole thing work is this setup with a parent fragment per tab holding a flow of child fragments, dagger and cicerone just make it butter smooth.
This is the general idea, the demo is excessively commented about the details so I won’t duplicate that here. This doesn’t solve all the problems of doing most of the app inside fragments, but at least the navigation problems become easier. I hope this helps someone.
Links:
Demo: https://github.com/yurimachioni/CiceroneDaggerDemo
Cicerone: https://github.com/terrakok/Cicerone
Dagger2: https://github.com/google/dagger
Google Navigation Architecture Component: https://developer.android.com/topic/libraries/architecture/navigation/