Skip to content

Instantly share code, notes, and snippets.

@kmerrell42
Last active December 9, 2022 00:29
Show Gist options
  • Save kmerrell42/7cb71db700bffcfd6a42b27c02553084 to your computer and use it in GitHub Desktop.
Save kmerrell42/7cb71db700bffcfd6a42b27c02553084 to your computer and use it in GitHub Desktop.
Composable effects for the Android Lifecycle (onCreate, onResume, onPause, etc)
package io.mercury.android.coroutines.lifecycle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Lifecycle.Event.ON_CREATE
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
import androidx.lifecycle.Lifecycle.Event.ON_PAUSE
import androidx.lifecycle.Lifecycle.Event.ON_RESUME
import androidx.lifecycle.Lifecycle.Event.ON_START
import androidx.lifecycle.Lifecycle.Event.ON_STOP
import androidx.lifecycle.LifecycleEventObserver
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
/**
* Effect with a lifecycle window from @param launchOnEvent to @param disposeOnEvent. The provided
* @param block will be called during the lifecycle window in a coroutine Job that will get
* cancelled at the end or when the composition is disposed.
*
* The effect runs on the MainDispatcher.
*
* @param launchOnEvent The event to start the effect
* @param disposeOnEvent The event to stop the effect, if null, the effect will run until the Composable is disposed
* @param block The block that runs during the lifecycle window
*/
@Composable
fun LifecycleEffect(
launchOnEvent: Lifecycle.Event,
disposeOnEvent: Lifecycle.Event? = null,
block: suspend CoroutineScope.() -> Unit
) {
val lifecycleOwner = LocalLifecycleOwner.current
val scope = rememberCoroutineScope()
DisposableEffect(lifecycleOwner) {
var job: Job? = null
val observer = LifecycleEventObserver { _, event ->
if (event == launchOnEvent) {
job?.cancel()
job = scope.launch { block() }
} else if (event == disposeOnEvent) {
job?.cancel()
}
}
lifecycleOwner.lifecycle.addObserver(observer)
// Cleanup
onDispose {
job?.cancel()
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
}
/**
* LifecycleEffect that will launch on onCreate and dispose on onDestroy.
*/
@Composable
fun CreatedEffect(block: suspend CoroutineScope.() -> Unit) {
LifecycleEffect(ON_CREATE, block = block)
}
@Composable
fun WhileCreatedEffect(block: suspend CoroutineScope.() -> Unit) {
LifecycleEffect(ON_CREATE, ON_DESTROY, block = block)
}
@Composable
fun StartedEffect(block: suspend CoroutineScope.() -> Unit) {
LifecycleEffect(ON_START, block = block)
}
@Composable
fun WhileStartedEffect(block: suspend CoroutineScope.() -> Unit) {
LifecycleEffect(ON_START, ON_STOP, block = block)
}
@Composable
fun ResumedEffect(block: suspend CoroutineScope.() -> Unit) {
LifecycleEffect(ON_RESUME, block = block)
}
@Composable
fun WhileResumedEffect(block: suspend CoroutineScope.() -> Unit) {
LifecycleEffect(ON_RESUME, ON_PAUSE, block = block)
}
@Composable
fun PausedEffect(block: suspend CoroutineScope.() -> Unit) {
LifecycleEffect(ON_PAUSE, block = block)
}
@Composable
fun StoppedEffect(block: suspend CoroutineScope.() -> Unit) {
LifecycleEffect(ON_STOP, block = block)
}
@Composable
fun DestroyedEffect(onEvent: suspend CoroutineScope.() -> Unit) {
LifecycleEffect(ON_DESTROY, block = onEvent)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment