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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 01:01:51