java.lang.IllegalArgumentException: Navigation action/destination - android

I'm building a notes application. I want to save the note when user press the back button from the createsNotesFragment and finish the createNotesFragment so that I can move to the homeFragment.
The code I've used to do this is below:
activity?.onBackPressedDispatcher?.addCallback(this){
saveNote()
activity?.supportFragmentManager?.popBackStack()
}
This is working fine. But when I try to again open the createNotesFragment to add an another note it shows me this error.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.lavanianotesapp, PID: 4952
java.lang.IllegalArgumentException: Navigation action/destination com.example.lavanianotesapp:id/action_homeFragment_to_createNotesFragment cannot be found from the current destination Destination(com.example.lavanianotesapp:id/createNotesFragment) label=fragment_create_notes class=com.example.lavanianotesapp.UI.Fragments.CreateNotesFragment
at androidx.navigation.NavController.navigate(NavController.kt:1540)
at androidx.navigation.NavController.navigate(NavController.kt:1472)
at androidx.navigation.NavController.navigate(NavController.kt:1454)
at androidx.navigation.NavController.navigate(NavController.kt:1437)
Here 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/homeFragment">
<fragment
android:id="#+id/homeFragment"
android:name="com.example.lavanianotesapp.UI.Fragments.HomeFragment"
android:label="fragment_home"
tools:layout="#layout/fragment_home" >
<action
android:id="#+id/action_homeFragment_to_createNotesFragment"
app:destination="#id/createNotesFragment" />
<action
android:id="#+id/action_homeFragment_to_editNotesFragment"
app:destination="#id/editNotesFragment" />
</fragment>
<fragment
android:id="#+id/createNotesFragment"
android:name="com.example.lavanianotesapp.UI.Fragments.CreateNotesFragment"
android:label="fragment_create_notes"
tools:layout="#layout/fragment_create_notes" >
<action
android:id="#+id/action_createNotesFragment_to_homeFragment"
app:destination="#id/homeFragment" />
<action
android:id="#+id/action_createNotesFragment_to_addLabelFragment"
app:destination="#id/addLabelFragment" />
</fragment>
<fragment
android:id="#+id/editNotesFragment"
android:name="com.example.lavanianotesapp.UI.Fragments.EditNotesFragment"
android:label="fragment_edit_notes"
tools:layout="#layout/fragment_edit_notes" >
<action
android:id="#+id/action_editNotesFragment_to_homeFragment"
app:destination="#id/homeFragment" />
<action
android:id="#+id/action_editNotesFragment_to_addLabelFragment"
app:destination="#id/addLabelFragment" />
</fragment>
<fragment
android:id="#+id/addLabelFragment"
android:name="com.example.lavanianotesapp.UI.Fragments.AddLabelFragment"
android:label="fragment_add_label"
tools:layout="#layout/fragment_add_label" >
<action
android:id="#+id/action_addLabelFragment_to_createNotesFragment"
app:destination="#id/createNotesFragment" />
<action
android:id="#+id/action_addLabelFragment_to_editNotesFragment"
app:destination="#id/editNotesFragment" />
</fragment>
</navigation>
I don't understant why after popBackStack() I'm not able to open the createNotesFragment again.
Is there any alternative of popBackStack or what I'm missing?

you could try check current destination of your current screen like this:
//id = nav graph fragment id
if (findNavController().currentDestination?.id == id) {
//do something here
findNavController().popBackStack()
}

nav Graph file,
<fragment
android:id="#+id/createNotesFragment"
android:name="com.example.lavanianotesapp.UI.Fragments.CreateNotesFragment"
android:label="#string/fragment_create_notes"
tools:layout="#layout/fragment_create_notes">
<action
android:id="#+id/action_createNotesFragment_to_homeFragment"
app:destination="#id/nav_home"
app:launchSingleTop="true"
app:popUpTo="#id/nav_trip"
app:popUpToInclusive="true">
<argument
android:name="trip_info_response"
android:defaultValue="#null"
app:argType="com.example.lavanianotesapp.UI.entities.TripInfoData"
app:nullable="true" />
</action>
User press the back button from the createsNotesFragment file,
activity?.onBackPressedDispatcher?.addCallback(this){
saveNote()
findNavController().popBackStack()
}

Related

Is there a way to update Jetpack Navigation Graph for a Fragment that can be accessible by any Fragment in the Graph?

Given I have a Jetpack Navigation Graph as below, where by
BlankFragment1 -> BlankFragment2 -> BlankFragment3 -> BlankFragment4 -> BlankFragment5
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
app:startDestination="#id/blankFragment1">
<fragment
android:id="#+id/blankFragment1"
android:name="com.example.cashdog.cashdog.BlankFragment1"
android:label="#string/label_blank1"
tools:layout="#layout/fragment_blank1" >
<action
android:id="#+id/action_blankFragment1_to_blankFragment2"
app:destination="#id/blankFragment2" />
</fragment>
<fragment
android:id="#+id/blankFragment2"
android:name="com.example.cashdog.cashdog.BlankFragment2"
android:label="#string/label_blank2"
tools:layout="#layout/fragment_blank2" >
<action
android:id="#+id/action_blankFragment2_to_blankFragment3"
app:destination="#id/blankFragment3" />
</fragment>
<fragment
android:id="#+id/blankFragment3"
android:name="com.example.cashdog.cashdog.BlankFragment3"
android:label="#string/label_blank3"
tools:layout="#layout/fragment_blank3" >
<action
android:id="#+id/action_blankFragment3_to_blankFragment4"
app:destination="#id/blankFragment4" />
</fragment>
<fragment
android:id="#+id/blankFragment4"
android:name="com.example.cashdog.cashdog.BlankFragment4"
android:label="#string/label_blank4"
tools:layout="#layout/fragment_blank4" >
<action
android:id="#+id/action_blankFragment4_to_blankFragment5"
app:destination="#id/blankFragment5" />
</fragment>
<fragment
android:id="#+id/blankFragment5"
android:name="com.example.cashdog.cashdog.BlankFragment5"
android:label="#string/label_blank5"
tools:layout="#layout/fragment_blank5" />
</navigation>
If I have another Fragment, named FragmentSomething, that can be open by and of the FragmentBlank1 to FragentBlank5
Is there a way to update the NavGraph above for my FragmentSomething, without the need to add actions for all 5 of them?
Apparently, there's something called the global action
https://developer.android.com/guide/navigation/navigation-global-action
We just need to add this
<action android:id="#+id/action_global_somethingFragment"
app:destination="#id/somethingFragment"/>
<fragment
android:id="#+id/somethingFragment"
android:name="com.example.cashdog.cashdog.SomethingFragment"
android:label="#string/label_something"
tools:layout="#layout/fragment_something" />
Or we can navigate the code directly to somethingFragment using
findNavController().navigate(R.id.somethingFragment)

Navigating to other graph part in navigation components

I have the problem that my sample app crashes when I deeplink from one graph part to the other one.
My structure is simple:
Two tabs with own graphs which have each two possible fragments
When I navigate to a detail page (in my sample a book) this just works from my "Shelf" but not from the home screen.
Here is my full 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/sample"
app:startDestination="#id/tab_home">
<navigation
android:id="#+id/tab_home"
app:startDestination="#id/frag_home">
<fragment
android:id="#+id/frag_home"
android:name="eu.rekisoft.android.navbug.HomeFragment"
tools:layout="#layout/fragment_home">
<action
android:id="#+id/cause_bug"
app:destination="#id/frag_hint"/>
<action
android:id="#+id/causeCrash"
app:destination="#id/frag_book">
<argument
android:name="name"
app:argType="string"/>
</action>
</fragment>
<fragment
android:id="#+id/frag_hint"
android:name="eu.rekisoft.android.navbug.HintFragment"
android:label="Hint"
tools:layout="#layout/fragment_hint"/>
</navigation>
<navigation
android:id="#+id/tab_books"
app:startDestination="#id/frag_shelf">
<fragment
android:id="#+id/frag_shelf"
android:name="eu.rekisoft.android.navbug.ShelfFragment"
android:label="Shelf Fragment"
tools:layout="#layout/fragment_shelf">
<action
android:id="#+id/open_book"
app:destination="#id/frag_book">
<argument
android:name="name"
app:argType="string"/>
</action>
</fragment>
<fragment
android:id="#+id/frag_book"
android:name="eu.rekisoft.android.navbug.BookFragment"
android:label="Book Fragment"
tools:layout="#layout/fragment_book">
<argument
android:name="name"
app:argType="string"/>
</fragment>
</navigation>
</navigation>
Here is my crash:
java.lang.IllegalArgumentException: Navigation destination eu.rekisoft.android.navbug:id/frag_book referenced from action eu.rekisoft.android.navbug:id/causeCrash cannot be found from the current destination Destination(eu.rekisoft.android.navbug:id/frag_home) class=eu.rekisoft.android.navbug.HomeFragment
at androidx.navigation.NavController.navigate(NavController.kt:1527)
at androidx.navigation.NavController.navigate(NavController.kt:1464)
at androidx.navigation.NavController.navigate(NavController.kt:1922)
at eu.rekisoft.android.navbug.HomeFragment.onViewCreated$lambda-2$lambda-1(HomeFragment.kt:23)
at eu.rekisoft.android.navbug.HomeFragment.$r8$lambda$q53N5QXeJ-lbbpd7MjwkcKbt9_4(Unknown Source:0)
at eu.rekisoft.android.navbug.HomeFragment$$ExternalSyntheticLambda1.onClick(Unknown Source:2)
Very clear error message, but I don't know how to fix this.
If you want to checkout my code check this GitHub repo.

