Library / SDK
listenzz/AndroidNavigation avatar
listenzz/AndroidNavigation

AndroidNavigation: nested fragments, a toolbar and a status bar in one library

A library managing navigation, nested Fragment, StatusBar, Toolbar for Android

710 stars95 forksJavaMIT

At a glance

What is it?
AndroidNavigation is an Android library that treats the single Activity architecture as a set of nested container fragments. An Activity extends AwesomeActivity, a Fragment extends AwesomeFragment, and StackFragment, TabBarFragment, and DrawerFragment handle the stack, the tab bar, and the drawer. It is published on Maven Central under io.github.listenzz and is MIT licensed.
Who is it for?
AndroidNavigation fits a team that has already decided to run one Activity and build the interface out of fragments, and that would rather have the container behaviour, the toolbar, and the back handling written once than in every screen.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The library takes the single Activity decision away from you

AndroidNavigation manages navigation, nested fragments, the status bar, and the toolbar for Android, and the project offers it as a way to build a single Activity architecture without writing the container code yourself. It is also the subproject behind hybrid-navigation, a larger project by the same author, which tells you that this library is one layer of a broader approach rather than a finished application framework.

The entry points are two base classes. A Fragment extends AwesomeFragment, and an Activity extends AwesomeActivity and then declares its root fragment. The core example sets the root inside onCreate, guarded by the saved instance state check so that the fragment is not recreated on a configuration change.

java
public class MainActivity extends AwesomeActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState == null) {
            TestFragment testFragment = new TestFragment();
            setActivityRootFragment(testFragment);
        }
    }

}

Two behaviours are worth noting in that snippet. The root fragment is set only when the saved state is null, which is the standard guard, and the root is set through a method on the Activity rather than by handing a fragment to the FragmentManager directly. The library's own description of its design says that the point is that you no longer write the bulk of the fragment manipulation code and no longer have to think about which FragmentManager to use.

The root can also be changed later. The method may be called more than once, and the documented use for that is application state: a login screen first, then the main screen once the sign-in has succeeded. The same switch is exposed from a fragment, so a screen can replace the root of its Activity at any point.

One thing does not have to extend anything. A splash screen Activity, the one you show while the app starts, does not need to extend AwesomeActivity, and the documentation makes that exception explicit so that a temporary screen does not inherit the whole navigation stack.

StackFragment pushes and pops without a FragmentManager

Three container classes exist to solve the usual nesting problems, and StackFragment is the stack-shaped one. It manages its child fragments in a stack, supports push and pop, and needs a root fragment assigned when it is created.

java
public class MainActivity extends AwesomeActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState == null) {
            TestFragment testFragment = new TestFragment();
            StackFragment stackFragment = new StackFragment();
            stackFragment.setRootFragment(testFragment);
            setActivityRootFragment(stackFragment);
        }
    }
}

Two lines do the work there. The first gives the stack its bottom page, and the second makes that stack the root of the Activity, so a stack can itself be the root of a container, which is the property that makes the nesting model work.

The toolbar comes for free in one condition. If the root layout of the fragment inside the stack is a LinearLayout or a FrameLayout, the library creates the toolbar for you, and when the user navigates from one page to another, a back button is added to the toolbar of the page being opened. The configuration of that toolbar is a separate documented section, so the automatic behaviour is a starting point rather than the whole feature.

Navigation from inside a page works through the parent. A fragment reaches the stack that encloses it with getStackFragment, and then calls pushFragment to open another page or popFragment to go back to the previous one. The library describes this as the navigation section's subject, and it is the pattern that replaces the transaction code a fragment would otherwise write against the FragmentManager.

Because the stack is a fragment like any other, a page inside a stack can itself host a stack, which is how a tab bar with an independent history per tab is built, and the library's own example does exactly that with a StackFragment per tab.

TabBarFragment, and the tab bar you can replace

TabBarFragment covers the common case of a main screen with a row of tabs along the bottom, where tapping a tab swaps the visible screen. Each tab is a fragment, and each one declares its own tab item, with a title and a drawable, through a call on the fragment itself before the fragments are handed to the container.

The container is then given those fragments and made the root of the Activity, so the structure at the top of the screen is: the Activity, a TabBarFragment, and a fragment per tab.

Three things can be done with the bar once it exists. The selected tab can be changed at run time through setSelectedIndex, which is what a deep link or a notification needs. The bar itself can be reached from a tab with getTabBar, and that object is what carries the badge and the unread count, so the red dot on a tab is a call on the bar rather than something the fragment draws. And the bar can be replaced wholesale by implementing the TabBarProvider interface and calling setTabBarProvider on the container, which has to happen before the TabBarFragment is set as the root of another container. The provider argument may be null, and the documentation says that this means no tab bar at all, which is how a screen is used without one.

That extension point matters more than it looks, because the default bar is a specific widget with a specific look, and a design system that has its own tab bar cannot use the container without replacing it.

The nesting story closes here too. A tab that needs its own navigation history, a contacts tab that opens a detail page and comes back, puts the fragment inside a StackFragment first, gives the stack the tab item, and then hands the stacks to the TabBarFragment. Each tab then has its own stack, its own toolbar, and its own back button, and none of it is coordinated by the screen that owns the tabs.

DrawerFragment, the drawer, and the swipe back gesture

