Reputation: 39853
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
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