Open
Description
I am not sure if it is covered by #2930, but to me steps look different
Having the following code
val threadLocal = ThreadLocal<Int>()
val stateFlow = MutableStateFlow<Int>(0)
viewLifecycleOwner.lifecycleScope.launch {
stateFlow.collect {
Log.d("testing", "coroutine A: ${threadLocal.get()}")
}
}
viewLifecycleOwner.lifecycleScope.launch(threadLocal.asContextElement(5)) {
delay(1000)
Log.d("testing", "before emit")
stateFlow.emit(1)
Log.d("testing", "after emit")
}
It logs
coroutine A: null
before emit
coroutine A: 5
after emit
So the coroutine A, that doesn't have a threadLocal as a ContextElement, has an access to it just because of Dispatchers.Main.immediate optimization (the code was invoked directly without dispatching, and somehow context element wasn't cleaned up).
If the first coroutine is launched with Dispatchers.Main
(not immediate) the issue disappears.
The reproducer is for android project (can be placed in onViewCreated
in an empty fragment) just because JVM has no direct dispatcher.