Chris Fillmore
01/30/2023, 10:10 PM@Composable
fun rememberLifecycleEvents(
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
): Flow<Lifecycle.Event>
@Composable
fun rememberLifecycleEvents(
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
): Flow<Lifecycle.Event> {
val scope = rememberCoroutineScope()
val flow = remember(lifecycleOwner) { MutableSharedFlow<Lifecycle.Event>() }
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
scope.launch {
flow.emit(event)
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
return remember(lifecycleOwner) { flow }
}
val lifecycleEvents = rememberLifecycleEvents()
LaunchedEffect(lifecycleEvents) {
lifecycleEvents.collect {
// Handle lifecycle events
}
}
Kevin Del Castillo
01/30/2023, 10:30 PMinterface LifecycleEffectScope {
/**
* Register a [callback] which will be invoked on [Lifecycle.Event.ON_START].
*/
fun onStart(callback: () -> Unit)
/**
* Register a [callback] which will be invoked on [Lifecycle.Event.ON_RESUME].
*/
fun onResume(callback: () -> Unit)
/**
* Register a [callback] which will be invoked on [Lifecycle.Event.ON_PAUSE].
*/
fun onPause(callback: () -> Unit)
/**
* Register a [callback] which will be invoked on [Lifecycle.Event.ON_STOP].
*/
fun onStop(callback: () -> Unit)
/**
* Register a [callback] which will be invoked on [Lifecycle.Event.ON_DESTROY].
*/
fun onDestroy(callback: () -> Unit)
}
private class LifecycleEffectScopeImpl : LifecycleEffectScope {
private var onStartCallback: (() -> Unit)? = null
private var onResumeCallback: (() -> Unit)? = null
private var onPauseCallback: (() -> Unit)? = null
private var onStopCallback: (() -> Unit)? = null
private var onDestroyCallback: (() -> Unit)? = null
override fun onStart(callback: () -> Unit) {
onStartCallback = callback
}
override fun onResume(callback: () -> Unit) {
onResumeCallback = callback
}
override fun onPause(callback: () -> Unit) {
onPauseCallback = callback
}
override fun onStop(callback: () -> Unit) {
onStopCallback = callback
}
override fun onDestroy(callback: () -> Unit) {
onDestroyCallback = callback
}
val observer = LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_START -> onStartCallback?.invoke()
Lifecycle.Event.ON_RESUME -> onResumeCallback?.invoke()
Lifecycle.Event.ON_PAUSE -> onPauseCallback?.invoke()
Lifecycle.Event.ON_STOP -> onStopCallback?.invoke()
Lifecycle.Event.ON_DESTROY -> onDestroyCallback?.invoke()
else -> {
/* no-op */
}
}
}
}
/**
* A side effect of a composition which registers the callbacks set on [block] using
* [LifecycleEffectScope] setters, whenever [owner] changes the events observer is disposed in
* the old [owner] and attached to the new [owner].
*/
@Composable
fun LifecycleEffect(
owner: LifecycleOwner = LocalLifecycleOwner.current,
block: LifecycleEffectScope.() -> Unit,
) {
DisposableEffect(owner) {
val scope = LifecycleEffectScopeImpl()
scope.block()
owner.lifecycle.addObserver(scope.observer)
onDispose {
owner.lifecycle.removeObserver(scope.observer)
}
}
}
You can use it like this:
LifecycleEffect {
onStart {
// ...
}
onStop {
// ...
}
// etc
}
Chris Fillmore
01/31/2023, 3:48 PMLifecycleEffect
which is consistent with other effects.
The reason I used a Flow is that it is easy to e.g. drop(1)
if we want effects for every ON_START
event after the first one.Kevin Del Castillo
01/31/2023, 3:59 PM