NavHostFragment Manager backstack is not proper

I am using navigation architecture component in my application.
Suppose I have fragment A as start destination.
I have push fragment B and Fragment C via navigation controller.
My navigation back stack is A-> B-> C.
Then I navigate to Fragment A with below action
<action
android:id="#+id/fragment_A_type"
app:destination="#id/fragment_a"
app:popUpTo="#id/fragment_a"
app:popUpToInclusive="true" />
Now My navigation back stack should be A.
But if check
parentFragmentManager.fragments back stack is
A->A
Also the swipeBackDismiss of activity is not working.
my navigation.xml file
<?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">
<fragment
android:id="#+id/FirstFragment"
android:name="com.example.wearexample1.FirstFragment"
android:label="#string/first_fragment_label"
tools:layout="#layout/fragment_first">
<action
android:id="#+id/action_FirstFragment_to_SecondFragment"
app:destination="#id/SecondFragment" />
</fragment>
<fragment
android:id="#+id/SecondFragment"
android:name="com.example.wearexample1.SecondFragment"
android:label="#string/second_fragment_label"
tools:layout="#layout/fragment_second">
</fragment>
<action
android:id="#+id/action_global_activity_type"
app:destination="#id/FirstFragment"
app:popUpTo="#id/FirstFragment"
app:popUpToInclusive="true" />
</navigation>

Android Navigation Components always returns to the start destination

I'm using the Navigation Component and I have 1 Activity with 3 fragments (startDestination: mainFragment , levelFragment and gameFragment). if I'm in levelFragment, it returns to mainFragment, and if I'm in gameFragment it should return to levelFragment, but it returns to mainFragment instead.
I followed the documentation in order to solve the problem but I didn't find any solutions and it's still happening, Why?
Note: gameFragment returns to levelFragment(it appears for just a split second) then immediately returns to mainFragment.
Here's my navigation.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/main_nav"
app:startDestination="#id/mainFragment">
<fragment
android:id="#+id/mainFragment"
android:name="com.hroub.physicsapp.MainFragment"
android:label="fragment_main"
tools:layout="#layout/fragment_main" >
<action
android:id="#+id/action_mainFragment_to_levelFragment"
app:destination="#id/levelFragment"
app:enterAnim="#android:anim/fade_in"
app:exitAnim="#android:anim/fade_out"
app:popEnterAnim="#android:anim/fade_in"
app:popExitAnim="#android:anim/fade_out" />
</fragment>
<fragment
android:id="#+id/gameFragment"
android:name="com.hroub.physicsapp.GameFragment"
android:label="fragment_game"
tools:layout="#layout/fragment_game" >
<argument
android:name="index"
app:argType="integer"
android:defaultValue="0" />
<argument
android:name="concept"
app:argType="com.hroub.physicsapp.model.Concept" />
<action
android:id="#+id/action_gameFragment_to_levelFragment"
app:destination="#id/levelFragment"
app:popUpTo="#id/levelFragment"
app:popUpToInclusive="true"
/>
</fragment>
<fragment
android:id="#+id/levelFragment"
android:name="com.hroub.physicsapp.LevelFragment"
android:label="fragment_level"
tools:layout="#layout/fragment_level" >
<action
android:id="#+id/action_levelFragment_to_gameFragment"
app:destination="#id/gameFragment"
app:enterAnim="#android:anim/fade_in"
app:exitAnim="#android:anim/fade_out"
app:popEnterAnim="#android:anim/fade_in"
app:popExitAnim="#android:anim/fade_out" />
<argument
android:name="position"
app:argType="integer"
android:defaultValue="0" />
</fragment>
Code to navigate to levelFragment :
MainFragmentDirections.ActionMainFragmentToLevelFragment action = MainFragmentDirections.actionMainFragmentToLevelFragment();
action.setPosition(getLayoutPosition());
Navigation.findNavController((Activity)context, R.id.main_host).navigate(action);
Code to navigate to gameFragment :
LevelFragmentDirections.ActionLevelFragmentToGameFragment action = LevelFragmentDirections.actionLevelFragmentToGameFragment(concept);
action.setIndex(getLayoutPosition());
action.setConcept(concept);
Navigation.findNavController((Activity)context, R.id.main_host).navigate(action);
from gameFragment to levelFragment :
Navigation.findNavController(requireActivity(), R.id.main_host).navigate(R.id.action_gameFragment_to_levelFragment);

