Lesson 5
Apply success, failure, and event dispatch
Follow RememberManager and RememberEventDispatcher across successful, failed, and abandoned composition.
Status: The separation between composition, application, and abandonment is Durable .
RememberManager,RememberEventDispatcher, and their exact queues are Version-specific at the pinned AndroidX revision. Paused-composition hooks are Experimental context, not ordinaryremembersemantics.
Outcome
You should be able to trace a remembered object through change calculation, apply, observer dispatch, side-effect dispatch, and the failure path that produces onAbandoned.
RememberManager is the apply-phase inbox
The internal RememberManager receives events while changes execute. Its responsibilities are deliberately broader than remembered values:
rememberingrecords aRememberObserverentering a slot;forgettingrecords one leaving;sideEffectrecords a callback for later;- node lifecycle callbacks record deactivation and release; and
- pausing and resuming hooks preserve ordering for pausable composition.
A composer adds newly created observer values to an abandonment set while calculating. An object is removed when successfully remembered; anything left can be abandoned (Composition.kt).
The dispatcher preserves an order
RememberEventDispatcher implements RememberManager and collects rather than immediately calls the observer methods. During dispatch, it processes leaving objects from the end of the queue, then sends remembers in entry order. It removes successfully dispatched objects from the abandonment set. Side effects are a separate queue dispatched after lifecycle observers (RememberEventDispatcher.kt).
The successful path is:
flowchart TD
Compose[Compose or recompose] --> Changes[Calculate changes]
Changes --> Apply[applyChanges]
Apply --> Commit[End applied changes]
Commit --> Lifecycle[Forget and remember dispatch]
Lifecycle --> Side[SideEffect dispatch]At the pinned applyChangesInLocked implementation, applier.onEndChanges() closes the applied-change boundary after changes execute. Only then does the runtime dispatch lifecycle observers and side effects. SideEffect therefore does not cause commitment; an effect that captured a remembered object sees it after onRemembered. This is the only effect boundary needed here; SideEffect is not the full effect family.
What failure changes
A composition can calculate a new observer and then throw before a successful apply. guardChanges tracks this path. On failure it calls abandonChanges, which clears pending change lists and dispatches abandon notifications for values still in the abandonment set. The trackAbandonedValues helper also dispatches when its block exits unsuccessfully. The result is not a successful remember followed by a forget: no onRemembered callback is promised for the uncommitted value.
A failure during change execution is not evidence that the whole target tree was rolled back. Keep “new object was abandoned” separate from “every earlier node mutation was undone.”
Late changes and paused composition add a qualification. applyChangesInLocked delays abandonment dispatch when late changes or a pending paused composition might still remember the candidate. Only after those paths are resolved are leftovers sent to onAbandoned. This is why exact queue behavior is a pinned implementation detail rather than a simplified rule that every exception immediately invokes the callback.
Reproduce both paths
Build a controlled composition with a logging RememberObserver. First compose successfully and call applyChanges; record the order of onRemembered and a SideEffect. Next remove the group and apply again; record reverse-order onForgotten. Finally create an observer inside a branch that throws after remember. Assert that the failure path records onAbandoned, not onRemembered or onForgotten. Repeat with the runtime’s test configuration if you are investigating the experimental link-buffer path.
Check yourself
Why does the dispatcher need an abandonment set if it already has a remembering list? What can happen between calculating a remembered value and successfully applying its changes?
Source notes
| Claim | Direct evidence | Status |
|---|---|---|
Apply-phase responsibilities and pausing hooks belong to RememberManager | Pinned RememberManager.kt | Version-specific |
| Dispatcher ordering and abandonment-set handling | Pinned RememberEventDispatcher.kt | Version-specific |
| Successful apply dispatches lifecycle observers before side effects | Pinned Composition.kt and EffectsTests.kt | Version-specific |
Failed composition sends uncommitted observer values to onAbandoned | Pinned Composition.kt and CompositionTests.kt | Version-specific |
Freshness
Refresh this lesson when applyChangesInLocked, abandonment tracking, dispatcher queues, or pausable/late change handling changes. Consult the Android Review history for Composition.kt and rerun the lifecycle tests before changing callback-order language.
Finished this lesson?
Your progress stays only in this browser.