Tuesday 9 March 2021

Viewbinding in Fragment causes KotlinNullPointerException running within lifecycle scoped coroutine

I am setting up my Fragment like suggested in Google docs as such:

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

Now I'm calling a coroutine that to my understanding should be scoped to the lifecycle of this fragment. It has a longer network call, then a success:

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

Now when I press the Android system-back button while loadFromNetwork is still loading the fragment gets destroyed and onDestroyView() is called. As such binding now is null. I'm getting a kotlin.KotlinNullPointerException. What I not quite getting is why responseSuccess() is still being executed even though I thought that lifecycleScope is specifically meant for these kind of situations. According to Google Docs:

A LifecycleScope is defined for each Lifecycle object. Any coroutine launched in this scope is canceled when the Lifecycle is destroyed.

I understand this code can be fixed by a few changes and some manual null-checks, but I would like to understand how to fix this without boilerplate and in the intended manner. What is the purpose of using lifecycleScope to be lifecycle aware if not exactly this?



from Viewbinding in Fragment causes KotlinNullPointerException running within lifecycle scoped coroutine

No comments:

Post a Comment