Android Fragment KTX. Universal Navigation approach in Activity

Android Jedi
Aug 31, 2018 · 2 min read

Goal: to make all fragment navigation in activity to look like this:

navigator.show<DummyFragment>()

Common approach for navigation in activity is to extract all navigation logic in some NavigationController class, but this approach has significant gap:

You have to create navigation method for EACH destination in EACH Activity

In snippet below this approach is shown also with usage of transaction function from androidx.fragmnet:fragment-ktx artifact, whose purpose is to get rid of boilerplate code and enforce usage of all power of Kotlin language.

Implementation that leads to code duplication:class NavigationController {
val containerId: Int
val fragmentManager:FragmentManager

fun navigateFragmentA() {
val fragment = new FragmentA() fragmentManager.transaction(allowStateLoss = true) {
replace(containerId, fragment)
}
}
public void navigateFragmentB...
//duplicated code
public void navigateFragmentC...
//duplicated code

}

To eliminate code duplication and reach our goal we’ll add another extension functions to FragmentManager class with usage of Kotlin’s inline functions and reified type parameters . Kotlin’sreified types will allow us to use generic types within the functions at runtime, which is impossible in Java. To skip this JVM limitation Kotlin’s compiler aslo needs the functions to be inline so it is possible for it to embed code with preserved type in the place where it is run.

inline fun <reified T : Fragment> FragmentManager.show() {
takeIf { it.notDisplayed<T>() }?.transaction {
replace(containerId, T::class.java.newInstance())
addToBackStack(null)
}
}

We’re almost there, another thing we need to do is to provide containerId by putting FragmentManager extension function in the Navigator class that is initialized by correcpoding fragmentManager and containerId.

So no more destination specific methods, just:

navigator.show<DummyFragment>()

If you need to go to fragment that is instantiating with pareameter’s:

navigator.show { DummyFragment.newInstance(params) }

If you need to show “main fragment” and clear stack so that backpress will quit the app use:

navigator.showOnly<DummyFragment>()

The source code of all functions is on GitHub

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