Android导航到Fragment时崩溃:profileFragment无法再次跳转editProfileFragment
问题根因
报错的核心是触发action_profileFragment_to_editProfileFragment跳转时,导航控制器的当前目的地仍然是editProfileFragment,而该action仅定义在profileFragment的配置下,跨目的地调用自然找不到对应资源。
出现这个问题的常见诱因有两个:
- 你从编辑页返回个人主页用的是正向跳转而非弹出回退栈,导致回退栈变为
profileFragment -> editProfileFragment -> profileFragment,如果两个Fragment共用了绑定到Activity作用域的ViewModel,旧的profileFragment实例也会收到编辑页发送的返回导航事件,重复跳转导致栈结构混乱。 - 跳转触发时机早于导航控制器的目的地切换完成,当前目的地还未更新为
profileFragment就发起了新跳转。
解决方案
方案1:替换返回逻辑为回退栈弹出(推荐)
从编辑页返回个人主页属于标准回退操作,不要用正向跳转新增Fragment实例,直接弹出回退栈即可:
步骤1:统一导航事件类型(可选,可避免Int类型的错误传值)
// 用密封类封装不同导航行为 sealed class NavEvent { object Back : NavEvent() data class To(val actionId: Int) : NavEvent() } // ViewModel中替换原有事件定义 private val _navigateTo = MutableLiveData<Event<NavEvent>>() val navigateTo: LiveData<Event<NavEvent>> = _navigateTo // 修改对应跳转方法 fun goBackToProfile(){ _navigateTo.value = Event(NavEvent.Back) } fun editProfileButtonClick() { _navigateTo.value = Event(NavEvent.To(R.id.action_profileFragment_to_editProfileFragment)) }
步骤2:修改观察侧的处理逻辑
viewModel.navigateTo.observe(viewLifecycleOwner, EventObserver { event -> when(event) { NavEvent.Back -> navController.popBackStack() is NavEvent.To -> navController.navigate(event.actionId) } })
方案2:修改导航action配置(需保留正向跳转时使用)
如果业务逻辑要求必须用正向跳转返回,给返回action添加popUpTo配置,清除多余的栈实例:
<action android:id="@+id/action_editProfileFragment_to_profileFragment" app:destination="@id/profileFragment" app:popUpTo="@id/profileFragment" app:popUpToInclusive="true" />
该配置会在跳转时先弹出回退栈到profileFragment(包含自身),再创建新的profileFragment实例入栈,避免栈结构混乱。
方案3:隔离ViewModel作用域
不要让profileFragment和editProfileFragment共用Activity级别的ViewModel,各自使用绑定到自身Fragment作用域的ViewModel,避免编辑页发送的导航事件被旧的profileFragment接收,触发错误跳转。
兜底方案
跳转前增加当前目的地校验,避免非法调用报错:
viewModel.navigateTo.observe(viewLifecycleOwner, EventObserver { actionId -> val currentDestId = navController.currentDestination?.id // 只有当前目的地和action所属目的地匹配时才执行跳转 if (currentDestId == R.id.profileFragment && actionId == R.id.action_profileFragment_to_editProfileFragment || currentDestId == R.id.editProfileFragment && actionId == R.id.action_editProfileFragment_to_profileFragment || currentDestId == R.id.editProfileFragment && actionId == R.id.action_editProfileFragment_to_chooseImageFragment || currentDestId == R.id.chooseImageFragment && actionId == R.id.action_chooseImageFragment_to_editProfileFragment ) { navController.navigate(actionId) } })
内容的提问来源于stack exchange,提问作者Hazard
相关产品推荐
相关产品推荐

