Home > Software engineering >  Android BottomNavigationView recreating Fragments each time with Navigation Component
Android BottomNavigationView recreating Fragments each time with Navigation Component

Time:11-24

I'm using a BottomNavigationView to switch between a Home and Meetings fragment. Each time I switch between them, each Fragment is recreated. I'm using a SharedViewModel between them for a shared "meetingID" variable, but that's being destroyed and recreated along with the Fragments (aggravatingly so). I'm using Jetpack Navigation Component; I almost completely copied the Google example here. It's still not working, however.

Here's a look at my onCreate and onSupportNavigateUp:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val navHostFragment = supportFragmentManager
            .findFragmentById(R.id.nav_host_fragment)
                as NavHostFragment

        navController = navHostFragment.navController
        setSupportActionBar(binding.toolBar)

        appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.homeFragment, R.id.meetingFragment
            )
        )

        setupActionBarWithNavController(navController, appBarConfiguration)

        binding.apply {
            navController.addOnDestinationChangedListener { _, destination, _ ->
                if (destination.id == R.id.loginFragment
                    || destination.id == R.id.registerFragment
                ) {
                    bottomNavigation.visibility = View.GONE
                } else {
                    bottomNavigation.visibility = View.VISIBLE
                }
            }

            bottomNavigation.setupWithNavController(navController)
        }
    }

    override fun onSupportNavigateUp(): Boolean {
        return navController.navigateUp(appBarConfiguration)
    }

My nav_graph is rather ugly:

<?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/loginFragment">
    <fragment
        android:id="@ id/loginFragment"
        android:name="edu.fsu.equidistant.fragments.LoginFragment"
        android:label="fragment_login"
        tools:layout="@layout/fragment_login">
        <action
            android:id="@ id/action_loginFragment_to_homeFragment"
            app:destination="@id/homeFragment"
            app:launchSingleTop="true"
            app:popUpTo="@ id/nav_graph"
            app:popUpToInclusive="true" />
        <action
            android:id="@ id/action_loginFragment_to_registerFragment"
            app:destination="@id/registerFragment" />
    </fragment>
    <fragment
        android:id="@ id/registerFragment"
        android:name="edu.fsu.equidistant.fragments.RegisterFragment"
        android:label="fragment_register"
        tools:layout="@layout/fragment_register">
        <action
            android:id="@ id/action_registerFragment_to_homeFragment"
            app:destination="@id/homeFragment"
            app:launchSingleTop="true"
            app:popUpTo="@ id/nav_graph"
            app:popUpToInclusive="true" />
        <action
            android:id="@ id/action_registerFragment_to_loginFragment"
            app:destination="@id/loginFragment" />
    </fragment>
    <fragment
        android:id="@ id/homeFragment"
        android:name="edu.fsu.equidistant.fragments.HomeFragment"
        android:label="Home"
        tools:layout="@layout/fragment_home" >
        <argument
            android:name="email"
            app:argType="string" >
        </argument>

        <argument
            android:name="userId" >
        </argument>
        <action
            android:id="@ id/action_homeFragment_to_loginFragment"
            app:destination="@id/loginFragment" />
        <action
            android:id="@ id/action_homeFragment_to_profileFragment"
            app:destination="@id/profileFragment"
            app:enterAnim="@anim/nav_default_enter_anim"
            app:exitAnim="@anim/nav_default_enter_anim" />
    </fragment>
    <fragment
        android:id="@ id/profileFragment"
        android:name="edu.fsu.equidistant.fragments.ProfileFragment"
        android:label="fragment_profile"
        tools:layout="@layout/fragment_profile" >
        <argument
            android:name="userId" >
        </argument>
        <action
            android:id="@ id/action_profileFragment_to_loginFragment"
            app:destination="@id/loginFragment" />
        <action
            android:id="@ id/action_profileFragment_to_homeFragment"
            app:destination="@id/homeFragment"
            app:enterAnim="@anim/nav_default_enter_anim"
            app:exitAnim="@anim/nav_default_exit_anim"
            app:popEnterAnim="@anim/nav_default_pop_enter_anim"
            app:popExitAnim="@anim/nav_default_pop_exit_anim" />
    </fragment>
    <fragment
        android:id="@ id/meetingFragment"
        android:name="edu.fsu.equidistant.fragments.MeetingFragment"
        android:label="Meeting"
        tools:layout="@layout/fragment_meeting" />
</navigation>

I'm setting each Fragment as a top-level with the appBarConfiguration, but nothing. . . any suggestions?

CodePudding user response:

@ianhanniballake was onto the right idea!

I was foolishly using the LoginFragment as my home destination to awkwardly do some conditional logic. A quick refactor, and with HomeFragment set as the actual home destination, it now works. Thanks, @ianhanniballake.

  • Related