如何在Android Navigation Component中无需显式使用FragmentManager加载嵌套Fragment
你的场景是父Fragment下有两个固定的子容器,要加载同一Fragment的两个实例,Navigation Component本身是为单容器导航设计的,但针对这种多容器静态加载的需求,有几种简洁的实现方式:
方案1:布局文件直接声明(零代码)
如果这两个子Fragment是父页面的固定组成部分,不需要动态切换,直接在父Fragment的布局里用<fragment>标签写死就行,系统会自动帮你初始化实例:
<!-- 父Fragment的布局 comparator_fragment.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <!-- 第一个FoodComparatorFragment实例 --> <fragment android:id="@+id/comparator_fragment_1" android:name="com.yourpackage.FoodComparatorFragment" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1"/> <!-- 第二个FoodComparatorFragment实例 --> <fragment android:id="@+id/comparator_fragment_2" android:name="com.yourpackage.FoodComparatorFragment" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1"/> </LinearLayout>
这种方式完全不用写Java代码,最省心。
方案2:用父Fragment的子FragmentManager(动态加载)
如果需要给两个子Fragment传不同参数,就得用代码动态加载,但别用getSupportFragmentManager(),换成父Fragment的getChildFragmentManager()——这是Navigation Component推荐的子Fragment管理方式,避免和Activity的Fragment栈冲突:
private void initializeFragments() { // 用getChildFragmentManager()管理当前Fragment的子Fragment FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); // 给第一个Fragment传参 FoodComparatorFragment fragment1 = new FoodComparatorFragment(); Bundle args1 = new Bundle(); args1.putString("COMPARATOR_TAG", "left"); fragment1.setArguments(args1); // 给第二个Fragment传参 FoodComparatorFragment fragment2 = new FoodComparatorFragment(); Bundle args2 = new Bundle(); args2.putString("COMPARATOR_TAG", "right"); fragment2.setArguments(args2); transaction.add(R.id.comparator_fragment_1, fragment1); transaction.add(R.id.comparator_fragment_2, fragment2); transaction.commit(); }
这种写法既满足动态加载的需求,又符合Navigation的最佳实践。
关于Navigation Component的说明
Navigation Component核心是管单容器的页面跳转(比如从列表页跳到详情页),它不会替代多容器静态子Fragment的加载逻辑。如果你的两个子Fragment不需要参与跨页面导航,上面两种方案就足够用了。
要是你需要让两个子Fragment各自有独立的导航栈(比如每个子Fragment里还要跳其他页面),可以给每个容器加NavHostFragment,分别关联不同的导航图:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <androidx.navigation.fragment.NavHostFragment android:id="@+id/nav_host_left" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" app:navGraph="@navigation/nav_comparator_left" app:defaultNavHost="false"/> <androidx.navigation.fragment.NavHostFragment android:id="@+id/nav_host_right" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" app:navGraph="@navigation/nav_comparator_right" app:defaultNavHost="false"/> </LinearLayout>
注意把app:defaultNavHost设为false,因为一个Activity只能有一个默认NavHost处理返回键。之后可以通过findNavController(R.id.nav_host_left)获取对应栈的控制器,进行导航操作。
内容的提问来源于stack exchange,提问作者Nexussim Lements