DrawerFragment is the third container, and it is the simplest of the three to describe. It wraps a DrawerLayout, and the child fragments are assigned to it: a content fragment for the main area and a second fragment for the drawer itself. The documentation states that two child fragments are needed rather than one, which is a small but real constraint to know before you write the layout.

The wider feature list is what places the containers in context. Alongside the nested fragment support, the library lists the pieces of an application's chrome: a translucent status bar, an automatically created toolbar, global styles set in one place and applied everywhere with per-page overrides, a swipe back gesture, lazy loading, font icons, and a dialog described as what you see is what you get, meaning the dialog is composed from the same view hierarchy as the page rather than drawn separately.

The status bar and the navigation bar each have their own section in the usage guide, and so does the toolbar, the font icon support, and the code specification. The global style section is the one that changes the most for an application, because it is where the decision lives to set a look once and let individual pages adjust it.

The swipe back gesture belongs with the containers rather than with the chrome, because it only makes sense when there is a stack to go back through. A page that has been pushed onto a stack can be dismissed with a gesture rather than only with the toolbar button that the library adds automatically, and both routes end in the same pop.

Lazy loading is listed as a supported feature, and it is worth understanding in relation to the containers. With fragments swapped in and out by a tab bar or a stack, the cost of building a screen that nobody is looking at is paid every time the container changes, so deferring the work of a fragment until it is shown is a normal requirement rather than an optimisation.

Installing it, and the version pair that goes with it

The library is published to Maven Central, and the installation is a Gradle dependency line paired with the Android support library the project expects.

groovy
implementation 'io.github.listenzz:AndroidNavigation:13.10.1'
implementation 'androidx.appcompat:appcompat:1.6.1'

Those two lines are the whole installation for a project that already has the standard Google and Central repositories configured, and the repository block below them is the reason they resolve.

groovy
allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

The appcompat line is not optional decoration. The library is built on the support library, and the version is pinned in the example rather than left to the newest one, so an application that upgrades appcompat on its own schedule may need to align this dependency with it.

The repository also documents how a fork publishes its own version, which is more detail than most libraries give, and it is a three part process. The first part is the coordinates in the Gradle properties file of the navigation module, where the group, the artifact name, and the version are set.

properties
GROUP=io.github.listenzz
POM_ARTIFACT_ID=AndroidNavigation
VERSION_NAME=13.10.1

The documentation notes that a version bump usually means changing only the version line, and recommends also syncing the versionName in the build file of the same module so the two do not disagree locally.

groovy
defaultConfig {
    versionName "13.10.1"
}

The second part is the publishing command, run from the root of the project, with a flag for a full stack trace when something fails.

bash
./gradlew :navigation:publishAndReleaseToMavenCentral
bash
./gradlew :navigation:publishAndReleaseToMavenCentral --stacktrace

The third is checking the result, and the documentation gives two addresses, the Sonatype Central page for the artifact and the Maven repository path for the version, with the version placeholder to be replaced by whatever was published.

The repository layout is a Gradle project with the library in a navigation directory, a demo application, a screenshot directory, and the usual wrapper scripts. The demo module carries its own build file, a ProGuard rules file, and a navigation directory of its own, and the downloadable demo APK in the project description is built from it.

Editorial conclusion

AndroidNavigation fits a team that has already decided to run one Activity and build the interface out of fragments, and that would rather have the container behaviour, the toolbar, and the back handling written once than in every screen. It does not fit a project that wants the standard Navigation component, since this library sits underneath the framework rather than replacing it, and it does not fit a team that has to support the pre-6.0 behaviour of earlier releases, because the current line is built around the newer container classes. Verify first that the version you pull matches the appcompat version your project already uses, since the installation pairs the two, and that the root layout of a fragment is a LinearLayout or a FrameLayout if you want the toolbar to be created for you.

Frequently asked questions

What does AndroidNavigation do for an Android application?

It manages nested fragments, a translucent status bar, and the toolbar, so that an application can be built on a single Activity. An Activity extends AwesomeActivity, a Fragment extends AwesomeFragment, and the container classes StackFragment, TabBarFragment, and DrawerFragment handle the stack, the tabs, and the drawer.

How do I install AndroidNavigation?

Add the Gradle dependencies for io.github.listenzz:AndroidNavigation and androidx.appcompat:appcompat, with the matching version, and make sure the project lists the google and mavenCentral repositories. The library is published to Maven Central, so no extra repository is needed.

When does AndroidNavigation create a toolbar for me?

When the root layout of the fragment inside a StackFragment is a LinearLayout or a FrameLayout, the library creates the toolbar, and a back button is added to the toolbar of the page being opened when navigating from one page to the next. The automatic creation can be turned off for a custom toolbar.

Can I replace the default tab bar in AndroidNavigation?

Yes. Implement the TabBarProvider interface and pass it to setTabBarProvider on the TabBarFragment, which has to be done before that fragment is set as the root of another container. The provider may be null, and the documentation says that means the screen has no tab bar at all.

How do I publish a modified version of AndroidNavigation?

Set the group, the artifact name, and the version in the gradle.properties file of the navigation module, sync the versionName in its build file, and run the publish and release task for that module from the project root. The documentation links the Sonatype Central page and the Maven repository path so you can confirm the artefact appeared.

Official sources

  1. Issues
  2. License: MIT
  3. listenzz/AndroidNavigation on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/listenzz-androidnavigation.svg)](https://hysenlabs.com/projects/listenzz-androidnavigation)

Was this useful?