Created
December 24, 2023 09:26
-
-
Save jisungbin/3d704ce8a825521f5ef1843cc3b61898 to your computer and use it in GitHub Desktop.
Revisions
-
jisungbin created this gist
Dec 24, 2023 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,100 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.InternalComposeApi import androidx.compose.runtime.NonRestartableComposable import androidx.compose.runtime.RememberObserver import androidx.compose.runtime.currentComposer import androidx.compose.runtime.remember import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.cancel import kotlinx.coroutines.launch internal interface LifecycleEffectHandle : CoroutineScope { fun whenDispose(dispose: () -> Unit) } private class LifecycleEffectScope( parentCoroutineContext: CoroutineContext, private val lifecycleTask: suspend LifecycleEffectHandle.() -> Unit, ) : RememberObserver { private val scope = CoroutineScope(parentCoroutineContext) private var job: Job? = null private var onDispose: (() -> Unit)? = null private val handle = object : LifecycleEffectHandle, CoroutineScope by scope { override fun whenDispose(dispose: () -> Unit) { onDispose = dispose } } override fun onRemembered() { // This should never happen but is left here for safety job?.cancel("Old job was still running!") job = scope.launch { handle.lifecycleTask() } } override fun onForgotten() { job?.cancel(LeftCompositionCancellationException()) onDispose?.invoke() job = null onDispose = null } override fun onAbandoned() { onForgotten() } } private class LeftCompositionCancellationException : CancellationException("The coroutine scope left the composition") { override fun fillInStackTrace(): Throwable { // Avoid null.clone() on Android <= 6.0 when accessing stackTrace stackTrace = emptyArray() return this } } @[Composable NonRestartableComposable] @OptIn(InternalComposeApi::class) internal fun LifecycleEffect( key1: Any?, block: suspend LifecycleEffectHandle.() -> Unit, ) { val applyContext = currentComposer.applyCoroutineContext remember(key1) { LifecycleEffectScope(applyContext, block) } } @[Composable NonRestartableComposable] @OptIn(InternalComposeApi::class) internal fun LifecycleEffect( key1: Any?, key2: Any?, block: suspend LifecycleEffectHandle.() -> Unit, ) { val applyContext = currentComposer.applyCoroutineContext remember(key1, key2) { LifecycleEffectScope(applyContext, block) } } @[Composable NonRestartableComposable] @OptIn(InternalComposeApi::class) internal fun LifecycleEffect( key1: Any?, key2: Any?, key3: Any?, block: suspend LifecycleEffectHandle.() -> Unit, ) { val applyContext = currentComposer.applyCoroutineContext remember(key1, key2, key3) { LifecycleEffectScope(applyContext, block) } } @[Composable NonRestartableComposable] @OptIn(InternalComposeApi::class) internal fun LifecycleEffect( vararg keys: Any?, block: suspend LifecycleEffectHandle.() -> Unit, ) { val applyContext = currentComposer.applyCoroutineContext remember(*keys) { LifecycleEffectScope(applyContext, block) } }