Search code examples
androidkotlinandroid-jetpackandroid-jetpack-navigation

BottomNavigationView.setupWithNavController not working


Currently I'm developing an Android app, in which I would like to utilize both Android Navigation Component and BottomNavigationView.

While working on said app I checked out the official codelab and several questions here, but they didn't prove to be of any help.

The problem is that assigning navController to my BottomNavigationView does not seem to have any effect - clicking on menu items does not affect the navigation host.

My code:

main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayoutxmlns: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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/main_host_fr"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/main_nav_bnv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="@android:color/transparent"
        android:elevation="0dp"
        app:elevation="0dp"
        app:menu="@menu/menu_main" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

MainActivity.kt

import android.os.Bundle
import android.os.PersistableBundle
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.NavigationUI
import androidx.navigation.ui.setupWithNavController
import com.aredruss.qurio.databinding.ActivityMainBinding
import com.aredruss.qurio.helpers.viewBinding

class MainActivity : AppCompatActivity() {

    // ViewBindingDelegate
    private val binding: ActivityMainBinding by viewBinding(ActivityMainBinding::inflate)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    
    }

    // Using onPostCreate because accessing NavHost in OnCreate causes crashes
    override fun onPostCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        super.onPostCreate(savedInstanceState, persistentState)
        binding.navigationBb.setupWithNavController(findNavController(R.id.main_host_fr))
        NavigationUI.setupWithNavController(binding.mainNavBnv, findNavController(R.id.main_host_fr))
    }
}

nav_graph.xml

<?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/action_history">

    <fragment
        android:id="@+id/action_history"
        android:name="com.aredruss.qurio.ui.HistoryFragment"
        android:label="HistoryFragment"
        tools:layout="@layout/fragment_history" >
    </fragment>
  
    <fragment
        android:id="@+id/action_settings"
        android:name="com.aredruss.qurio.ui.SettingsFragment"
        android:label="SettingsFragment"
        tools:layout="@layout/fragment_settings" >
    </fragment>
</navigation>

menu_main.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_history"
        android:icon="@drawable/ic_history"
        android:title="History"
        app:showAsAction="withText" />

    <item
        android:id="@+id/action_settings"
        android:title="Settings"
        android:icon="@drawable/ic_settings"
        app:showAsAction="withText"
        />
</menu>

I've checked out this solution and it wasn't of any help.


Solution

  • You've overridden the wrong onPostCreate():

    override fun onPostCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
    

    You don't want the one that takes a PersistableBundle - you want the regular one:

    override fun onPostCreate(savedInstanceState: Bundle?) {
    

    Now your onPostCreate() will actually be called.

    Of course, you shouldn't be using onPostCreate() at all. Instead, you should be following the documentation, which specifically state that you should be using the following code to get your NavController in onCreate():

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

    which lets you write your entire code as:

    // ViewBindingDelegate
    private val binding: ActivityMainBinding by viewBinding(ActivityMainBinding::inflate)
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Note how we actually set the content view from the binding
        setContentView(binding.root)
    
        val navHostFragment =
            supportFragmentManager.findFragmentById(R.id.main_host_fr) as NavHostFragment
        val navController = navHostFragment.navController
    
        binding.navigationBb.setupWithNavController(navController)
        binding.mainNavBnv.setupWithNavController(navController)
    }