I want to have a multiple host_fragment to have many bottomNavigationView
. One of the tabs (Nº2 "Myzone") go to another fragment which is my second host_fragment ("profile_host_fragment") it has another bottomNavigationView
at the top.
What I was trying to do is this:
main_nav_graph
<navigation
xmlns:app="http://schemas.android.com/apk/res-auto"
app:startDestination="@id/feature_home_nav_graph">
<include app:graph="@navigation/feature_home_nav_graph" />
<include app:graph="@navigation/feature_my_zone_nav_graph" />
<include app:graph="@navigation/feature_catalogue_nav_graph" />
<include app:graph="@navigation/feature_cart_nav_graph" />
<include app:graph="@navigation/feature_support_nav_graph" />
</navigation>
my_zone_nav_graph (where profile tab is)
<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"
app:startDestination="@id/myZoneFragment"
android:id="@+id/feature_my_zone_nav_graph">
<fragment
android:id="@+id/myZoneFragment"
android:name="feature_my_zone.presentation.myzone.MyZoneFragment"
android:label="fragment_my_zone"
tools:layout="@layout/fragment_my_zone">
<action
android:id="@+id/action_myZoneFragment_to_profileHostFragment"
app:destination="@id/profileHostFragment" />
</fragment>
<fragment
android:id="@+id/profileHostFragment"
android:name="feature_my_zone.presentation.profile.ProfileHostFragment"
android:label="fragment_profile_host"
tools:layout="@layout/fragment_profile_host" />
</navigation>
profile_nav_graph
<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/profile_nav_graph.xml"
app:startDestination="@id/addressFragment">
<fragment
android:id="@+id/addressFragment"
android:name="feature_my_zone.presentation.profile.address.AddressFragment"
android:label="fragment_address"
tools:layout="@layout/fragment_address" />
<fragment
android:id="@+id/profileFragment"
android:name="feature_my_zone.presentation.profile.profile.ProfileFragment"
android:label="fragment_profile"
tools:layout="@layout/fragment_profile" />
<fragment
android:id="@+id/paymentsFragment"
android:name="feature_my_zone.presentation.profile.payments.PaymentsFragment"
android:label="fragment_payments"
tools:layout="@layout/fragment_payments" />
<fragment
android:id="@+id/shippingFragment"
android:name="feature_my_zone.presentation.profile.shipping.ShippingFragment"
android:label="fragment_shipping"
tools:layout="@layout/fragment_shipping" />
</navigation>
this is my fragment_profile_host
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="feature_my_zone.presentation.profile.ProfileHostFragment">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/topNavigationView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:labelVisibilityMode="labeled"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:menu="@menu/profile_nav_menu" />
<fragment
android:id="@+id/profile_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/topNavigationView"
app:navGraph="@navigation/profile_nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
and I am trying to set up nav controller on ProfileHostFragment this way like in the same that in NavHostActivity
val navController = profile_nav_host_fragment.findNavController()
topNavigationView.setupWithNavController(navController)
But I am getting the following error:
Process: game.spa.android.app.v3, PID: 22367
java.lang.IllegalStateException: profile_nav_host_fragment must not be null
at feature_my_zone.presentation.profile.ProfileHostFragment.setupTopNavigation(ProfileHostFragment.kt:22)
at feature_my_zone.presentation.profile.ProfileHostFragment.onViewCreated(ProfileHostFragment.kt:17)
I Don't know what is the propper way to achieve this. Thanks for any help.
Why IllegalStateException
happens?
Basically, thing is that when we have nested navigation host fragments then retrieving child NavHost fragment
from Fragment class throws this exception. refer here
Official doc states that:
fun Fragment.findNavController(): NavController
Calling this on a Fragment that is not a NavHostFragment or within a NavHostFragment will result in an IllegalStateException
Solution is to retrieve it from activity context and navigation library provides method for that (refer here):
fun Activity.findNavController(@IdRes viewId: Int): NavController
Find a NavController given the id of a View and its containing Activity.
Calling this on a View that is not a NavHost or within a NavHost will result in an IllegalStateException.
So, changing
val navController = profile_nav_host_fragment.findNavController()
to
val navController = activity.findNavController(R.id.profile_nav_host_fragment)
will help solving the exception.