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

Android BottomNavigation设置startDestination致Fragment onCreate无限循环

Android Jetpack Navigation 底部导航无限循环问题排查

问题现象

开发Android应用时,使用FragmentContainerView+BottomNavigationView配合NavGraph实现底部导航,切换三个仅显示文本的Fragment时遇到两个问题:

  1. 配置app:navGraph并设置startDestination后,起始Fragment的onCreate方法被无限循环调用;
  2. 不配置app:navGraph时,底部导航可见但点击无任何切换效果。

相关代码

MainActivity.kt

class MainActivity: AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val navHostFragment =
            supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        val navController = navHostFragment.navController

    }
}

FirstFragment.kt(SecondFragment、ThirdFragment逻辑一致)

class FirstFragment: Fragment(R.layout.fragment_first) {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.i("FirstFragment", "onCreate called")
    }

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<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=".MainActivity"
    android:orientation="horizontal">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/simple_nav_graph"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toTopOf="@+id/bottom_nav"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_nav"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:itemTextColor="@color/cardview_light_background"
        app:layout_constraintBottom_toBottomOf="@+id/nav_host_fragment"
        app:menu="@menu/menu_bottom_nav" />

</androidx.constraintlayout.widget.ConstraintLayout>

fragment_first.xml

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/details_page_fragment_one"
    android:name="com.****.****.ui.fragone.FirstFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello Fragment One"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</fragment>

simple_nav_graph.xml

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/simple_nav_graph"
    app:startDestination="@id/details_page_fragment_one">

    <fragment
        android:id="@+id/details_page_fragment_one"
        android:name="com.*.*.ui.fragone.FirstFragment"
        android:label="Fragment 1"
        tools:layout="@layout/fragment_first">
        <action
            android:id="@+id/action_details_page_fragment_one_to_details_page_fragment_two"
            app:destination="@id/details_page_fragment_two" />
        <action
            android:id="@+id/action_details_page_fragment_one_to_details_page_fragment_three"
            app:destination="@id/details_page_fragment_three" />
    </fragment>


    <fragment
        android:id="@+id/details_page_fragment_two"
        android:name="com.*.*.ui.fragtwo.SecondFragment"
        android:label="Fragment 2"
        tools:layout="@layout/fragment_second">
        <action
            android:id="@+id/action_details_page_fragment_two_to_details_page_fragment_three"
            app:destination="@id/details_page_fragment_three" />
        <action
            android:id="@+id/action_details_page_fragment_two_to_details_page_fragment_one"
            app:destination="@id/details_page_fragment_one" />
    </fragment>
    <fragment
        android:id="@+id/details_page_fragment_three"
        android:name="com.*.*.ui.fragthree.ThirdFragment"
        android:label="Fragment 3"
        tools:layout="@layout/fragment_third">
        <action
            android:id="@+id/action_details_page_fragment_three_to_details_page_fragment_two"
            app:destination="@id/details_page_fragment_two" />
        <action
            android:id="@+id/action_details_page_fragment_three_to_details_page_fragment_one"
            app:destination="@id/details_page_fragment_one" />
    </fragment>

</navigation>

Logcat输出

2023-06-07 16:40:33.457 22883-22883 FirstFragment                       com...r.automotivecafeapp  I  onCreate called
2023-06-07 16:40:33.468 22883-22883 FirstFragment                       com...r.automotivecafeapp  I  onCreate called
...(重复调用日志)

问题原因

  1. 无限循环创建Fragment:fragment_first.xml的根布局使用了<fragment>标签,NavHostFragment会根据导航图创建FirstFragment实例,加载该布局时系统会再次创建FirstFragment,形成无限递归,导致onCreate被反复调用。
  2. 底部导航无功能:未将BottomNavigationView与NavController绑定,点击菜单时没有触发导航动作。

解决方案

1. 修改Fragment布局根标签

将所有Fragment布局的根标签从<fragment>改为普通ViewGroup(如ConstraintLayout),避免重复实例化Fragment:

修改后的fragment_first.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello Fragment One"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

2. 绑定BottomNavigationView与NavController

在MainActivity中添加代码,关联底部导航和导航控制器,实现点击切换:

修改后的MainActivity.kt:

class MainActivity: AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val navHostFragment =
            supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        val navController = navHostFragment.navController
        
        // 绑定底部导航与导航控制器
        findViewById<BottomNavigationView>(R.id.bottom_nav).setupWithNavController(navController)
    }
}

3. 简化导航图

底部导航切换无需定义action,NavController会自动匹配菜单id与Fragment id,删除导航图中所有action:

修改后的simple_nav_graph.xml:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/simple_nav_graph"
    app:startDestination="@id/details_page_fragment_one">

    <fragment
        android:id="@+id/details_page_fragment_one"
        android:name="com.*.*.ui.fragone.FirstFragment"
        android:label="Fragment 1"
        tools:layout="@layout/fragment_first" />

    <fragment
        android:id="@+id/details_page_fragment_two"
        android:name="com.*.*.ui.fragtwo.SecondFragment"
        android:label="Fragment 2"
        tools:layout="@layout/fragment_second" />

    <fragment
        android:id="@+id/details_page_fragment_three"
        android:name="com.*.*.ui.fragthree.ThirdFragment"
        android:label="Fragment 3"
        tools:layout="@layout/fragment_third" />

</navigation>

4. 确保菜单id与Fragment id一致

menu_bottom_nav.xml中每个item的id必须和导航图中对应Fragment的id相同:

示例menu_bottom_nav.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/details_page_fragment_one"
        android:title="Fragment 1" />
    <item
        android:id="@+id/details_page_fragment_two"
        android:title="Fragment 2" />
    <item
        android:id="@+id/details_page_fragment_three"
        android:title="Fragment 3" />
</menu>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 20:52:35