|

Exploring UI Navigation Architecture JetPack Component of Android

Sharing is caring!

From my last post, we have talked about the journey of Android architecture design. We have discussed the different -different (MVC, MVP, MVI, MVVM, and Jetpack) architectures pattern of Android to use to build a solid android application. I would recommend to go and check this article (Journey of Android Architecture Design pattern) which is posted here.

In this tutorial, we will learn about one of the Foundation components of Android Jetpack is UI Navigation. I remembered while navigating to one screen to other screen or content we are generally calling intent to start Activity or beginning the transaction to a fragment. In Android, fragment transaction is very hard to maintain the back stack. Now Google has realized the developer problems about the fragment transaction and provided the new library in Jetpack to make the navigation becomes easy and smooth with Single Activity.

The Navigation component consists of three key parts that are described below:

  • Navigation graph: An XML resource that contains all navigation-related information in one centralized location.
  • NavHost: An empty container that displays destinations from your navigation graph.
  • NavController: An object that manages app navigation within a NavHost.

As you navigate through your app, you tell the NavController that you want to navigate either along a specific path in your navigation graph or directly to a specific destination. The NavController then shows the appropriate destination in the NavHost.

Let’s explore the android UI Navigation with a simple android movie project with the help of navigation and fragment ktx extension library. In the very first step, we need to add the relevant dependency into a build.gradle file to get the UI Navigation feature.

// navigation
implementation "androidx.navigation:navigation-ui-ktx:2.0.0"
implementation "androidx.navigation:navigation-fragment-ktx:2.0.0"

If you want to pass any object from Activity/Fragment to another fragment while navigating then we need to add one more plugin is called safeargs.

//Apply Safe Args Plugin
apply plugin: "androidx.navigation.safeargs.kotlin"

And now you need to add the classpath of this plugin with project level gradle file.

 classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.1.0-alpha01"

In our movie sample project, our aim is to open the main movie fragment and navigate to the movie detail fragment and then navigate to the movie Cover Fragment and vice versa to handle the back stack. So we need to create the two navigation XML file to create the navigation graph. For the reference please see the below project snapshot.

Let’s create the navigation XML file with navigation tag to define the start destination from the current fragment to the destination of another fragment. We need to define the action tag for other fragment or any other graph.

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:id="@+id/nav_graph_home_feature"
            app:startDestination="@id/mainFragment">

    <!-- Main fragment -->
    <fragment android:id="@+id/mainFragment"
              android:name="com.sunil.arch.ui.main.MainFragment"
              android:label="@string/app_name">

        <!-- Go to Detail Fragment (Its graph is responsible to handle response) -->
        <action android:id="@+id/action_mainFragment_to_detailFragment"
                app:destination="@id/nav_graph_detail_feature">
            <argument android:name="movie" app:argType="com.sunil.arch.data.MovieEntity"/>
        </action>
    </fragment>

    <include app:graph="@navigation/nav_graph_detail_feature"/>
</navigation>

For the above XML, our design looks like that.

As we can see the above navigation graph, it is clear that from the main fragment screen to navigation to another navigation graph which is the detail below XML.

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:id="@+id/nav_graph_detail_feature"
            app:startDestination="@id/detailFragment">

    <!-- Detail Fragment -->
    <fragment android:id="@+id/detailFragment"
              android:name="com.sunil.arch.ui.detail.DetailFragment"
              android:label="movie's detail">
        <argument android:name="movie" app:argType="com.sunil.arch.data.MovieEntity"/>

        <action android:id="@+id/action_detailFragment_to_movieCoverFragment"
                app:destination="@id/movieCoverFragment"/>
    </fragment>


    <!-- covert Detail Fragment -->
    <fragment android:id="@+id/movieCoverFragment"
              android:name="com.sunil.arch.ui.moviecover.MovieCoverFragment"
              android:label="movie cover">
        <argument android:name="imageUrl" app:argType="string"/>
    </fragment>

</navigation>

From the above XML, our design looks like that. Please see the below snapshot.

As we can see from the above two design snapshot, our aim to navigate from the main screen to detail screen and from the detail screen to cover the screen and maintaining the back stack.

Now we need to create the NavHostFragment as a container to navigate the start destination to other destination and maintain the back compatibility. So I am defining this fragment tag with NavHostFragment in a main_activity.xml file for providing the navigation graph.

<?xml version="1.0" encoding="utf-8"?>
<fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph_home_feature"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"/>

Now our UI navigation graph is ready to navigation. The library has provided the NavController to set up the toolbar configuration and observe the navigation to navigate. So let’s see how can we set up the action bar with Navigation Controller.

fun configureNavController() {
        navController = findNavController(R.id.nav_host_fragment)
        appBarConfiguration = AppBarConfiguration(navController.graph)
        // it based on support configure like action bar or toolbar or collapsing
        setupActionBarWithNavController(navController, appBarConfiguration)

    }

Let’s observe the navigation direction in a View, we need to define two objects, one is To direction and another is Back direction to observe by the navigation controller.

sealed class NavigationController{
    data class To(val directions: NavDirections): NavigationController()
    object Back: NavigationController()
}
 private fun observeNavigation(viewModel: BaseViewModel) {
        viewModel.navigation.observe(viewLifecycleOwner, Observer {
            it?.getContentIfNotHandle()?.let { command ->
                when (command) {
                    is NavigationController.To -> findNavController().navigate(command.directions, getExtras())
                    is NavigationController.Back -> findNavController().navigateUp()
                }
            }
        })
    }

Internally our id is defined in action tag will generate the corresponding classes to which we need to pass a navigation direction. For example, navigate to the main fragment to detail fragment and detail fragment to cover fragment. One thing remembers that you need to pass the unique shared element name for transition the fragment to the correct destination.

NavigationController.To(MainFragmentDirections.actionMainFragmentToDetailFragment(movieEntity))
NavigationController.To(DetailFragmentDirections.actionDetailFragmentToMovieCoverFragment(movieEntity.posterPath))

That’ it. I  really love the new Navigation Architecture Component. Google makes our life very easy to maintain this library. Currently the library in alpha, It may come in production very soon with few modifications of function.

Wrapping 

Now we have a good understanding of the new android Jetpack Component of UI Navigation. We have played with a sample project to learn the basic concept of Navigation. I personally like this change from Google. You can get the full Github source code of Jetpack Sample. So my next tutorial, we will learn some other jetpack Components in detail, ok till then enjoy your healthy day.

If you are wondering to learn Android then Please learn from Android category and wondering to learn Kotlin then Kotlin Category will help you. If you want to learn all the python article, then learn from the python category.

Happy Coding 🙂

5 1 vote
Article Rating

Similar Posts

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments