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

切换请求状态时ViewBinding出现NullPointerException问题排查

问题分析:Fragment返回后空状态页面崩溃问题

问题场景

我正在实现应用的空状态页面,但第二次返回至Fragment时应用崩溃。首次启动应用时视图可正常创建,但当完成主Fragment→注册文档Fragment(为RecyclerView列表创建新项)→主Fragment的流程后,应用在binding.imageEmptyState.hide()代码行崩溃。

相关代码

数据收集函数

private fun configDataCollector() = lifecycleScope.launch {
    viewModel.list.collectLatest { result->
        when(result) {
            is ResourceState.Success -> {
                binding.imageEmptyState.hide()
                binding.textEmptyState.hide()
                result.data?.let { values ->
                    adapterDoc.docs = values.toList()
                }
            }
            is ResourceState.Empty -> {
                binding.imageEmptyState.show()
                binding.textEmptyState.show()
            }
            else -> { }
        }
    }
}

ResourceState密封类

sealed class ResourceState<T>(
    val data: T? = null,
    val message: String? = null
) {
    class Success<T>(data: T?): ResourceState<T>(data)
    class Error<T>(message: String?, data: T? = null): ResourceState<T>(data, message)
    class Loading<T>: ResourceState<T>()
    class Empty<T>: ResourceState<T>()
}

BaseFragment抽象类

abstract class BaseFragment<VB: ViewBinding, VM: ViewModel>: Fragment() {
    private var _binding: VB? = null
    protected val binding get() = _binding!!
    protected abstract val viewModel: VM

    override fun onCreateView
                (inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        _binding = recoverViewBinding(inflater, container)
        return binding.root
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

    protected abstract fun recoverViewBinding(inflater: LayoutInflater, container: ViewGroup?): VB
}

报错日志

2023-01-04 11:55:35.905 14014-14014/com.tods.docreminder E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.tods.docreminder, PID: 14014
java.lang.NullPointerException
    at com.tods.docreminder.feature.doc.presentation.util.BaseFragment.getBinding(BaseFragment.kt:13)
    at com.tods.docreminder.feature.doc.presentation.doc.MainFragment.access$getBinding(MainFragment.kt:34)
    at com.tods.docreminder.feature.doc.presentation.doc.MainFragment$configDataCollector$1$1.invokeSuspend(MainFragment.kt:255)

崩溃原因

核心原因是协程未绑定视图生命周期,视图销毁后仍尝试访问已置空的Binding:

  • 当从主Fragment跳转到注册文档Fragment时,主Fragment会执行onDestroyView,此时_binding被置为null。
  • 但configDataCollector()中用lifecycleScope.launch启动的协程,默认绑定的是Fragment的整体生命周期(从onCreate到onDestroy),并不会在onDestroyView时自动取消。
  • 当在注册文档Fragment添加数据后,ViewModel的list数据流会发送更新事件,之前启动的协程仍然会执行collectLatest中的逻辑,此时访问binding会通过_binding!!强制解包null值,直接抛出NullPointerException。
  • 首次启动正常是因为视图尚未销毁,_binding不为null,协程访问Binding无问题。

修复建议

将协程绑定到视图生命周期,确保视图销毁时协程自动取消:

private fun configDataCollector() = viewLifecycleOwner.lifecycleScope.launch {
    viewModel.list.collectLatest { result->
        // 原有逻辑不变
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 19:15:31