min
09/01/2025, 11:55 AM@Composable
to inject an output parameter of sorts at compile time via which composables build a composition. I suppose that ‘recomposition scopes’ emitted into the composer by composables somehow correspond to snapshots, and that once a recomposition scope has been invalidated because a state has changed, a rerun of the corresponding composable is scheduled. But where is the code that actually does this? My MainActivity
is a ComponentActivity
, I’ve had a quick look at the call graph that starts from the call to .setContent
in the onCreate
method but couldn’t identify whatever is orchestrating this chain of eventsChrimaeon
09/01/2025, 1:12 PMmin
09/02/2025, 5:48 AMval state = mutableIntStateOf(42)
var nReads = 0
var nWrites = 0
Snapshot.observe(
readObserver = { target: Any -> Unit; if (target == state) nReads += 1 },
writeObserver = { target: Any -> Unit; if (target == state) nWrites += 1 },
) {
kotlin.test.assertEquals(42, state.value)
state.value = 16
state.value = 78
}
kotlin.test.assertEquals(78, state.value)
kotlin.test.assertEquals(1, nReads)
kotlin.test.assertEquals(2, nWrites)
Where in Compose does it install an actual read/write observer like this?min
09/02/2025, 6:05 AMcomposer.currentRecomposeScope?.let {
it.used = true
val alreadyRead = it.recordRead(value)
if (!alreadyRead) {
if (value is StateObjectImpl) {
value.recordReadIn(ReaderKind.Composition)
}
observations.add(value, it)
This in internal class CompositionImpl
I feel is the closest I’ve got to the answer. I suppose that nothing happens automatically and each implementation of Composition
should take care to record what states an instance of it has read (e.g. value
) and which scopes are invalidated (e.g. it
) when the recorded states have changed. But this just explains what keeps track of which recomposition scopes to invalidate on state changes (each composition does), I still don’t know what actually observes reads and writesAlbert Chang
09/03/2025, 9:52 AMmin
09/03/2025, 10:45 AMComponentActivity::onCreate
calls this.setContent(parent: CompositionContext? = null, content: @Composable () -> Unit)
. The method (essentially) gets hold of existingComposeView ?: ComposeView(this)
and calls .setParentCompositionContext(parent: CompositionContext?)
, and .setContent(content: @Composable () -> Unit)
. As a result of the latter, (AbstractComposeView::createComposition)(this)
is called. Would you be so kind as to point out which of these leads to the functions you’ve linked to, please? I’m completely new to Android and I still find that the Jetpack codebase rather expansive. The composing
function you’ve linked seems to be the culprit I’ve been looking for (massive thanks for telling me), I can’t seem to identify which chain of calls leads to it 😭Albert Chang
09/03/2025, 10:52 AM