min
06/13/2026, 9:23 AMwhile (shouldKeepRecomposing) {
awaitWorkAvailable()
// ...
if (!recordComposerModifications()) continue
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^👆
// ...
parentFrameClock.withFrameNanos { frameTime ->
// ...
trace("Recomposer:recompose") {
recordComposerModifications()
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^👆
I know that Recomposer.recordComposerModifications converts snapshot invalidations to composition invalidations. But why do we call it twice per iteration in the recompositionRunner body loop??min
06/13/2026, 9:29 AMif (hasBroadcastFrameClockAwaiters) {
trace("Recomposer:animation") {
// Propagate the frame time to anyone who is awaiting from the
// recomposer clock.
broadcastFrameClock.sendFrame(frameTime)
// Ensure any global changes are observed
Snapshot.sendApplyNotifications()
}
}
Ah it’s probably because of this if that precedes the trace block. Something that has waiting for the next frame might write to the global snapshot after the initial call to Recomposer.recordComposerModifications has converted all snapshot invalidations to composition invalidations which would result in more and newer snapshot invalidations to also convertshikasd
06/17/2026, 12:54 PMwithFrameNanos is a suspend call, so we might accumulate new changes between those twomin
06/18/2026, 12:29 PM