remember cache returns stale value when mutable key contents change without reference update
0 reputation · 19 May 2020, 12:06 UTC
0 reputation · 19 May 2020, 12:06 UTC
The remember function caches a computed value across recompositions as long as the supplied keys remain equal under the runtime's equality check. When a key is a mutable object whose internal state changes but whose reference or hashCode stays identical, the cached value may not refresh, leaving stale data in the UI.
This behavior is a documented limitation across Compose 1.0 through 1.6.x, with no compiler mechanism to flag insufficient keys. The uncertainty lies in determining whether a given key design is safe: specifically, when does structural equality fail to detect meaningful changes, and what alternative patterns—such as keyedRemember with custom equality or derivedStateOf—are appropriate without introducing unnecessary recomposition overhead?
Which equality semantics does the Compose runtime apply to keys passed to remember, and how can developers reliably detect when a mutable key has changed without creating a new reference? Is there a supported way to observe or diagnose stale cache behavior at runtime, or must correctness be guaranteed entirely at design time?
34775 reputation · 19 May 2020, 18:48 UTC
Compose compares remember keys by calling equals() on the key object; it does not use reference identity or hashCode() alone as the invalidation test. For a data class, equals() compares the declared components. For a plain class without an equals() override, equality is reference equality. For standard collections, equals() compares contents, but an overridden equals() can ignore a mutated field. When old and new keys are equal, remember returns the cached value and the UI can show stale data.
Assumed scope: Compose 1.0 through 1.6.x public runtime; later versions may differ. The compiler does not analyze key mutability or warn about insufficient keys. There is no public runtime API to observe or diagnose stale cache hits in production, so correctness is a design-time responsibility. Compiler stability reports can review @Stable and @Immutable annotations, but they do not prove that a key covers every input that affects the cached value.
Run a Compose test: pass a mutable key to remember, mutate a field not included in equals(), and assert the cached value does not refresh. Then use a key that includes the mutated field or derivedStateOf and assert the value refreshes. Enable compiler reports only to review stability annotations; treat stale-key correctness as a code-review concern.
Does the mutable key change through Compose snapshot state, or is it mutated imperatively outside Compose? If it is snapshot state, use derivedStateOf for the key. If it is imperative mutation outside snapshot, derivedStateOf will not see the change; create a new key instance or wrap the state in Compose state.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.