Android屏幕旋转后Fragment未关联FragmentManager问题求解
Android Fragment跳转后重建调用闭包报错的解决方案
问题根源
当应用后台久置或屏幕旋转触发Fragment重建时,原NotificationListFragment实例已被销毁并脱离FragmentManager,但你通过Bundle传递的闭包捕获了这个旧实例的引用。此时调用闭包内的findNavController().navigateUp(),会因旧Fragment不再关联FragmentManager而抛出IllegalStateException。
此外,通过Parcelable传递闭包本身存在设计缺陷:序列化/反序列化后的闭包无法保证捕获的上下文是当前活跃的Fragment实例,极易引发上下文失效问题。
推荐解决方案:使用Navigation返回结果机制
Jetpack Navigation原生支持Fragment间传递返回结果,完全不需要传递闭包,从根源避免上下文失效问题。
1. 在NotificationListFragment中注册结果监听
在onCreate方法中注册监听,接收InfoNotificationFragment返回的通知已读状态:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 注册结果监听,key需与返回端一致 setFragmentResultListener("notification_read_result") { _, resultBundle -> val notificationId = resultBundle.getString("notification_id") ?: return@setFragmentResultListener // 执行标记已读的逻辑 markInfoNotificationAsReadInRV(notificationId) } }
2. 修改跳转逻辑,移除闭包传递
跳转时仅传递MessageNotificationCompatible对象,不需要再打包闭包:
adapter.action.observe(viewLifecycleOwner) { action -> when(action) { is NotificationAction.SelectionAction -> { val message = action.infoNotification.toNotificationMessage() val bundle = Bundle().apply { putParcelable(InfoNotificationFragment.MESSAGE_KEY, message) } findNavController().navigate( R.id.action_notificationListFragment_to_infoNotificationFragment, bundle ) } } }
3. 在InfoNotificationFragment中返回结果并关闭
点击关闭按钮时,传递通知ID并调用navigateUp():
// 关闭按钮点击事件处理 closeButton.setOnClickListener { val resultBundle = Bundle().apply { putString("notification_id", message.data.getID()) } // 发送结果到NotificationListFragment setFragmentResult("notification_read_result", resultBundle) // 执行返回操作 findNavController().navigateUp() }
备选方案:在onResume中刷新列表
如果不需要实时传递结果,可简化逻辑:在InfoNotificationFragment中直接返回,NotificationListFragment在onResume时主动刷新列表状态。
1. InfoNotificationFragment关闭逻辑
closeButton.setOnClickListener { // 若需要,可在此处先调用API标记通知为已读 findNavController().navigateUp() }
2. NotificationListFragment刷新逻辑
override fun onResume() { super.onResume() // 重新获取通知数据,刷新列表状态 refreshNotificationList() }
不推荐方案:修复闭包上下文
若坚持使用闭包,需避免捕获旧Fragment引用,改为通过Activity获取全局NavController,但这种方式仍存在序列化风险,不建议采用:
val handler: () -> Unit = { markInfoNotificationAsReadInRV(message.data.getID()) // 通过Activity获取当前活跃的NavController requireActivity().findNavController(R.id.nav_host_fragment_container).navigateUp() }
内容的提问来源于stack exchange,提问作者Davide
相关产品推荐
相关产品推荐

