Android Navigation 避免重建的尝试

页面3个Tab,分别为A,B,C
A页面�内有 ViewPager2,内部有多个子页面D,其余无子 Fragment

依赖项

implementation("androidx.navigation:navigation-fragment:2.4.2")
implementation("androidx.appcompat:appcompat:1.4.1")
implementation("com.google.android.material:material:1.5.0")

页面布局

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/main_nav"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        app:defaultNavHost="true"
        app:navGraph="@navigation/main_nav_graph" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_nav_fg_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:menu="@menu/main_nav_menu" />
</LinearLayout>

1. 使用默认设置,不做任何处理

mBinding.bottomNavFgMain.setOnItemSelectedListener(item -> {
    // 这里我将 menu 的 id 与 NavDestination 的 id 一致对应
    findNavController().navigate(item.getItemId());
    return true;
});
测试过程 结果
APP 启动 A,D初始化 state == null; state == null
切到B B初始化 state == null; A,D到 onDestroyView
切到C C初始化 state == null; B 到 onDestroyView
切到B B1初始化 state == null; C 到 onDestroyView
切到A A1,D1 初始化 state == null; B1 到 onDestroyView
多次按返回键 A1->B1->C->B->A->桌面

其中A1,B1表示每次跳转到的新页面 hashCode 打印出来都是不同的,意味着其实每次都是新建页面,栈内的对象实例一直在增加。返回键只是将这些栈内的实例重新显示。

state 表示 saveInstanceState

使用 NavigationUI

添加依赖

implementation("androidx.navigation:navigation-ui:2.4.2")

删除之前的跳转逻辑,使用

NavigationUI.setupWithNavController(mBinding.bottomNavFgMain, findNavController());
测试过程 结果
APP 启动 A,D初始化 state == null
切到B B初始化 state == null; A,D到 onDestroyView
切到C C初始化 state == null; B 到 onDestroy
切到B B1初始化 state != null; C 到 onDestroy
切到A A,D 初始化 state == null; B1 到 onDestroy
切到B B2初始化 state != null; A,D到 onDestroyView
切到C C1初始化 state == null; B2 到 onDestroy
多次按返回键 C1->A->桌面

其中B1、C1表示每次跳转到的新页面 hashCode 打印出来都是不同的。

总结

  • 不做任何操作的话,Navigation 是单任务栈管理模式,只能往里填充和显示最近实例;
  • NavigationUI#setupWithNavController则是通过配合popUpTosaveState等API,保证只缓存默认导航页面A,其余同级界面离开前会保存状态,不会保留实例。
  • 两者都会重建 UI,无法保存滚动位置等等...至于新版本多任务栈的特性,与避免 UI 创建完全不相干,如果欣赏 YouTube 那种风格的话,可以尝试。

总之,我个人认为 Navigation 不适合用作传统 APP 多 Tab 切换的主页,用作二级菜单确实不错。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容