java.lang.IllegalStateException ConstraintLayout does not have a NavController set for a fragment

I have an activity (main) with three fragments (first, second and third). I included the 3 fragments in my activity (activity_main.xml) by using <include layout="#layout/content_main"/>.
The content_main.xml is using FragmentContainerView with id = nav_host_fragment. And this is 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/FirstFragment">
<fragment
android:id="#+id/FirstFragment"
android:name="com.example.makegroups.FirstFragment"
android:label="#string/first_fragment_label"
tools:layout="#layout/fragment_first">
<action
android:id="#+id/action_FirstFragment_to_SecondFragment"
app:destination="#id/SecondFragment" />
</fragment>
<fragment
android:id="#+id/SecondFragment"
android:name="com.example.makegroups.SecondFragment"
android:label="#string/second_fragment_label"
tools:layout="#layout/fragment_second">
<action
android:id="#+id/action_SecondFragment_to_FirstFragment"
app:destination="#id/FirstFragment" />
<action
android:id="#+id/action_SecondFragment_to_ThirdFragment"
app:destination="#id/ThirdFragment" />
</fragment>
<fragment
android:id="#+id/ThirdFragment"
android:name="com.example.makegroups.ThirdFragment"
android:label="#string/third_fragment_label"
tools:layout="#layout/fragment_third">
<action
android:id="#+id/action_ThirdFragment_to_FirstFragment"
app:destination="#id/FirstFragment" />
</fragment>
</navigation>
I have a floatingactionbuttonin my activity (first fragmentstarts first) and when I click on it, I open the third fragment.
On the third fragment I have a button (next) to navigate to the first fragment, and when I click on it, I am back to first fragment using:
Fragment frg = new FirstFragment();
FragmentManager fm = requireActivity().getSupportFragmentManager();
Now (while I am in the first fragment), I click on the button next(another button to navigate to the second fragment), then the app crashes. I found this error:
java.lang.IllegalStateException: View androidx.constraintlayout.widget.ConstraintLayout{c9572fa V.E...... ........ 0,0-1440,2112} does not have a NavController set
Why I am getting this error? -I tried these suggestions here, without success.
I am using Java.
EDIT:
Read the last comment with #Zain to know why I got the error.
Bu using Navigation Architecture components, The NavController is the responsible for fragment transaction and managing the back stack instead of the Support FragmentManager.
So, instead of making tranditional framgnet transactions with FragmentManager
You can move from ThridFragment to the first one by:
Navigation.findNavController(requireView()).navigate(R.id.action_ThirdFragment_to_FirstFragment);
Where action_ThirdFragment_to_FirstFragment is the id of the action you defined in the navigation graph to move from ThridFragment to FirstFragment
UPDATE:
As discussed from comments, besides replacing FragmentManager by NavController in all actions; there is another issue:
Missing of action_FirstFragment_to_ThirdFragment action from the navigation graph.
navController = Navigation.findNavController(activity, R.id.nav_host_fragment)
when using the Navigation Component you should not handle the transactions yourself, instead you define the actions between each fragment and then access those directly like this
override fun onCreate(){
val navController = this.findNavController()
button.setOnClickListener{
navController.navigate(R.id.action_FirstFragment_to_SecondFragment, null)
}
}
and your nav_graph should be like this
<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/FirstFragment">
<fragment
android:id="#+id/FirstFragment"
android:name="com.example.makegroups.FirstFragment"
android:label="#string/first_fragment_label"
tools:layout="#layout/fragment_first">
<action
android:id="#+id/action_FirstFragment_to_SecondFragment"
app:destination="#id/SecondFragment" />
</fragment>
<fragment
android:id="#+id/SecondFragment"
android:name="com.example.makegroups.SecondFragment"
android:label="#string/second_fragment_label"
tools:layout="#layout/fragment_second">
<action
android:id="#+id/action_SecondFragment_to_FirstFragment"
app:destination="#id/FirstFragment" />
<action
android:id="#+id/action_SecondFragment_to_ThirdFragment"
app:destination="#id/ThirdFragment" />
</fragment>
<fragment
android:id="#+id/ThirdFragment"
android:name="com.example.makegroups.ThirdFragment"
android:label="#string/third_fragment_label"
tools:layout="#layout/fragment_third">
<action
android:id="#+id/action_ThirdFragment_to_FirstFragment"
app:destination="#id/FirstFragment" />
</fragment>
val navController = Navigation.findNavController(requireActivity(), R.id.fragment_container)
navigate.navigate(R.id.fragment)

Categories

Resources