retain
@Composable
public inline fun <reified T> retain(noinline calculation: () -> T): T
Remember the value produced by calculation
and retain it in the current RetainScope
. A
retained value is one that is persisted in memory to survive transient destruction and recreation
of a portion or the entirety of the content in the composition hierarchy. Some examples of when
content is transient destroyed occur include:
- Navigation destinations that are on the back stack, not currently visible, and not composed
- UI components that are collapsed, not rendering, and not composed
- On Android, composition hierarchies hosted by an Activity that is being destroyed and recreated due to a configuration change
When a value retained by retain
leaves the composition hierarchy during one of these retention
scenarios, the LocalRetainScope
will persist it until the content is recreated. If an instance
of this function then re-enters the composition hierarchy during the recreation, it will return
the retained value instead of invoking calculation
again.
If this function leaves the composition hierarchy when the LocalRetainScope
is not keeping
values that exit the composition, the value will be discarded immediately.
The lifecycle of the retained value can be observed by implementing RetainObserver
. Callbacks
from RememberObserver
are never invoked on objects retained this way. It is invalid to retain
an object that is a RememberObserver
but not a RetainObserver
, and an exception will be
thrown.
The lifecycle of a retained value is shown in the diagram below. This diagram tracks how a retained value is held through its lifecycle and when it transitions between states.
ββββββββββββββββββββββββ
β β
β retain(keys) { ... } β
β βββββββββββββββ
ββββββββββ€ value: T ββ ββββ¬ββββββββββ β β² Exitβ βEnter
compositionβ βcomposition or changeβ β keysβ β ββββββββββββββββββββββββββββ β ββββNo retained valueββββββ€ calculation: () -> T β β β or different keys ββββββββββββββββββββββββββββ β β ββββββββββββββββββββββββββββ β ββββRe-enter compositionβββ€ Local RetainScope β β with the same keys βββββββββββββββββββ¬βββββββββ β β² β β ββYesβββββββββββββββββ β value not β β β restored and β .βββββββββββββββββββ΄ββββββββββββββββββ. β scope stops βββΆ( RetainScope.isKeepingExitedValues ) β keeping exited `βββββββββββββββββββ¬ββββββββββββββββββ' β values β βΌ β ββββββββββββββββββββββββββββ ββNoβββΆβ value is retired β ββββββββββββββββββββββββββββ
Important: Retained values are held longer than the lifespan of the composable they are
associated with. This can cause memory leaks if a retained object is kept beyond its expected
lifetime. Be cautious with the types of data that you retain. Never retain an Android Context or
an object that references a Context (including View), either directly or indirectly. To mark that
a custom class should not be retained (possibly because it will cause a memory leak), you can
annotate your class definition with androidx.compose.runtime.annotation.DoNotRetain
.
Parameters
calculation | A computation to invoke to create a new value, which will be used when a previous one is not available to return because it was neither remembered nor retained. |
Returns
The result of calculation |
@Composable
public inline fun <reified T> retain(vararg keys: Any?, noinline calculation: () -> T): T
Remember the value produced by calculation
and retain it in the current RetainScope
. A
retained value is one that is persisted in memory to survive transient destruction and recreation
of a portion of the entirety of the composition hierarchy. Some examples of when this transient
destruction occur include:
- Navigation destinations that are on the back stack, not currently visible, and not composed
- UI components that are collapsed, not rendering, and not composed
- On Android, composition hierarchies hosted by an Activity that is being destroyed and recreated due to a configuration change
When a value retained by retain
leaves the composition hierarchy during one of these retention
scenarios, the LocalRetainScope
will persist it until the content is recreated. If an instance
of this function then re-enters the composition hierarchy during the recreation, it will return
the retained value instead of invoking calculation
again.
If this function leaves the composition hierarchy when the LocalRetainScope
is not keeping
values that exit the composition or is invoked with list of keys
that are not all equal (==
)
to the values they had in the previous composition, the value will be discarded immediately and
calculation
will execute again when a new value is needed.
The lifecycle of the retained value can be observed by implementing RetainObserver
. Callbacks
from RememberObserver
are never invoked on objects retained this way. It is illegal to retain
an object that is a RememberObserver
but not a RetainObserver
.
Keys passed to this composable will be kept in-memory while the computed value is retained for
comparison against the old keys until the value is retired. Keys are allowed to implement
RememberObserver
arbitrarily, unlike the values returned by calculation
. If a key implements
RetainObserver
, it will not receive retention callbacks from this usage.
The lifecycle of a retained value is shown in the diagram below. This diagram tracks how a retained value is held through its lifecycle and when it transitions between states.
ββββββββββββββββββββββββ
β β
β retain(keys) { ... } β
β βββββββββββββββ
ββββββββββ€ value: T ββ ββββ¬ββββββββββ β β² Exitβ βEnter
compositionβ βcomposition or changeβ β keysβ β ββββββββββββββββββββββββββββ β ββββNo retained valueββββββ€ calculation: () -> T β β β or different keys ββββββββββββββββββββββββββββ β β ββββββββββββββββββββββββββββ β ββββRe-enter compositionβββ€ Local RetainScope β β with the same keys βββββββββββββββββββ¬βββββββββ β β² β β ββYesβββββββββββββββββ β value not β β β restored and β .βββββββββββββββββββ΄ββββββββββββββββββ. β scope stops βββΆ( RetainScope.isKeepingExitedValues ) β keeping exited `βββββββββββββββββββ¬ββββββββββββββββββ' β values β βΌ β ββββββββββββββββββββββββββββ ββNoβββΆβ value is retired β ββββββββββββββββββββββββββββ
Important: Retained values are held longer than the lifespan of the composable they are
associated with. This can cause memory leaks if a retained object is kept beyond its expected
lifetime. Be cautious with the types of data that you retain. Never retain an Android Context or
an object that references a Context (including View), either directly or indirectly. To mark that
a custom class should not be retained (possibly because it will cause a memory leak), you can
annotate your class definition with androidx.compose.runtime.annotation.DoNotRetain
.
Parameters
keys | An arbitrary list of keys that, if changed, will cause an old retained value to be discarded and for calculation to return a new value, regardless of whether the old value was being retained in the RetainScope or not. |
calculation | A producer that will be invoked to initialize the retained value if a value from the previous composition isn't available. |
Returns
The result of calculation |