Lesson 4
Remembered, forgotten, and abandoned objects
Classify RememberObserver callbacks without confusing calculation, commitment, and removal.
Status: The distinction between Durable remembered, forgotten, and abandoned outcomes comes from the
RememberObservercontract. Callback threading and dispatcher internals are Version-specific at the pinned revision.
Outcome
Given a remembered object and a composition event, you should be able to predict whether onRemembered, onForgotten, or onAbandoned is the relevant callback—and which callback is not justified.
Three outcomes, three questions
A RememberObserver is not notified when its constructor runs. It is notified when the composition has a lifecycle result for the remembered slot.
| Event | Question answered | Callback |
|---|---|---|
| Successful entry | Did this object become part of the applied composition? | onRemembered() |
| Normal exit | Is this object no longer remembered anywhere in this composition? | onForgotten() |
| Uncommitted result | Was this object returned by remember but never successfully remembered? | onAbandoned() |
The interface says that an object remembered in one place in one composition receives either onRemembered or onAbandoned. If it is remembered successfully, it will eventually receive onForgotten. That is a useful ownership rule, not a statement about garbage collection (RememberObserver.kt).
A successful composition calculates changes and then applies them. An observer created by remember can therefore exist briefly before its callback. Calculation alone is not commitment. If composition throws before the new value is successfully installed, the object is abandoned rather than remembered. The runtime tests deliberately throw after remember { observed } and assert that onAbandoned runs while the other two callbacks do not (CompositionTests.kt).
One instance can have several memberships
The contract counts locations, not object identity alone. If the same RememberObserver instance is returned from two separate remember calls, it has two remembered memberships. Each location can produce its own onRemembered and onForgotten notification. The AndroidX test named testRememberObserver_Remember_SingleNotification uses one instance in two places and expects a count of two after initial composition, with no extra notifications on an ordinary recomposition.
This is why a RememberObserver should usually not be passed broadly through a composition. A reference that is remembered in several places can outlive one caller’s expectation and receive callbacks for each membership. Treat the observer as an owner of the resource associated with its particular remembered location.
Ordering is part of the contract
When several objects enter together, onRemembered follows entry order. When those same objects leave together, onForgotten runs in reverse order. The reverse ordering makes nested ownership easier to unwind: a later-entered child can release before an earlier-entered parent. The tests record R[1] through R[4], then expect F[4] through F[1] when the content leaves.
onRemembered and onForgotten are documented as running on the composition’s apply thread. onAbandoned is different: it reports an uncommitted value and should not be used as evidence that the value entered the applied tree. Do not assume all three callbacks mean “the object was displayed.”
flowchart TD
Calculated[remember calculation returns] --> Applied{Changes applied?}
Applied -->|Yes| Remembered[onRemembered]
Applied -->|No| Abandoned[onAbandoned]
Remembered --> Removed[Group leaves composition]
Removed --> Forgotten[onForgotten]Small lifecycle experiment
Create a token that appends its callback name to a list. Compose it behind a Boolean. First apply with the Boolean true, then recompose with false. Expect remembered followed by forgotten. In a separate composition, throw immediately after creating the token during the first composition. Expect abandoned only. Finally, place the same token in two keyed branches and remove one branch at a time; the count shows membership, not just object count.
Misconceptions to remove
- “A calculated value is remembered immediately.” It is only a candidate until the composition commits it.
- “Abandoned means forgotten.” Forgotten requires prior successful membership.
- “One object means one callback.” One instance can be remembered at multiple locations.
Check yourself
A remember calculation allocates a resource, then composition throws before apply. Which callback should release the resource, and why is onForgotten the wrong prediction?
Source notes
| Claim | Direct evidence | Status |
|---|---|---|
| Definitions and guarantees for all three callbacks | Pinned RememberObserver.kt | Durable |
| Remembered and forgotten order, multiple memberships, and abandonment are tested | Pinned CompositionTests.kt | Version-specific |
| Observer callbacks are part of apply-thread lifecycle | Pinned RememberObserver.kt | Version-specific |
Freshness
Refresh this lesson when the RememberObserver contract, callback ordering, or composition abandonment tests change. Check the Android Review history for CompositionTests.kt before asserting a stronger ordering rule.
Finished this lesson?
Your progress stays only in this browser.