tynn
tynn

Reputation: 39853

Fragment and viewLifecycleOwner deviation

I'm collecting a flow on the viewLifecycleOwner. It flows on Dispatchers.Default, but the collection itself takes place on Dispatchers.Main.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    viewLifecycleOwner.lifecycleScope.launch {
        flow.flowOn(Default).collect {
            requireContext()
        }
    }
}

In one occation I found the IllegalStateException stating, that the fragment is not attached.

IllegalStateException: Fragment Test not attached to a context.

I assumed that the collection of the flow would be canceled before the fragment is detached.

How is it possible for the coroutine to resume on a detached fragment?

Upvotes: 1

Views: 2224

Answers (1)

aminography
aminography

Reputation: 22832

First of all, it is worth noting that flowOn changes the upstream context, in case you have operator functions such as map, filter, etc, preceding to the flowOn. So, it doesn't affect the context of the terminal functions like collect. It is stated on the kotlin docs. So, if you want to change the context of the collect terminal, you should change it from the outer block, I mean the launch builder function.

Next, to avoid IllegalStateException use context in a safe manner, instead of requireContext() to be sure that the fragment is attached. There is no doubt that all of the coroutines launched in the viewLifecycleOwner.lifecycleScope should be terminated when the fragment is getting destroyed, but in some cases, there might exist a race condition in threads which causes this problem.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    viewLifecycleOwner.lifecycleScope.launch(Main/Default/WhateverContextYouWant) {
        flow.collect {
            context?.let { }
        }
    }
}

Upvotes: 2

Related Questions