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

Android Bottom Navigation导航异常求助:无法正确切换Fragment

问题描述

我的应用包含4个Fragment,底部导航栏有3个图标。进入底部导航栏未包含的Fragment后,导航结构出现异常:

  • 点击首页的食品图片进入FoodDetailFragment;
  • 从该页面切换到BasketFragment后,无法切换回FoodListFragment;
  • 点击底部导航栏的首页图标,会回到之前打开的FoodDetailFragment,而非首页。

我已在Activity中处理了所有Item点击事件,但问题仍未解决。相关代码如下:

Main Activity

@AndroidEntryPoint
class FoodOrderingActivity : AppCompatActivity() {

    private lateinit var binding: ActivityFoodOrderingBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityFoodOrderingBinding.inflate(layoutInflater)
        setContentView(binding.root)


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

        NavigationUI.setupWithNavController(binding.bottomNavigationView, navHostFragment.navController)

        binding.bottomNavigationView.setOnItemReselectedListener{
            when(it.itemId) {
                R.id.foodListFragment -> navHostFragment.findNavController().navigate(R.id.foodListFragment)
                //R.id.foodDetailFragment -> navHostFragment.findNavController().navigate(R.id.foodDetailFragment)
                R.id.basketFragment -> navHostFragment.findNavController().navigate(R.id.basketFragment)
                R.id.favoriteFoodFragment -> navHostFragment.findNavController().navigate(R.id.favoriteFoodFragment)
            }
        }
    }
}
<?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/food_ordering_activity_nav_graph"
    app:startDestination="@id/foodListFragment">

    <fragment
        android:id="@+id/foodListFragment"
        android:name="com.omersungur.foodorderingapp.ui.fragment.food_list.FoodListFragment"
        android:label="fragment_food_list"
        tools:layout="@layout/fragment_food_list" >
        <action
            android:id="@+id/action_foodListFragment_to_foodDetailFragment"
            app:destination="@id/foodDetailFragment" />
        <action
            android:id="@+id/action_foodListFragment_to_basketFragment"
            app:destination="@id/basketFragment" />
    </fragment>
    <fragment
        android:id="@+id/foodDetailFragment"
        android:name="com.omersungur.foodorderingapp.ui.fragment.food_detail.FoodDetailFragment"
        android:label="fragment_food_detail"
        tools:layout="@layout/fragment_food_detail" >
        <action
            android:id="@+id/action_foodDetailFragment_to_basketFragment"
            app:destination="@id/basketFragment"
            app:popUpTo="@id/foodDetailFragment"
            app:popUpToInclusive="true" />
        <argument
            android:name="food"
            app:argType="com.omersungur.foodorderingapp.model.food.Food" />
    </fragment>
    <fragment
        android:id="@+id/basketFragment"
        android:name="com.omersungur.foodorderingapp.ui.fragment.basket.BasketFragment"
        android:label="fragment_basket"
        tools:layout="@layout/fragment_basket" >
        <action
            android:id="@+id/action_basketFragment_to_foodListFragment"
            app:destination="@id/foodListFragment"
            app:popUpTo="@id/foodListFragment" />
    </fragment>
    <fragment
        android:id="@+id/favoriteFoodFragment"
        android:name="com.omersungur.foodorderingapp.ui.fragment.favorite.FavoriteFoodFragment"
        android:label="fragment_favorite_food"
        tools:layout="@layout/fragment_favorite_food" />
</navigation>

Bottom Nav Menu

<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/foodListFragment"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:icon="@drawable/ic_home"
        android:title="Home" />

    <item
        android:id="@+id/favoriteFoodFragment"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:icon="@drawable/ic_favorite"
        android:title="Favorite" />

    <item
        android:id="@+id/basketFragment"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:icon="@drawable/ic_basket"
        android:title="Basket" />

</menu>

解决方案

问题确实和**回退栈(BackStack)**直接相关,以下是具体修复步骤:

1. 修正Navigation Graph的Action配置

修改FoodDetailFragment到BasketFragment的Action

原来的Action只弹出自身,需要改成弹出到FoodListFragment(底部导航的根节点),确保从BasketFragment点击首页能直接回到FoodListFragment:

<action
    android:id="@+id/action_foodDetailFragment_to_basketFragment"
    app:destination="@id/basketFragment"
    app:popUpTo="@id/foodListFragment"
    app:popUpToInclusive="false" />

修正BasketFragment回到FoodListFragment的Action

确保返回时清空中间栈,避免残留页面:

<action
    android:id="@+id/action_basketFragment_to_foodListFragment"
    app:destination="@id/foodListFragment"
    app:popUpTo="@id/foodListFragment"
    app:popUpToInclusive="true" />

2. 移除Activity中多余的重选监听

NavigationUI.setupWithNavController已经默认处理了底部导航的点击和重选逻辑,额外添加的setOnItemReselectedListener会导致重复导航,干扰默认行为,直接删除这段代码:

// 删掉以下这段代码
binding.bottomNavigationView.setOnItemReselectedListener{
    when(it.itemId) {
        R.id.foodListFragment -> navHostFragment.findNavController().navigate(R.id.foodListFragment)
        //R.id.foodDetailFragment -> navHostFragment.findNavController().navigate(R.id.foodDetailFragment)
        R.id.basketFragment -> navHostFragment.findNavController().navigate(R.id.basketFragment)
        R.id.favoriteFoodFragment -> navHostFragment.findNavController().navigate(R.id.favoriteFoodFragment)
    }
}

3. 优化底部导航跳转的回退栈(可选)

在Navigation Graph中,给底部导航三个Fragment之间的跳转添加回退栈清理逻辑,比如修改FoodListFragment到BasketFragment的Action:

<action
    android:id="@+id/action_foodListFragment_to_basketFragment"
    app:destination="@id/basketFragment"
    app:popUpTo="@id/foodListFragment"
    app:popUpToInclusive="false" />

这样每次切换底部导航时,都会回到对应目的地的根实例,不会保留之前的子页面栈。


验证效果

  • 从FoodListFragment进入FoodDetailFragment,再跳转到BasketFragment,回退栈里只会保留FoodListFragment和BasketFragment;
  • 点击底部导航的首页图标,会直接回到FoodListFragment的根页面;
  • 从BasketFragment切换到其他底部导航项再切回,也会回到BasketFragment的根实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 12:35:38