DisposableEffect and Cleanup

Registrations need an undo step. DisposableEffect(key) runs setup on enter and onDispose before a restart or on leave, and does not compile without onDispose: useEffect's cleanup, enforced.

EffectDemos.kt: observing the activity lifecycle from a composable (excerpt)Kotlin
  val owner = LocalLifecycleOwner.current
  DisposableEffect(owner) {
    val observer = LifecycleEventObserver { _, event -> Log.d(FX, "$name saw $event") }
    owner.lifecycle.addObserver(observer)
    Log.d(FX, "$name: observer added")
    onDispose {                                  // key change or leaving the composition
      owner.lifecycle.removeObserver(observer)
      Log.d(FX, "$name: onDispose, observer removed")
    }
  }

Launch, Home, return, then Hide reader:

Output of 93
D/BookNestFx: reader saw ON_CREATE
D/BookNestFx: reader saw ON_START
D/BookNestFx: reader saw ON_RESUME
D/BookNestFx: reader: observer added
D/BookNestFx: reader saw ON_PAUSE
D/BookNestFx: reader saw ON_STOP
D/BookNestFx: reader saw ON_START
D/BookNestFx: reader saw ON_RESUME
D/BookNestFx: reader: onDispose, observer removed

A new observer is replayed the events up to the current state, hence the burst. Lifecycle 2.7.0 and later also offer LifecycleStartEffect and LifecycleResumeEffect.