Skip to content

Instantly share code, notes, and snippets.

@cbeyls
Last active January 1, 2022 20:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cbeyls/86f18a64b44fff51bc02ff6f82606923 to your computer and use it in GitHub Desktop.
Save cbeyls/86f18a64b44fff51bc02ff6f82606923 to your computer and use it in GitHub Desktop.
A LifecycleOwner composed of children LifecycleOwners
package be.digitalia.utils
import android.os.Handler
import android.os.Looper
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import java.io.Closeable
/**
* A LifecycleOwner composed of children LifecycleOwners.
* Its state moves to STARTED when a least one child Lifecycle is at least in the STARTED state.
* Its state moves to CREATED when no child Lifecycle is at least in the STARTED state.
* Its state moves to DESTROYED when close() is called. The instance cannot be used afterwards.
*/
class CompositeLifecycleOwner(private val stopTimeoutMillis: Long = 1000L) : LifecycleOwner, Closeable {
private val registry = LifecycleRegistry(this).apply {
currentState = Lifecycle.State.CREATED
}
private val handler = Handler(Looper.getMainLooper())
private val children = mutableSetOf<LifecycleOwner>()
private var startedCount = 0
private val lifecycleObserver: LifecycleObserver = LifecycleEventObserver { source, event ->
when (event) {
Lifecycle.Event.ON_START -> incrementStartedCount()
Lifecycle.Event.ON_STOP -> decrementStartedCount()
Lifecycle.Event.ON_DESTROY -> children.remove(source)
else -> Unit
}
}
private val onStopRunnable = Runnable {
registry.currentState = Lifecycle.State.CREATED
}
private fun incrementStartedCount() {
if (++startedCount == 1) {
handler.removeCallbacks(onStopRunnable)
registry.currentState = Lifecycle.State.STARTED
}
}
private fun decrementStartedCount() {
if (--startedCount == 0) {
handler.postDelayed(onStopRunnable, stopTimeoutMillis)
}
}
override fun getLifecycle(): Lifecycle = registry
operator fun plusAssign(child: LifecycleOwner) {
require(child != this)
check(registry.currentState >= Lifecycle.State.CREATED)
if (children.add(child)) {
child.lifecycle.addObserver(lifecycleObserver)
}
}
operator fun minusAssign(child: LifecycleOwner) {
if (children.remove(child)) {
val lifecycle = child.lifecycle
lifecycle.removeObserver(lifecycleObserver)
if (lifecycle.currentState >= Lifecycle.State.STARTED) {
decrementStartedCount()
}
}
}
override fun close() {
handler.removeCallbacks(onStopRunnable)
for (child in children) {
child.lifecycle.removeObserver(lifecycleObserver)
}
children.clear()
startedCount = 0
registry.currentState = Lifecycle.State.DESTROYED
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment