Fragment 中的视图绑定导致 KotlinNullPointerException 在生命周期范围内的协程中运行

A1m*_*A1m 5 android kotlin kotlin-coroutines android-viewbinding

我正在按照 Google 文档中的建议设置 Fragment :

    private var _binding: MyBinding? = null
    private val binding get() = _binding!!
Run Code Online (Sandbox Code Playgroud)
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        _binding = MyBinding.inflate(inflater, container, false)
Run Code Online (Sandbox Code Playgroud)
    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
Run Code Online (Sandbox Code Playgroud)

现在我正在调用一个协程,据我所知,该协程应限定在此片段的生命周期内。它有一个更长的网络调用,然后成功:

        lifecycleScope.launch(Dispatchers.Main) {
            when (myViewModel.loadFromNetwork(url)) {
                true -> responseSuccess()
                false -> responseFailure()
            }
        }
Run Code Online (Sandbox Code Playgroud)
    private suspend fun responseSuccess() {
        binding.stateSuccess.visibility = View.VISIBLE
        // ...
    }
Run Code Online (Sandbox Code Playgroud)

现在,当我在loadFromNetwork加载时按下 Android 系统后退按钮时,片段会被销毁并被onDestroyView()调用。因此binding现在是null. 我得到一个kotlin.KotlinNullPointerException. 我不太明白的是为什么responseSuccess()仍然被执行,即使我认为这lifecycleScope是专门针对这种情况的。根据谷歌文档

LifecycleScope 为每个 Lifecycle 对象定义。当生命周期被销毁时,在此范围内启动的任何协程都会被取消。

我知道可以通过一些更改和一些手动空检查来修复此代码,但我想了解如何在没有样板的情况下以预期方式修复此问题。如果不完全是这样,使用生命周期范围来感知生命周期的目的是什么?

ese*_*sov 2

协程取消是合作性的。这意味着协程本身有责任检查取消。协程库中的大多数(或可能全部)挂起操作都会检查取消情况,但如果您不调用其中任何一个,则需要按照此处所述使代码可取消

在协程中使用视图的更好选择是使用生命周期扩展,当生命周期状态不处于所需状态时,它会自动挂起/取消协程。

另请注意,取消只是常规情况CancellationException,因此请确保您不会意外发现。