Skip to content
AKarda-kazancimain
Personal blog
AK
arda-kazanci › journal ›observing-compose-runtime-with-compositionobserver.md
← Journal.md
observing-compose-runtime-with-compositionobserver.md42 lines · Markdown · UTF-8
Markdown Preview · observing-compose-runtime-with-compositionobserver.md Rendered
journal/observing-compose-runtime-with-compositionobserver.md

Observing Compose Runtime with CompositionObserver

Track state reads and recomposition scope lifecycles with CompositionObserver, and understand the observation fixes in Compose Runtime 1.13.0-beta01.

Compose Runtime associates state reads with recomposition scopes. CompositionObserver is an experimental API for observing those relationships. If you’re building a recomposition analysis tool, it lets you track which state a scope reads, when it becomes invalid, and when it leaves the composition. API reference.

Attach an observer to an existing composition with composition.setObserver(observer):

AttachObserver.kt
import androidx.compose.runtime.Composition
import androidx.compose.runtime.ExperimentalComposeRuntimeApi
import androidx.compose.runtime.tooling.CompositionObserver
import androidx.compose.runtime.tooling.CompositionObserverHandle
import androidx.compose.runtime.tooling.setObserver
@OptIn(ExperimentalComposeRuntimeApi::class)
fun attachObserver(
composition: Composition,
observer: CompositionObserver
): CompositionObserverHandle? = composition.setObserver(observer)
// Retain the returned handle and detach when finished:
// handle?.dispose()

The caller supplies an observer implementation and owns the returned handle. A null handle means the composition doesn’t support observation. The API belongs to androidx.compose.runtime:runtime and requires ExperimentalComposeRuntimeApi opt-in. Registration API.

The observer receives composition start/end events and scope lifecycle callbacks. onReadInScope(scope, value) is particularly useful: it exposes the relationship between a scope and the object it reads. value is usually the snapshot state instance, rather than the value stored inside it.

For example, if a counter reads a MutableState<Int>, an analysis tool can associate that state object with the reading scope. When the scope is invalidated, onScopeInvalidated reports the associated object, or null for direct invalidation through scope.invalidate(). State-driven invalidations aren’t necessarily reported at the moment of the write. Callback contracts.

There are two limits to keep in mind. An invalidated scope isn’t guaranteed to execute again: its parent might remove the branch containing it. Also, onEndComposition marks the end of composition processing; it doesn’t mean a frame has been drawn. These callbacks shouldn’t be treated as a direct measurement of frame time. Scope lifecycle.

What changed in 1.13.0-beta01?

The observer is now selected once at the beginning of a composition pass and kept for the entire pass. If you call setObserver halfway through, the replacement takes effect on the next pass. This keeps a pass’s events associated with the same observer.

Movable content insertion now also reports onBeginComposition and onEndComposition. An observation tool needs those boundaries to interpret its event sequence consistently. Both fixes shipped in Compose Runtime 1.13.0-beta01; the API itself predates that release.

SHARE ENTRYLinkedIn ↗X ↗Markdown / AI ↗
Discussions ardakazanci/blog-comments
● GiscusView discussions on GitHub ↗
⑂Reactions & comments/ Sign in with GitHub to react or join the discussion.
Notifications Newsletter · beehiiv
✓ Active channelSubscribe directly ↗
✉Get new posts by email/ Android, Kotlin, and Compose notes. Straight to your inbox.

SUBSCRIPTION CONFIG · EMAIL DISPATCH

Stay synced with new entries

Receive practical engineering notes on Android architecture, Kotlin, and Jetpack Compose whenever a new article is published.

channel = "email"spam = falseunsubscribe = "anytime"
K subscriber.propertiesEmail address