TheRock
TheRock

Reputation: 97

How to set BottomNavigationView inside Fragment

I have one activity and few fragments. I set up my activity with NavController and navigation graph like this:

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

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

}

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

In this navigation graph I take care of splash screen, login, register fragment and going to main fragment which has a BottomNavigationView with two sub fragments.

I made a menu for bottomNavView fragments and made a graph for them, menu id's match with bottom nav graph id's.

My layout looks like this:

<androidx.fragment.app.FragmentContainerView
    android:id="@+id/nav_host_fragment_main"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:defaultNavHost="true"
    app:layout_constraintBottom_toTopOf="@+id/bottom_Navigation_view"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:navGraph="@navigation/bottom_view_nav_graph" />

<com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/bottom_Navigation_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:menu="@menu/bottom_nav_menu" />

</androidx.constraintlayout.widget.ConstraintLayout>

In main fragment I am trying to set up bottom nav view with navigation graph like this:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    val appCompat = requireActivity() as AppCompatActivity

    val navHostFragment = appCompat.supportFragmentManager.findFragmentById(R.id.nav_host_fragment_main) as NavHostFragment
    val navController = navHostFragment.findNavController()

    binding.bottomNavigationView.setupWithNavController(navController)

}

However I keep getting this exception:

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ak.chatter, PID: 1937
java.lang.NullPointerException: null cannot be cast to non-null type androidx.navigation.fragment.NavHostFragment
    at com.ak.chatter.ui.main.MainFragment.onViewCreated(MainFragment.kt:34)
    at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:332)
    at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
    at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224)
    at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997)
    at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
    at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
    at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
    at android.os.Handler.handleCallback(Handler.java:900)
    at android.os.Handler.dispatchMessage(Handler.java:103)
    at android.os.Looper.loop(Looper.java:219)
    at android.app.ActivityThread.main(ActivityThread.java:8347)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)

Upvotes: 4

Views: 3457

Answers (1)

Zain
Zain

Reputation: 40830

java.lang.NullPointerException: null cannot be cast to non-null type 
androidx.navigation.fragment.NavHostFragment

You try to cast a null to a non-null.

The null is got from appCompat.supportFragmentManager.findFragmentById(R.id.nav_host_fragment_main) statement.

Because the supportFragmentManager is used as the fragment manager of fragments that are hosted by a fragment. Although the supportFragmentManager should manage fragments that are hosted by an activity.

Whereas the childFragmentManager should be used instead to manage fragments that are hosted by another fragment.

So, to solve this replace supportFragmentManager with childFragmentManager in the main fragment class:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    val appCompat = requireActivity() as AppCompatActivity

    val navHostFragment = appCompat.childFragmentManager.findFragmentById(R.id.nav_host_fragment_main) as NavHostFragment
    val navController = navHostFragment.findNavController()

    binding.bottomNavigationView.setupWithNavController(navController)

}

Upvotes: 6

Related Questions