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

Navigation Architecture Component:无法在onResume中导航至Fragment

解决FragmentManager事务冲突的登录导航问题

你遇到的这个IllegalStateException是因为在onResume方法里直接发起导航操作的时机不对——此时FragmentManager可能正在执行Fragment的恢复相关事务,新的导航事务会和它冲突。下面给你几个更安全的实现方案:

方案1:用View.post延迟导航操作

把导航逻辑放到view.post里,这样会把操作放到主线程消息队列的末尾,等当前所有Fragment事务完成后再执行:

abstract class SignedInFragment : Fragment() {
    override fun onResume() {
        super.onResume()
        // 确保view已经创建完成
        view?.post {
            val currentUser = FirebaseAuth.getInstance().currentUser
            val navController = NavHostFragment.findNavController(this)
            // 避免重复跳转到登录页
            if (currentUser == null && navController.currentDestination?.id != R.id.loginFragment) {
                navController.navigate(R.id.action_login)
            }
        }
    }
}

方案2:全局目的地监听(更推荐)

把登录检查逻辑集中到Activity里,通过Navigation的OnDestinationChangedListener监听页面切换,这样所有需要登录验证的页面都能统一处理:

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

        val navController = findNavController(R.id.nav_host_fragment)
        navController.addOnDestinationChangedListener { _, destination, _ ->
            val isLoggedIn = FirebaseAuth.getInstance().currentUser != null
            // 定义需要登录才能访问的页面ID集合
            val protectedDestinations = setOf(R.id.mainFragment, R.id.signedInFragment)
            
            if (destination.id in protectedDestinations && !isLoggedIn) {
                // 跳转到登录页,同时弹出之前的保护页面,避免返回时回到未登录状态
                navController.navigate(R.id.action_login) {
                    popUpTo(R.id.mainFragment) { inclusive = true }
                }
            }
        }
    }
}

方案3:使用LifecycleObserver监听生命周期

通过自定义生命周期观察者,在更安全的时机执行检查,同时避免内存泄漏:

abstract class SignedInFragment : Fragment() {
    private val authLifecycleObserver = object : DefaultLifecycleObserver {
        override fun onResume(owner: LifecycleOwner) {
            super.onResume(owner)
            val currentUser = FirebaseAuth.getInstance().currentUser
            val navController = NavHostFragment.findNavController(this@SignedInFragment)
            
            if (currentUser == null && navController.currentDestination?.id != R.id.loginFragment) {
                navController.navigate(R.id.action_login)
            }
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 绑定到viewLifecycleOwner,避免Fragment销毁后仍持有引用
        viewLifecycleOwner.lifecycle.addObserver(authLifecycleObserver)
    }

    override fun onDestroyView() {
        viewLifecycleOwner.lifecycle.removeObserver(authLifecycleObserver)
        super.onDestroyView()
    }
}

额外优化:完善导航Action配置

为了避免用户从登录页返回时回到未登录的保护页面,建议修改你的全局action_login,添加popUpTo和popUpToInclusive属性:

<action android:id="@+id/action_login"
    app:destination="@id/loginFragment"
    app:popUpTo="@id/mainFragment"
    app:popUpToInclusive="true"/>

这样跳转到登录页后,MainFragment会被从导航栈中移除,用户按返回键会直接退出应用,而不是回到未授权的页面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:35:24