Can we use Android Jetpack Navigation Component with Settings preferences? Can we use Android Jetpack Navigation Component with Settings preferences? android android

Can we use Android Jetpack Navigation Component with Settings preferences?


The google documentation states that hierarchical nesting of preferences are now deprecated in favour of inter-fragment navigation; that is the structure <PreferencesScreen> ... <PreferencesScreen ...> ... </PreferenceScreen> ... </PreferenceScreen> is now out.

The documents propose that one replace the nested <PreferenceScreen/> with a preference and set the app:fragment attribute, hence

<xml ...><PreferencesScreen ...>    <Preference        android:title="Title"        app:fragment="TLD.DOMAIN.PACKAGE.preferences.SUBPreferenceFragment"        app:destination="@+id/SUBPreferenceFragment" # Not supported by Schema        android:summary="Summary"/> </PreferenceScreen>

Note : It'd be mighty handy if they allowed app:destination="@+id/SUBPreferenceFragment" to identify the navigation destination; I simply duplicate app:destination from the navigation graph's XML file.

From the documentation it is then possible to navigate between the PREFERENCEFramgents by referencing this preference.fragment as follows

class Activity : AppCompatActivity(),                  // Preferences Interface                  PreferenceFragmentCompat.OnPreferenceStartFragmentCallback{    ...    override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, preference: Preference): Boolean     {        // Instantiate the new Fragment        val args = preference.extras        val fragment = supportFragmentManager.fragmentFactory.instantiate(            classLoader,            preference.fragment)        fragment.arguments = args        fragment.setTargetFragment(caller, 0)        // Replace the existing Fragment with the new Fragment        supportFragmentManager.beginTransaction()            .replace(R.id.FRAGMENT, fragment)            .addToBackStack(null)            .commit()       return true    }    ...}

There is however a small Snafoo ! R.id.FRAGMENT in a normal activity represents the placeholder within the activities' view where one would swap the main fragments in an out of existence. When using Navigation R.id.FRAGMENT maps to R.id.NAVIGATION and the code above swaps out the entire navigation fragment with the preference. For an activity using Navigation a reformulation is necessary.

class Activity : AppCompatActivity(),                  // Preferences Interface                  PreferenceFragmentCompat.OnPreferenceStartFragmentCallback{    ...    override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, preference: Preference): Boolean {        // Retrieve the navigation controller        val navctrl = findNavController(R.id.navigation)        // Identify the Navigation Destination        val navDestination = navctrl.graph.find { target -> preference.fragment.endsWith(target.label?:"") }         // Navigate to the desired destination        navDestination?.let { target -> navctrl.navigate(target.id) }    }    ...}

While this works I am a bit dubious about the line that determines the navDestination. If you have a better incantation for val navDestination = navctrl.graph.find { target -> preference.fragment.endsWith(target.label?:"") } then please edit the question or leave a comment accordingly so I can update the answer.


Yes, you can use Navigation components inside Preference fragments.

I have also a main preference fragment with multiple nested fragments. For me the best way was to navigate just inside preference fragments without any activity. So I created onPreferenceClickListeners and navigate just like you would from a normal fragment.

findPreference(getString(R.string.PREF_GN_BUTTON_MAIN)).setOnPreferenceClickListener(preference5 -> {            Navigation.findNavController(requireView()).navigate(R.id.another_settings_fragment);            return true;        });

The advantage of this way is that you can use gradle plugin Safe args to navigate between destinations. So it is a little bit safer than to use it only with ids just like Carel from Activity.

I tried to override onPreferenceStartFragment in my activity but I could not see any advantages of it. I use single Activity architecture.