Hello everybody, I’m new to Android development an...
# compose
m
Hello everybody, I’m new to Android development and have a question about Jetpack Compose: I understand that the ‘compiler’ (Kotlin compiler plugin) transforms every
@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 events
c
Have a look at Composer and Applier. also if you are really interested in the internals, check out https://jorgecastillo.dev/book/
👆 1
👀 1
m
@Chrimaeon Thanks for having a look at my question! I appreciate the links and I’ve checked them out but unfortunately I’m still deeply confused
Copy code
val 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?
Copy code
composer.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 writes
a
Where are you reading the source code? If you are reading in an IDE or on cs.android.com, you can easily follow the call hierarchy and find this, which is where state reads and writes during composition are recorded. And here is what happens when states are written outside composition.
m
@Albert Chang My
ComponentActivity::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 😭
a
Please follow the call hierarchy yourself. Another way is to set a breakpoint on the lines and debug the app.