Search code examples
android-preferencesandroidxandroid-architecture-navigationandroid-jetpack-navigation

AndroidX Preferences and Navigation


Are there any examples of using the Jetpack / androidx preference library alongside the navigation component / Single activity? All the examples I'm seeing ( e.g. Google's example ) are using supportFragmentManager and replacing the content of a FrameLayout.

Navigating to the PreferenceFragmentCompat() with the navigation component almost works, in that it shows the Preferences page, but it is missing all of the toolbar/navigation icons. It's just implanted over the previous fragment, so to exit it, you need to hit the hardware back button.


Looks like this already has an issue filed with Google's issue tracker here


Solution

  • I just ran into the same problem and this is how I implemented it. Before I get into the code I want to give a quick summary. I have a single activity and two fragments. One of the fragments is the main fragment that is the home screen for the application and the other is the fragment that shows the settings. I end up not using SupportFragmentManager (which Google shows in their settings guide) as I was running into the same problem where the view would just appear on top of the previous view. So I just navigate to the settings fragment in the same way you would navigate to any other fragment in the single activity architecture using findNavController().navigate(...).


    Firstly you will need to add the appropriate dependencies to your app build.gradle:

    dependencies {
        ...
        // androidx Preferences
        implementation "androidx.preference:preference-ktx:1.1.0"
    
        // androidx Navigation
        implementation 'androidx.navigation:navigation-fragment-ktx:2.2.0'
        implementation 'androidx.navigation:navigation-ui-ktx:2.2.0'
    

    Then I set up my MainActivity.kt for Navigation as described in Google's navigation guide

    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            NavigationUI.setupActionBarWithNavController(
                this, this.findNavController(R.id.nav_host_fragment)
            )
    
        }
        // Allows the up arrow to navigate back to the navigation host fragment.
        override fun onSupportNavigateUp(): Boolean {
            return Navigation.findNavController(this, R.id.nav_host_fragment).navigateUp()
        }
    
    }
    

    After that, set up a fragment that will be hosted by MainActivity.kt. This fragment is what will appear when you open up your app. I call mine MainFragment.kt. See Google's menu guide for help on creating the dropdown menu that is inflated when the three dot icon in the toolbar is clicked.

    class MainFragment : Fragment() {
    
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
    
            // Show the three dot icon in the top right had corner of the toolbar
            setHasOptionsMenu(true)
            return inflater.inflate(R.layout.fragment_main, container, false)
        }
    
        override fun onOptionsItemSelected(item: MenuItem): Boolean {
            return when (item.itemId) {
    
                // Navigate to the settings fragment when the options menu item is selected
                R.id.settings -> {
                    findNavController().navigate(MainFragmentDirections.actionMainToSettings())
                    true
                }
                else -> super.onOptionsItemSelected(item)
            }
        }
    
        // Inflates menu.xml when the three dot icon is clicked
        override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
            inflater.inflate(R.menu.menu, menu)
        }
    }
    

    Finally, the settings fragment is pretty easy to implement. Reference Google's settings guide (see link above) on how to set that up.

    class MySettingsFragment : PreferenceFragmentCompat() {
    
        override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
            setPreferencesFromResource(R.xml.preferences, rootKey)
        }
    }
    

    Also, don't forget to hook up your fragments in nav_graph.xml. Reference Google's navigation guide linked above for examples of that.

    Hope this helps!