You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Navigation组件保存BottomNavigationView的Fragment实例

前置依赖要求

首先确保项目引入的Navigation组件版本≥2.5.0,配套Fragment依赖版本≥1.5.0,在模块级build.gradle中添加/升级对应依赖:

dependencies {
    // Fragment依赖,需匹配Navigation版本要求
    implementation "androidx.fragment:fragment-ktx:1.5.0+"
    // Navigation组件依赖,版本不低于2.5.0即可,建议使用当前最新稳定版
    implementation "androidx.navigation:navigation-fragment-ktx:2.7.7"
    implementation "androidx.navigation:navigation-ui-ktx:2.7.7"
}

导航图配置规则

导航图res/navigation/nav_main.xml需要遵循以下规则:

  • 根导航图的起始目的地必须是BottomNavigationView对应的一级Fragment之一
  • 所有底部菜单项对应的一级Fragment,必须直接作为根导航图的直接子节点,不要嵌套在其他导航图下
  • 不要给一级Fragment配置popUpTo清空栈、launchDocument等特殊启动属性
    配置示例:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_main"
    app:startDestination="@id/homeFragment">

    <!-- 底部菜单对应的一级Fragment,直接挂载在根导航图下 -->
    <fragment
        android:id="@+id/homeFragment"
        android:name="com.yourapp.HomeFragment"
        android:label="首页" />
    <fragment
        android:id="@+id/dashboardFragment"
        android:name="com.yourapp.DashboardFragment"
        android:label="数据面板" />
    <fragment
        android:id="@+id/profileFragment"
        android:name="com.yourapp.ProfileFragment"
        android:label="个人中心" />

    <!-- 二级跳转页面正常配置即可,不影响一级页状态留存 -->
    <fragment
        android:id="@+id/settingsFragment"
        android:name="com.yourapp.SettingsFragment"
        android:label="设置" />
</navigation>

Activity绑定逻辑

不要手动实现BottomNavigationView的菜单项选中监听做跳转,直接使用官方提供的setupWithNavController扩展方法完成绑定,代码示例:

class MainActivity : AppCompatActivity() {
    private lateinit var navController: NavController
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        navController = navHostFragment.navController
        // 调用官方扩展方法完成绑定,内部已实现多Tab栈管理与状态保存逻辑
        findViewById<BottomNavigationView>(R.id.bottom_nav).setupWithNavController(navController)
    }

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

如果有自定义菜单选中逻辑的需求,不要直接调用navController.navigate()跳转,必须使用NavigationUI.onNavDestinationSelected()处理选中事件,否则会触发Fragment重复创建:

bottomNav.setOnItemSelectedListener { menuItem ->
    // 调用官方封装的选中处理逻辑,保留状态保存能力
    NavigationUI.onNavDestinationSelected(menuItem, navController)
}

常见避坑点

  • 不要手动给底部Tab跳转加popUpTo、singleTop等NavOptions配置,官方绑定方法内部已经做了适配
  • 不要自定义NavHostFragment的FragmentFactory重写一级Fragment的创建逻辑,除非自行实现实例缓存
  • 不要给NavHostFragment设置app:defaultNavHost="false"属性,会破坏返回栈与状态管理逻辑

配置完成后验证:首次进入每个Tab会正常走Fragment创建生命周期,后续切换Tab时不会重新调用onCreate、onViewCreated方法,列表滚动位置、输入框内容等页面状态会自动留存。

内容的提问来源于stack exchange,提问作者pa1pal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 01:15:40