Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Navigation Architecture Component: How to pass bundle data to startDestination

I have an activity which has a NavHostFragment. The activity receives certain values in its intent. I want to pass this data to the first fragment i.e startDestination of the navigation graph. I couldn't find any documentation regarding this.

I have already gone through this question on SO but I can't seem to find the addDefaultArguments method for navController.getGraph().

Is it possible to pass bundle to startDestination?

like image 732
Praveen Singh Avatar asked Dec 24 '18 12:12

Praveen Singh


People also ask

Can navigation component be used for activities?

The Navigation component uses an activity as a host for navigation and swaps individual fragments into that host as your users navigate through your app. Before you can start to layout out your app's navigation visually, you need to configure a NavHost inside of the activity that is going to host this graph.

How do I get NavController in fragment?

To retrieve the NavController for a fragment, activity, or view, use one of the following methods: Kotlin: Fragment. findNavController()


2 Answers

Answering my own question as I found the correct approach in the updated Navigation documentation.

At the time of writing this answer, I am using Navigation 2.2.0-alpha01

If you want to pass some data to the start destination directly as arguments from host activity, you need to manually set your host’s navigation graph inside the host activity’s onCreate() method, as shown below:

Get you navController:

val navController by lazy { findNavController(R.id.<your_nav_host_id>) }

Then in the host activity's onCreate()

val bundle = Bundle()
bundle.putString("some_argument", "some_value")
navController.setGraph(R.navigation.<you_nav_graph_xml>, bundle)

Or if you want to pass the whole intent extras as it is to the startDestination:

navController.setGraph(R.navigation.<you_nav_graph_xml>, intent.extras)

Since intent.extras would return a Bundle only

When you are setting the navGraph using setGraph() method, you should avoid setting the app:NavGraph attribute in the NavHostFragment definition, because doing so results in inflating and setting the navigation graph twice.

While reading these arguments in your startDestination fragment:

If you are using the Safe Args Plugin (which is very much recommended), then in your fragment:

private val args by navArgs<DummyFragmentArgs>()

Safe Args plugin would generate an Args class by appending Args to your fragment name. For example, if you fragment is called DummyFragment then Safe Args would generate a class called DummyFragmentArgs

where navArgs<> is an extension function defined in Android KTX

If you are not using Android KTX, you can get the args object like:

val args = DummyFragmentArgs.fromBundle(arguments!!)

Once you've acquired the arguments object, you can simply fetch your arguments:

args.someArgument

Notice how we passed "some_argument" as argument, and we are reading it as someArgument using Safe Args

If you are not using Safe Args (there is no reason to not use it though), you can access your arguments like this:

arguments?.getString("some_argument")

All of this is documented in Migrate to Navigation Component documentation here: https://developer.android.com/guide/navigation/navigation-migrate#pass_activity_destination_args_to_a_start_destination_fragment

like image 128
Praveen Singh Avatar answered Sep 18 '22 08:09

Praveen Singh


i also came across same issue,

This is how i resolved it:

  1. Remove the the xml setup of NavHostFragment from your_activity.xml : i.e remove app:navGraph="@navigation/nav_graph

This is how your XML Should look like.

        <fragment
        android:id="@+id/nav_host"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        />
  1. Add Setup for NavHostFragment Programatically in onCreate() of activity. And pass bundle data using NavGraph.addDefaultArguments(bundleData) api

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.editor_layout)
            setupNavigation()
        }
    
        private fun setupNavigation() {
            val navHostFragment = nav_host as NavHostFragment
            val navController = navHostFragment.navController
            val navInflater = navController.navInflater
            val graph = navInflater.inflate(R.navigation.nav_graph)
            graph.addDefaultArguments(intent!!.extras!!) // This is where you pass the bundle data from Activity to StartDestination 
            navHostFragment.navController.graph = graph
        }
    

UPDATE:

Dependencies in my Project Gradle file:

dependencies {

    def nav_version = "1.0.0-alpha08"

    implementation "android.arch.navigation:navigation-fragment:$nav_version" // use -ktx for Kotlin
    implementation "android.arch.navigation:navigation-ui:$nav_version" // use -ktx for Kotlin}
}

NOTE: In Navigation Component version 1.0.0-alpha09 for some reason google have no method as addDefaultArguments() might be fixed soon. But lower version's have addDefaultArguments() method.I have checked both in java and kotlin so try using 1.0.0-alpha07 or 1.0.0-alpha08

like image 36
Anmol Avatar answered Sep 20 '22 08:09

Anmol