使用Navigation Controller返回时Fragment被重复创建的解决方案咨询
问题解答
1. 旧版FragmentManager实现方案是否正确?
不正确。该方案属于绕过Navigation组件的违规操作,会直接破坏Navigation内部的回退栈管理逻辑,后续如果有嵌套导航、跳转动画、生命周期监听等需求时极容易出现不可预期的异常,你当前看到的「同一个Fragment实例」本质是强制不销毁旧实例、手动弹栈的副作用,不符合Navigation的设计规范,不建议长期使用。
2. 改用requireActivity().supportFragmentManager抛出异常如何解决?
你看到的java.lang.IllegalStateException: Cannot remove Fragment attached to a different FragmentManager.异常,是因为Navigation宿主NavHostFragment有自己独立的子FragmentManager,你的Fragment A和B都是托管在这个子FragmentManager下,而非Activity级别的supportFragmentManager。
如果要手动操作FragmentManager,应该用parentFragmentManager而非Activity的全局FragmentManager,参考代码:
// 在Fragment B中执行回退操作 parentFragmentManager.let { if (it.backStackEntryCount > 0) { it.popBackStack() } } // 不需要手动调用remove当前Fragment,popBackStack会自动处理销毁逻辑
但还是不建议手动操作FragmentManager,优先使用Navigation原生API。
3. 如何用Navigation Controller直接返回Fragment A不重复创建实例?
你之前调用navigate()跳转到Fragment A,本质是往回退栈新增了一个Fragment A的实例,所以才会出现旧实例销毁、新实例创建的问题。正确的回退操作不需要调用navigate,直接调用以下API即可:
- 如果你只需要回退到上一个页面(从B直接回到A),直接调用:
findNavController().popBackStack() - 如果你需要回退到指定的Fragment A,中间可能存在其他页面,可以指定回退目标ID:
findNavController().popBackStack(R.id.nav_something_fragment, false) // 第二个参数inclusive为false表示保留目标Fragment A,为true表示连目标一起弹出
该操作会直接复用回退栈中已有的Fragment A实例,不会触发新实例创建。
内容的提问来源于stack exchange,提问作者thahgr

