RememberObserver : The Compose API You Probably Aren’t Using
When it comes to cleaning things up in Jetpack Compose, the most instinctive approach is to reach for DisposableEffect. It’s the tool we’ve all learned to use when something needs to start when a composable enters the composition and stop when it leaves.
Something like :
@Composable
fun MyScreen() {
val controller = remember { Controller() }
DisposableEffect(Unit) {
onDispose {
controller.cancelJobs()
controller.clearCache()
controller.reset()
}
}
}The composable creates the controller and ensures it is released when the screen leaves the composition.
Okay i know that the previous example is too extreme, because you can just wrapp all these methods insde a single one.
But there is still a small architectural smell hiding here, also the risk to forget and introduce memory leaks. Imagine you had to manually call viewmodel.clear in every view.
RememberObserver has entered the chat
RememberObserver is an interface in Compose that allows an object to know when it is remembered or forgotten by the composition.
public interface RememberObserver {
public fun onRemembered()
public fun onForgotten()
public fun onAbandoned()
}If an object created with remember implements this interface, Compose automatically calls these methods.
When the composable enters the composition, onRemembered() runs.
When it leaves the composition, onForgotten() runs.
So the object becomes lifecycle-aware.
class Controller : RememberObserver {
private var job: Job? = null
private val cache = mutableMapOf<String, Any>()
private var isActive = false
override fun onRemembered() {
isActive = true
}
override fun onForgotten() {
cleanup()
}
override fun onAbandoned() {
// No-op, on onRemembered was not called
}
private fun cleanup() {
job?.cancel()
job = null
cache.clear()
isActive = false
}
}Now the composable can simply use the object.
val controller = remember { Controller() }Another interesting detail is this mechanism is actually used inside Compose itself. Many side-effect APIs like DisposableEffect, LaunchedEffect,ect rely internally on objects implementing RememberObserver.
This way, the cleanup no longer need to be done into the composable. The object owns its internal state, and it also owns the responsibility of cleaning it up.

