简体   繁体   中英

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 ie 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 ?

i also came across same issue,

This is how i resolved it:

  1. Remove the the xml setup of NavHostFragment from your_activity.xml : ie 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

I found the solution after some research. It works with the latest Navigation library release. Refer the below code:

  1. Add this in your activity layout. Note: We are not setting app:navGraph argument in the xml file. We will set it dynamically.

     <fragment android:id="@+id/fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" app:defaultNavHost="true" />
  2. In your activity java file, write the below code and make changes accordingly. Use NavArgument to pass your argument value and add the argument to your custom Navgraph and then set graph.

     public class YourActivity extends AppCompatActivity { private NavArgument nameArg, mailArg; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.profile); nameArg = new NavArgument.Builder().setDefaultValue("your name").build(); mailArg = new NavArgument.Builder().setDefaultValue("your email id").build(); NavController navController = Navigation.findNavController(this, R.id.fragment); NavInflater navInflater = navController.getNavInflater(); NavGraph navGraph = navInflater.inflate(R.navigation.nav_profile_graph); navGraph.addArgument("your name key", nameArg); navGraph.addArgument("your mail key", mailArg); navController.setGraph(navGraph); } }
  3. Write the navigation graph below and add the same argument keys to the starting fragment.

     <?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" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/nav_graph" app:startDestination="@+id/profile_basic"> <fragment android:id="@+id/profile_basic" android:name="com.yourpackage.ProfileBasicFragment" android:label="Profile Basic" tools:layout="@layout/fragment_profile_basic"> <argument android:name="your name key" app:argType="string"/> <argument android:name="your mail key" app:argType="string"/> </fragment> </navigation>
  4. In your fragment, just fetch the values using getArguments() function.

     String name = getArguments().getString("your name key"); String mail = getArguments().getString("your mail key");

you can add arguments in your graph like this

<fragment
  android:id="@+id/exampleFragment"
  android:label="example_fragment"
  android:name="com.example.yourapp.ui.ExampleFragment"
  tools:layout="@layout/example_fragment">
<argument
  android:name="exampleArgs"
  app:argType="reference"
  android:defaultValue="@string/example"/>
</fragment>

https://developer.android.com/guide/navigation/navigation-pass-data

Though it is a late answer there is a very easy way for passing bundles using navigation controller/Navigation Architecture:

Fragment that will send data

//Best to put in onViewCreated
val navController = findNavController()

//Put in code where you want to start navigation
val b = Bundle()
b.putString("key_1", "Data 1")
b.putString("key_2", "Data 2")

navController.navigate(R.id.action_signupFragment_to_signinFragment,b)

Fragment that will receive data

val data_1: String = arguments?.getString("key_1")?:""
val data_1: String = arguments?.getString("key_2")?:"" 

Depending on the type of data you are sending you need to update the safe call or make the variables nullable.

I cannot find this method, too. It is not existant in the architecture components documentation.

But the is another way to set arguments to the start destination:

// Kotlin Code, in Fragment
with(findNavController().graph) {
    get(startDestination).addArgument(...)
}

I checked the source code an saw that there a lot of changes regarding navigation destination and arguments. I think the proper way to pass arguments to start destination is using 'addArgument' method, something like this:

val argument1 = 1 //First value
val argument2 = "Value" //Second value
val navArgument1=NavArgument.Builder().setDefaultValue(argument1).build()
val navArgument2=NavArgument.Builder().setDefaultValue(argument2).build()
navController.getGraph().addArgument("Key1",navArgument1)
navController.getGraph().addArgument("Key2",navArgument2)

Maybe there is a better way, but i didn't found one.

class MainActivity : BaseActivity()  {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val navHostFragment = container as NavHostFragment
        val inflater = navHostFragment.navController.navInflater
        val graph = inflater.inflate(R.navigation.main_nav)

        var data : Data  = intent.getParcelableExtra("DATA") as Data
        var bundle : Bundle = Bundle()
        bundle.putParcelable("DATA", data)
        graph.addDefaultArguments(bundle)
        graph.addDefaultArguments(intent!!.extras!!)
        navHostFragment.navController.graph = graph

    }
}

Add the above code in Activity for sending the data using using navigation

override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        var data = NavHostFragment.findNavController(this).graph.defaultArguments.getParcelable("DATA") as Booking

}

Add the above code in fragment side

Navigation 1.0.0

        val navHostFragment = root_nav_host_fragment as NavHostFragment
        val navController = navHostFragment.navController
        val navInflater = navController.navInflater
        val graph = navInflater.inflate(R.navigation.navigation)
        val sectionId = intent.getIntExtra(KEY_SECTION_ID, -1)
        val bundle = bundleOf(KEY_SECTION_ID to sectionId)
        navHostFragment.navController.setGraph(graph, bundle)

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM