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

Android Menu Item导航崩溃:二次退出触发IllegalStateException问题

问题描述

首次从LoginFragment跳转至MainFragment后,点击菜单中的logout按钮可正常返回LoginFragment;但第二次重复该操作时,触发如下异常:

java.lang.IllegalStateException: Fragment MainFragment{632a8a3} (33a94b4d-9e85-4315-ae99-51e5edc7ddc2 id=0x7f08015e) did not return a View from onCreateView() or this was called before onCreateView()


相关代码

LoginFragment代码

class LoginFragment : Fragment() {
    private lateinit var binding : FragmentLoginBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        auth = Firebase.auth
        database = Firebase.database.reference
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentLoginBinding.inflate(inflater,container,false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.apply {
            btnConfirm.setOnClickListener {
                Navigation.findNavController(requireView()).navigate(R.id.action_loginFragment_to_mainFragment)
            }
        }
    }
}

MainFragment代码

class MainFragment : Fragment() {
    private lateinit var binding : FragmentMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentMainBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val toolbar = binding.toolbar
        (requireActivity() as AppCompatActivity).setSupportActionBar(toolbar)
        requireActivity().addMenuProvider(object : MenuProvider {
            override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
                if(menu.size()==0){
                    menuInflater.inflate(R.menu.main_menu,menu)
                }
            }

            override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
                return when (menuItem.itemId) {
                    R.id.logout ->{
                        Navigation.findNavController(requireView()).navigate(R.id.action_mainFragment_to_loginFragment)
                        true
                    }
                    else -> false
                }
            }
        })
    }
}

导航配置文件

<?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/nav_menu"
    app:startDestination="@id/splashFragment">
    <fragment
        android:id="@+id/loginFragment"
        android:name="com.yasinsenel.yapacaklarm.view.fragment.LoginRegisterFragment"
        android:label="fragment_login"
        tools:layout="@layout/fragment_login" >
        <action
            android:id="@+id/action_loginFragment_to_mainFragment"
            app:destination="@id/mainFragment"
            app:enterAnim="@anim/nav_default_enter_anim"
            app:exitAnim="@anim/nav_default_exit_anim" />
    </fragment>

    <fragment
        android:id="@+id/mainFragment"
        android:name="com.yasinsenel.yapacaklarm.view.fragment.MainFragment"
        android:label="fragment_main"
        tools:layout="@layout/fragment_main" >
        <action
            android:id="@+id/action_mainFragment_to_loginFragment"
            app:destination="@id/loginFragment" />
</navigation>

错误原因
  1. 导航栈冗余叠加:当前从MainFragment到LoginFragment的导航action未配置popUpTo和popUpToInclusive属性,每次跳转都会在导航栈中新增LoginFragment实例,旧的MainFragment并未被弹出。第二次操作时,旧的MainFragment视图已销毁(onDestroyView执行),但它绑定的菜单提供者仍在Activity中生效,点击logout时会调用旧实例的requireView(),触发视图不存在的异常。
  2. MenuProvider未绑定生命周期:MainFragment中添加的MenuProvider未与Fragment的视图生命周期绑定,也未在视图销毁时移除,导致Activity中存在多个无效的MenuProvider实例,旧实例响应菜单点击时会访问已销毁的视图。

解决方法

1. 修复导航栈配置,清理冗余Fragment

修改导航配置文件中mainFragment到loginFragment的action,添加栈清理属性:

<action
    android:id="@+id/action_mainFragment_to_loginFragment"
    app:destination="@id/loginFragment"
    app:popUpTo="@id/loginFragment"
    app:popUpToInclusive="true"/>
  • app:popUpTo="@id/loginFragment":跳转时弹出栈内直到loginFragment的所有Fragment
  • app:popUpToInclusive="true":将loginFragment本身也弹出,确保栈内只有一个新的loginFragment实例,避免重复叠加

2. 绑定MenuProvider到Fragment生命周期

在MainFragment添加MenuProvider时,指定绑定到Fragment的视图生命周期,这样当视图销毁时,MenuProvider会自动移除:

requireActivity().addMenuProvider(object : MenuProvider {
    override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
        if(menu.size()==0){
            menuInflater.inflate(R.menu.main_menu,menu)
        }
    }

    override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
        return when (menuItem.itemId) {
            R.id.logout ->{
                Navigation.findNavController(requireView()).navigate(R.id.action_mainFragment_to_loginFragment)
                true
            }
            else -> false
        }
    }
}, viewLifecycleOwner) // 绑定到Fragment视图生命周期

或者手动在视图销毁时移除MenuProvider:

private lateinit var menuProvider: MenuProvider

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    // ...其他代码
    menuProvider = object : MenuProvider {
        // ...原有实现
    }
    requireActivity().addMenuProvider(menuProvider)
}

override fun onDestroyView() {
    super.onDestroyView()
    requireActivity().removeMenuProvider(menuProvider)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 19:05:23