I use Android Navigation library for fragment navigation and try pass data back from second fragment to first. Do it with the next code:
findNavController().setGraph(R.navigation.nav_graph, bundle)
findNavController().popBackStack()
It works fine, but when I try to open the same screen after it, the next error occurred:
java.lang.IllegalArgumentException: navigation destination com.leshchenko.test:id/openPurchaseDetailsAction is unknown to this NavController
Thanks.
UPDATE:
My nav_graph.xml
<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/purchasesListFragment">
<fragment
android:id="#+id/purchasesListFragment"
android:name="com.leshchenko.finance.presentation.purchases.PurchasesListFragment"
android:label="fragment_purchases_list"
tools:layout="#layout/fragment_purchases_list">
<action
android:id="#+id/openPurchaseDetailsAction"
app:destination="#+id/purchaseDetailsFragment">
<argument
android:name="purchaseId"
android:defaultValue="-1L"
app:argType="long" />
</action>
</fragment>
<fragment
android:id="#+id/purchaseDetailsFragment"
android:name="com.leshchenko.finance.presentation.purchase_details.PurchaseDetailsFragment"
android:label="fragment_purchase_details"
tools:layout="#layout/fragment_purchase_details">
<argument
android:name="purchaseId"
android:defaultValue="-1L"
app:argType="long" />
</fragment>
Details opens via:
findNavController().navigate(PurchasesListFragmentDirections.openPurchaseDetailsAction())
use findNavController().navigateUp() instead of findNavController().popBackStack()
I think you can just pass your data through viewModel and for fragment finish
just use :
findNavController().popBackStack()
eg:
view.setOnClickListener {
// pass Data through ViewModel
// viewModel.sendData(data)
Navigation.findNavController(it).popBackStack()
}
Related
In my application I have 2 fragment and for show these I use NavigationComponent and I want sent some data.
My navigation codes:
<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_home"
app:startDestination="#id/recipesFragment">
<fragment
android:id="#+id/recipesFragment"
android:name="myapp.ui.fragments.recipe.RecipesFragment"
android:label="#string/recipes"
tools:layout="#layout/fragment_recipes" >
<action
android:id="#+id/action_recipesFragment_to_menuFragment"
app:destination="#id/menuFragment" />
<argument
android:name="isUpdatedData"
app:argType="boolean"
android:defaultValue="false" />
</fragment>
<dialog
android:id="#+id/menuFragment"
android:name="myapp.ui.fragments.recipe.menu.MenuFragment"
android:label="fragment_menu"
tools:layout="#layout/fragment_menu" >
<action
android:id="#+id/action_menuFragment_to_recipesFragment"
app:destination="#id/recipesFragment" />
</dialog>
</navigation>
I set argument with default value, but when use this action into MenuFragment not access to me for set value!
MenuFragment codes:
submitBtn.setOnClickListener {
val action = MenuFragmentDirections.actionMenuFragmentToRecipesFragment(true)
findNavController().navigate(action)
}
When write true for value of actionMenuFragmentToRecipesFragment show me below error:
Too many arguments for public open fun actionMenuFragmentToRecipesFragment(): MenuFragmentDirections.ActionMenuFragmentToRecipesFragment defined in myapp.ui.fragments.recipe.menu.MenuFragmentDirections
How can I fix it and set data with defaultValue?
Hi I hope this answer be useful for you
if you would like to use default value below code will help you:
findNavController().navigate(MenuFragmentDirections.actionMenuFragmentToRecipesFragment().setIsUpdatedData(true))
when you set default value for your argument compiler recognize code does not need setter and if you want change it you have to call setter method of argument in your navigation for custom fragment
I use navigation components to navigate from one fragment to another. However, when the user press the back button, I want to navigate back to first fragment. But it keep showing the second fragment. This is my nav_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"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/nav_graph"
app:startDestination="#id/fragment1">
<fragment
android:id="#+id/fragment2"
android:name="com.myapp.ui.fragments.Fragment2"
android:label="fragment_2" />
<fragment
android:id="#+id/fragment1"
android:name="com.myapp.ui.fragments.Fragment1"
android:label="fragment_1">
<action
android:id="#+id/action_fragment1_to_fragment2"
app:destination="#id/fragment2"
app:enterAnim="#anim/fragment_fade_enter"
app:exitAnim="#anim/fragment_fade_exit"
app:popUpTo="#id/fragment1" />
</fragment>
</navigation>
And this is how I trigger the navigation in the code of my Fragment1-Class:
viewModel.itemSelected.observe(viewLifecycleOwner) {
navigate(it)
}
....
fun navigate(id: Long){
val bundle = Bundle()
bundle.putLong("itemid", id)
getNavController().navigate(R.id.action_fragment1_to_fragment2, bundle)
}
Edit:
Corrected startDestination in XML.
Edit2:
Added more code.
You're using a LiveData for an event. LiveData always caches the set value, so when you return to your Fragment1, you observe the LiveData again and get the same value a second time, causing you to navigate() yet again.
See this blog post for more information and alternatives.
I use navigation components to navigate from one fragment to another. However, when the user press the back button, I want to navigate back to first fragment. But it keep showing the second fragment. This is my nav_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"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/nav_graph"
app:startDestination="#id/fragment1">
<fragment
android:id="#+id/fragment2"
android:name="com.myapp.ui.fragments.Fragment2"
android:label="fragment_2" />
<fragment
android:id="#+id/fragment1"
android:name="com.myapp.ui.fragments.Fragment1"
android:label="fragment_1">
<action
android:id="#+id/action_fragment1_to_fragment2"
app:destination="#id/fragment2"
app:enterAnim="#anim/fragment_fade_enter"
app:exitAnim="#anim/fragment_fade_exit"
app:popUpTo="#id/fragment1" />
</fragment>
</navigation>
And this is how I trigger the navigation in the code of my Fragment1-Class:
viewModel.itemSelected.observe(viewLifecycleOwner) {
navigate(it)
}
....
fun navigate(id: Long){
val bundle = Bundle()
bundle.putLong("itemid", id)
getNavController().navigate(R.id.action_fragment1_to_fragment2, bundle)
}
Edit:
Corrected startDestination in XML.
Edit2:
Added more code.
You're using a LiveData for an event. LiveData always caches the set value, so when you return to your Fragment1, you observe the LiveData again and get the same value a second time, causing you to navigate() yet again.
See this blog post for more information and alternatives.
I'm using Android Jetpack Navigation Component.
I have a nested nav graph with id, say R.id.nested_graph
The first Fragment of the nested graph receives one parameter.
<navigation
android:id="#+id/nested_graph"
android:label="Nested Graph"
app:startDestination="#id/firstFragment">
<fragment
android:id="#+id/firstFragment"
android:name="...."
android:label="....">
<argument
android:name="item_id"
app:argType="integer" />
</fragment>
[...]
</navigation>
How can I pass the parameter to the nested graph using safe args?
At the moment, I need to pass the argument manually in the bundle, using the API that receives the id of the nested graph directly:
val args = Bundle()
args.putInt("item_id", itemId)
navController.navigate(R.id.nested_graph, args)
I'd like to use safe args, and do something like:
val directions = OrigininFragmentDirections.nestedGraph(itemId)
navController.navigate(directions)
But when trying that, I get the following error at build time:
Too many arguments for public final fun nestedGraph(): NavDirections defined
The issue is that the nav graph preprocessing is generating the factory method to create the NavDirections object without the required parameter in the signature.
The declaration of the nested graph looks like this:
After some trial and error experimentation (I don't think it's officially documented by Google, or at least I could not find it), I've discovered that navigating to nested nav graphs passing arguments safely can be done:
You need to add the argument XML object the first fragment expects in the root of the nested fragment itself.
In my case, the fragment with id firstFragment, which is the first fragment in the nested graph receives:
<argument
android:name="item_id"
app:argType="integer" />
Hence, I need to add that argument to the nested graph:
<navigation
android:id="#+id/nested_graph"
android:label="Nested Graph"
app:startDestination="#id/firstFragment">
<argument
android:name="item_id"
app:argType="integer" />
<fragment
android:id="#+id/firstFragment"
android:name="...."
android:label="....">
<argument
android:name="item_id"
app:argType="integer" />
</fragment>
[...]
</navigation>
Now I can navigate to it with:
val directions = OrigininFragmentDirections.nestedGraph(itemId)
navController.navigate(directions)
Note that the navigation graph editor does not do it for you. This needs to be done manually in the XML code.
#GaRRaPeTa answer is almost correct, but if you navigate from main graph to nested graph by action using SafeArgs, you must also add an argument to the action:
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/graph_main"
app:startDestination="#id/mainFragment">
<fragment
android:id="#+id/mainFragment"
android:name="com.example.MainFragment">
<action
android:id="#+id/toNestedGraph"
app:destination="#id/graph_nested">
<argument
android:name="arg_name"
app:argType="string" />
</action>
</fragment>
</navigation>
I want to navigate from HomeFragment to DetailFragment
in RecyclerView item click I am calling DetailFragment and
it is not working ,I see it enters onClickListener but it doesn't go further and it doesn't call DetailFragment
viewBinding.assetImage.setOnClickListener {
val bundle = bundleOf("owner" to "TestUser")
Navigation.createNavigateOnClickListener(R.id.detail_screen,bundle)
}
<fragment
android:id="#+id/home_screen"
android:name="HomeFragment"
android:label="#string/title_home"
tools:layout="#layout/fragment_home">
<action
android:id="#+id/action_home_screen_to_detailFragment"
app:destination="#id/detail_screen" />
</fragment>
<fragment
android:id="#+id/detail_screen"
android:name="DetailFragment"
android:label="DetailFragment"
tools:layout="#layout/fragment_detail">
<argument
android:name="owner"
app:argType="string" />
</fragment>
Below is solution for you,
val bundle = Bundle()
bundle.putString("owner", "TestUser")
if (it.findNavController().currentDestination?.id == R.id.home_screen) {
it.findNavController().navigate(R.id.action_home_screen_to_detailFragment, bundle)
}
You can use safeArgs to pass data.
This can help you
You go to your navigation xml file
Select Fragment to which values are passed.
Add attributes
Build → Rebuild
Then you can use it like this
findNavController().navigate(MenuFragmentDirections.Action_menuFragment_to_servisFragment(param))