Last active
October 28, 2023 20:01
-
-
Save fergusonm/88a728eb543c7f6727a7cc473671befc to your computer and use it in GitHub Desktop.
launchWhenX dropping events
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MainFragment : Fragment(R.layout.main_fragment) { | |
companion object { | |
fun newInstance() = MainFragment() | |
} | |
private lateinit var viewModel: MainViewModel | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
viewModel = ViewModelProvider(this).get(MainViewModel::class.java) | |
lifecycleScope.launchWhenStarted { | |
viewModel.flow.collect { | |
print("********** View: launch when started collector received $it in lifecycle state ") | |
println(lifecycle.currentState.name) | |
} | |
} | |
// Notify the view model of a lifecycle event just to cause | |
// emissions during different lifecycle states. In practice | |
// the view model will emit values down the flow | |
// without care to the observer's lifecycle state. | |
// This just forces the conditions | |
// necessary to demonstrate the issue. | |
lifecycle.addObserver(LifecycleEventObserver { source: LifecycleOwner, event: Lifecycle.Event -> | |
println("********** event: ${event.name}") | |
viewModel.lifecycleEvent(event.name) | |
} | |
) | |
} | |
} | |
class MainViewModel : ViewModel() { | |
private var counter = AtomicInteger(0) | |
private val channel = Channel<String>(Channel.BUFFERED) | |
val flow = channel.receiveAsFlow() | |
fun lifecycleEvent(eventName: String) { | |
viewModelScope.launch { | |
// Send the event name down the flow to make some traffic | |
val i = counter.getAndIncrement() | |
val event = "$eventName $i" | |
println("********** ViewModel: Emitting $event on the flows") | |
channel.send(event) | |
} | |
} | |
} | |
Note that if you run this you'll see the following logs: | |
********** event: ON_STOP | |
********** ViewModel: Emitting ON_STOP 4 on the flows | |
********** View: launch when started collector received ON_STOP 4 in lifecycle state CREATED | |
********** event: ON_DESTROY | |
********** ViewModel: Emitting ON_DESTROY 5 on the flows | |
********** event: ON_CREATE | |
********** ViewModel: Emitting ON_CREATE 6 on the flows | |
********** View: launch when started collector received ON_CREATE 6 in lifecycle state STARTED | |
Note the event forced out during ON_STOP was received in the CREATED lifecycle state. This makes sense as the observer is in on_stop. However, this could be bad if the event is a navigation event. | |
Also, note that the ON_DESTROY event that was forced out was dropped! That is, no observer collected it. This is really bad. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment