Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NavController.OnDestinationChangedListener passes a destination.id not matching the triggered Navigation Action ID

In my Android project I have a very simple Navigation Graph, including two fragments: Master and Detail:

<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"
   app:startDestination="@id/wordsListFragment">

    <fragment
        android:id="@+id/wordsListFragment"
        android:name="com.***.presentation.view.WordsListFragment"
        android:label="List"
        tools:layout="@layout/words_list_fragment">
        <action
            android:id="@+id/action_wordsListFragment_to_wordDetailsFragment"
            app:destination="@id/wordDetailsFragment" />
    </fragment>
    <fragment
        android:id="@+id/wordDetailsFragment"
        android:name="com.***.presentation.view.WordDetailsFragment"
        android:label="Details"
        tools:layout="@layout/word_details_fragment" />
</navigation>

The navigation itself works perfectly fine in both directions including the "Back" behaviour. In that project I have a single activity where I implement OnDestinationChangedListener. All this according to the following documentation from Google: NavController Updating UI

I call the following method when the user clicks on a list item (while being on the master fragment):

findNavController().navigate(R.id.action_wordsListFragment_to_wordDetailsFragment, null)

Then in the parent activity I have the following implementation:

private fun setupNavController() {
    navigationController = findNavController(R.id.nav_mainhost_fragment_container)
    navigationController.addOnDestinationChangedListener(mainDestinationChangedListener)
    appBarConfiguration = AppBarConfiguration(navigationController.graph)
    setupActionBarWithNavController(navigationController, appBarConfiguration)
}

and that is the listener object:

private val mainDestinationChangedListener = 
NavController.OnDestinationChangedListener { controller, destination, arguments ->        

if (destination.id == R.id.action_wordsListFragment_to_wordDetailsFragment) {
        actionBar?.hide()
    } else {
        actionBar?.show()
    }
}

but the destination.id does not match the R.id.action_wordsListFragment_to_wordDetailsFragment

I have tried to clean up the project, clean up the IDE cache, the gradle cache, but the generated identifiers still does not match. I have also tried to use Navigation via Safe Args:

val action = WordsListFragmentDirections.actionWordsListFragmentToWordDetailsFragment()
findNavController().navigate(action)

but the results in the given listener are always the same (i.e. not matching).

Some values from debugging:

findNavController().navigate(1000021) //R.id.action_wordsListFragment_to_wordDetailsFragment

but the next call on stack has another value: enter image description here what also matches the destination.id values passed to the OnDestinationChangedListener:

destination.id //2131231018

Any hints from your side are more than welcome. I just want to recognise the destination or the action ID and adjust the ToolBar accordingly.

like image 396
gary0707 Avatar asked Mar 14 '20 10:03

gary0707


People also ask

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()

What is NavController in Android?

NavController manages app navigation within a NavHost . Apps will generally obtain a controller directly from a host, or by using one of the utility methods on the Navigation class rather than create a controller directly. Navigation flows and destinations are determined by the navigation graph owned by the controller.

How do you complete a fragment navigation component?

How do I get rid of current fragment navigation component? You add to the back state from the FragmentTransaction and remove from the backstack using FragmentManager pop methods: FragmentManager manager = getActivity(). getSupportFragmentManager();


2 Answers

You are comparing fragmentId with actionId so it's always false

here if (destination.id == R.id.action_wordsListFragment_to_wordDetailsFragment)

As destination.id is fragmentId and R.id.action_wordsListFragment_to_wordDetailsFragment is actionId

To make it work you should compare two fragment ids like

if (destination.id == R.id.wordDetailsFragment)

*Edit

First you should find you navControler , then listen to its destination change.

val navController = findNavController(this,R.id.nav_host_fragment)// this maybe change
navController.addOnDestinationChangedListener { controller, destination, arguments ->
   if(destination.id == R.id.wordDetailsFragment) {
       actionBar?.hide()
   } else {
       actionBar?.show()
   }
}
like image 197
Mohammed Alaa Avatar answered Oct 14 '22 05:10

Mohammed Alaa


The issue is with the Android studio debugger. If I print the value in logcat or assign it to a variable, then the value is 2XXXXXXXXX but if I evaluate with debugger then the value is 1XXXXXX.

I have checked the action id(R.id.xxxx) hex code in the APK. When I convert the hex code into integer, it gives a value in 2XXXXXXXXX which is equal to the value that got printed in the logcat

like image 5
Nanzbz Avatar answered Oct 14 '22 07:10

Nanzbz