多个主机片段 - 导航 Android Jetpack
Multiple Host Fragments - Navigation Android Jetpack
我想要多个 host_fragment 来拥有多个 bottomNavigationView。其中一个选项卡 (Nº2 "Myzone") 转到另一个片段,这是我的第二个 host_fragment ("profile_host_fragment") 它在顶部有另一个 bottomNavigationView。
我想做的是:
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" />
my_zone_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"
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" />
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" />
这是我的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" />
我正在尝试以与 NavHostActivity 相同的方式在 ProfileHostFragment 上设置导航控制器
val navController = profile_nav_host_fragment.findNavController()
topNavigationView.setupWithNavController(navController)
但我收到以下错误:
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)
我不知道实现此目标的正确方法是什么。感谢您的帮助。
为什么会发生 IllegalStateException
?
基本上,当我们有嵌套的导航主机片段时,从 Fragment class 中检索子 NavHost fragment
会抛出此异常。参考 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
解决方案是从 activity 上下文 中检索它,导航库为此提供方法 (参考 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.
所以,改变
val navController = profile_nav_host_fragment.findNavController()
到
val navController = activity.findNavController(R.id.profile_nav_host_fragment)
将有助于解决异常。
我想要多个 host_fragment 来拥有多个 bottomNavigationView。其中一个选项卡 (Nº2 "Myzone") 转到另一个片段,这是我的第二个 host_fragment ("profile_host_fragment") 它在顶部有另一个 bottomNavigationView。
我想做的是:
<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" />
my_zone_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"
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" />
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" />
这是我的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" />
我正在尝试以与 NavHostActivity 相同的方式在 ProfileHostFragment 上设置导航控制器
val navController = profile_nav_host_fragment.findNavController()
topNavigationView.setupWithNavController(navController)
但我收到以下错误:
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)
我不知道实现此目标的正确方法是什么。感谢您的帮助。
为什么会发生 IllegalStateException
?
基本上,当我们有嵌套的导航主机片段时,从 Fragment class 中检索子 NavHost fragment
会抛出此异常。参考 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
解决方案是从 activity 上下文 中检索它,导航库为此提供方法 (参考 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.
所以,改变
val navController = profile_nav_host_fragment.findNavController()
到
val navController = activity.findNavController(R.id.profile_nav_host_fragment)
将有助于解决异常。