From 5cdf0f021d6b6ab4268f3a32cd4eb71f370109f5 Mon Sep 17 00:00:00 2001 From: DevSrSouza Date: Mon, 16 Oct 2023 18:48:08 -0300 Subject: [PATCH 1/2] fix: propagating lifecycle events to AndroidScreenLifecycleOwner --- .../androidx/AndroidScreenLifecycleOwner.kt | 61 ++++++++++++++++--- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/androidx/AndroidScreenLifecycleOwner.kt b/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/androidx/AndroidScreenLifecycleOwner.kt index 8db4fb42..4fc55b8a 100644 --- a/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/androidx/AndroidScreenLifecycleOwner.kt +++ b/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/androidx/AndroidScreenLifecycleOwner.kt @@ -53,6 +53,7 @@ public class AndroidScreenLifecycleOwner private constructor() : override val viewModelStore: ViewModelStore = ViewModelStore() private val atomicContext = AtomicReference() + internal val atomicParentLifecycleOwner = AtomicReference() private val controller = SavedStateRegistryController.create(this) @@ -129,10 +130,11 @@ public class AndroidScreenLifecycleOwner private constructor() : override fun onDispose(screen: Screen) { val context = atomicContext.getAndSet(null) ?: return - if (context is Activity && context.isChangingConfigurations) return + val activity = context.getActivity() + if (activity != null && activity.isChangingConfigurations) return viewModelStore.clear() - disposeEvents.forEach { - lifecycle.handleLifecycleEvent(it) + disposeEvents.forEach { event -> + lifecycle.handleLifecycleEvent(event) } } @@ -143,6 +145,7 @@ public class AndroidScreenLifecycleOwner private constructor() : @Composable private fun getHooks(): List> { atomicContext.compareAndSet(null, LocalContext.current) + atomicParentLifecycleOwner.compareAndSet(null, LocalLifecycleOwner.current) return remember(this) { listOf( @@ -153,20 +156,52 @@ public class AndroidScreenLifecycleOwner private constructor() : } } - private fun registerLifecycleListener(outState: Bundle) { - val activity = atomicContext.get()?.getActivity() - if (activity != null && activity is LifecycleOwner) { + private fun registerLifecycleListenerForSaveState(outState: Bundle) { + val lifecycleOwner = getParentLifecycleOwnerOrActivityOrNull() + if (lifecycleOwner != null) { val observer = object : DefaultLifecycleObserver { override fun onStop(owner: LifecycleOwner) { performSave(outState) } } - val lifecycle = activity.lifecycle + val lifecycle = lifecycleOwner.lifecycle lifecycle.addObserver(observer) deactivateLifecycleListener = { lifecycle.removeObserver(observer) } } } + /** + * Returns a unregister callback + */ + private fun registerLifecycleListenerPropagation(): () -> Unit { + val lifecycleOwner = getParentLifecycleOwnerOrActivityOrNull() + if (lifecycleOwner != null) { + val observer = object : DefaultLifecycleObserver { + override fun onPause(owner: LifecycleOwner) { + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE) + } + + override fun onResume(owner: LifecycleOwner) { + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) + } + + override fun onStart(owner: LifecycleOwner) { + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) + } + + override fun onStop(owner: LifecycleOwner) { + lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP) + } + } + val lifecycle = lifecycleOwner.lifecycle + lifecycle.addObserver(observer) + + return { lifecycle.removeObserver(observer) } + } else { + return { } + } + } + @Composable private fun LifecycleDisposableEffect() { val savedState = rememberSaveable { Bundle() } @@ -175,9 +210,11 @@ public class AndroidScreenLifecycleOwner private constructor() : } DisposableEffect(this) { - registerLifecycleListener(savedState) + registerLifecycleListenerForSaveState(savedState) + val unregisterLifecyclePropagation = registerLifecycleListenerPropagation() onStart() onDispose { + unregisterLifecyclePropagation() performSave(savedState) onStop() } @@ -196,6 +233,14 @@ public class AndroidScreenLifecycleOwner private constructor() : else -> null } + private fun getParentLifecycleOwnerOrActivityOrNull(): LifecycleOwner? = + getParentLifecycleOwner() ?: atomicContext.get()?.getActivity() as? LifecycleOwner? + + private fun getParentLifecycleOwner(): LifecycleOwner? = when (val parent = atomicParentLifecycleOwner.get()) { + is AndroidScreenLifecycleOwner -> parent.getParentLifecycleOwner() + else -> parent + } + public companion object { private val initEvents = arrayOf( From 326a5048a01e265a99a4c36accb696bdad1bbf6e Mon Sep 17 00:00:00 2001 From: DevSrSouza Date: Mon, 16 Oct 2023 22:41:16 -0300 Subject: [PATCH 2/2] refactor: requested review changes and some documentation --- .../androidx/AndroidScreenLifecycleOwner.kt | 51 ++++++------------- 1 file changed, 16 insertions(+), 35 deletions(-) diff --git a/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/androidx/AndroidScreenLifecycleOwner.kt b/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/androidx/AndroidScreenLifecycleOwner.kt index 4fc55b8a..a743e8ca 100644 --- a/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/androidx/AndroidScreenLifecycleOwner.kt +++ b/voyager-core/src/androidMain/kotlin/cafe/adriel/voyager/androidx/AndroidScreenLifecycleOwner.kt @@ -57,8 +57,6 @@ public class AndroidScreenLifecycleOwner private constructor() : private val controller = SavedStateRegistryController.create(this) - private var deactivateLifecycleListener: (() -> Unit)? = null - private var isCreated: Boolean by mutableStateOf(false) override val savedStateRegistry: SavedStateRegistry @@ -98,15 +96,13 @@ public class AndroidScreenLifecycleOwner private constructor() : } } - private fun onStart() { + private fun emitOnStartEvents() { startEvents.forEach { lifecycle.handleLifecycleEvent(it) } } - private fun onStop() { - deactivateLifecycleListener?.invoke() - deactivateLifecycleListener = null + private fun emitOnStopEvents() { stopEvents.forEach { lifecycle.handleLifecycleEvent(it) } @@ -156,25 +152,11 @@ public class AndroidScreenLifecycleOwner private constructor() : } } - private fun registerLifecycleListenerForSaveState(outState: Bundle) { - val lifecycleOwner = getParentLifecycleOwnerOrActivityOrNull() - if (lifecycleOwner != null) { - val observer = object : DefaultLifecycleObserver { - override fun onStop(owner: LifecycleOwner) { - performSave(outState) - } - } - val lifecycle = lifecycleOwner.lifecycle - lifecycle.addObserver(observer) - deactivateLifecycleListener = { lifecycle.removeObserver(observer) } - } - } - /** * Returns a unregister callback */ - private fun registerLifecycleListenerPropagation(): () -> Unit { - val lifecycleOwner = getParentLifecycleOwnerOrActivityOrNull() + private fun registerLifecycleListener(outState: Bundle): () -> Unit { + val lifecycleOwner = atomicParentLifecycleOwner.get() if (lifecycleOwner != null) { val observer = object : DefaultLifecycleObserver { override fun onPause(owner: LifecycleOwner) { @@ -191,6 +173,9 @@ public class AndroidScreenLifecycleOwner private constructor() : override fun onStop(owner: LifecycleOwner) { lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP) + + // when the Application goes to background, perform save + performSave(outState) } } val lifecycle = lifecycleOwner.lifecycle @@ -210,13 +195,17 @@ public class AndroidScreenLifecycleOwner private constructor() : } DisposableEffect(this) { - registerLifecycleListenerForSaveState(savedState) - val unregisterLifecyclePropagation = registerLifecycleListenerPropagation() - onStart() + val unregisterLifecycle = registerLifecycleListener(savedState) + emitOnStartEvents() + onDispose { - unregisterLifecyclePropagation() + unregisterLifecycle() + + // when the screen goes to stack, perform save performSave(savedState) - onStop() + + // notify lifecycle screen listeners + emitOnStopEvents() } } } @@ -233,14 +222,6 @@ public class AndroidScreenLifecycleOwner private constructor() : else -> null } - private fun getParentLifecycleOwnerOrActivityOrNull(): LifecycleOwner? = - getParentLifecycleOwner() ?: atomicContext.get()?.getActivity() as? LifecycleOwner? - - private fun getParentLifecycleOwner(): LifecycleOwner? = when (val parent = atomicParentLifecycleOwner.get()) { - is AndroidScreenLifecycleOwner -> parent.getParentLifecycleOwner() - else -> parent - } - public companion object { private val initEvents = arrayOf(