问题
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
?
回答1:
i also came across same issue,
This is how i resolved it:
- 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"
/>
Add Setup for NavHostFragment Programatically in
onCreate()
of activity. And pass bundle data usingNavGraph.addDefaultArguments(bundleData)
apioverride 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
回答2:
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
回答3:
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
回答4:
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(...)
}
回答5:
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.
回答6:
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
回答7:
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)
回答8:
I found the solution after some research. It works with the latest Navigation library release. Refer the below code:
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" />
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); } }
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>
In your fragment, just fetch the values using getArguments() function.
String name = getArguments().getString("your name key"); String mail = getArguments().getString("your mail key");
来源:https://stackoverflow.com/questions/53913648/android-navigation-architecture-component-how-to-pass-bundle-data-to-startdesti