DevBits
DevBitsAndroid Handbook
Jetpack Compose

What is the composition lifecycle?

Understand when Compose starts keeping a part of the UI, what recomposition means while it remains there, and what happens when that part leaves.

CMP-017Advanced~45 sec

What the interviewer is testing

The interviewer is testing whether you can separate recomposition from lifetime.

A composable function may run many times while Compose is still keeping the same part of the UI. The important question is not simply how many times the function ran, but whether that part of the UI is still in the Composition or has actually left it.

That distinction is what lets you reason correctly about remembered state, effects, and cleanup.

❌ Common mistake

If they ask you to elaborate

Start with the mental model from composition:

Composition is the UI that Compose remembers between executions of your composable functions.

The lifecycle question is the next step:

How long does Compose keep a particular part of that UI?

Imagine a checkout screen:

@Composable
fun CheckoutScreen(
    showSummary: Boolean
) {
    CheckoutForm()

    if (showSummary) {
        OrderSummary()
    }
}

Suppose the screen first runs with:

showSummary = false

The UI Compose is keeping can be pictured like this:

CheckoutScreen
└── CheckoutForm

OrderSummary is not part of the UI yet.

Later:

showSummary = true

CheckoutScreen() runs again. This time the condition calls OrderSummary().

Now you can picture the Composition like this:

CheckoutScreen
├── CheckoutForm
└── OrderSummary

Compose is now keeping track of OrderSummary as part of the current UI.

That is what it means for OrderSummary to enter the Composition.

Nothing is physically entering a container somewhere. It simply means that this part of the UI is now part of what Compose is remembering and managing.

So what is Compose actually remembering?

It is worth looking just slightly beneath the mental model, because otherwise this can feel like magic.

Compose is not remembering a screenshot, and it is not storing the finished result of OrderSummary().

As composable functions run, Compose keeps internal bookkeeping about the composable calls that make up the current Composition. During recomposition, the runtime uses that information to update the Composition and determine which parts are still present and which are no longer being produced.

The runtime goes much deeper than that, but you do not need its internal data structures to understand the lifecycle.

For this page, the useful picture is simply:

your composable functions run

Compose keeps track of the UI they describe

that remembered UI is the Composition

Now suppose OrderSummary reads some state:

@Composable
fun OrderSummary(
    total: Money
) {
    Text("Total: $total")
}

The total changes.

Compose may run OrderSummary() again so the text can be updated.

That is recomposition.

But look at what happened to its lifecycle:

OrderSummary enters

Compose keeps it

total changes

OrderSummary recomposes

Compose is still keeping it

It did not leave just because its function ran again.

It may recompose many times while it remains part of the Composition. Compose may also skip running it during an update when there is nothing there that needs changing.

Either way, it can still be part of the Composition.

Now the user goes back to editing the checkout and:

showSummary = false

The condition no longer calls OrderSummary().

The UI is back to:

CheckoutScreen
└── CheckoutForm

Compose no longer needs to keep OrderSummary as part of this Composition.

Now it has left the Composition.

So the lifecycle is easier to picture as:

Compose starts keeping this part of the UI

                ENTER

       it may recompose 0..n times

     Compose is still keeping it

Compose stops keeping this part of the UI

                LEAVE

That is the distinction to hold onto.

Recomposition is something that can happen during the lifetime.

Leaving the Composition is what ends that lifetime.

Why does that matter for remember?

Now the behaviour of remember becomes much easier to reason about:

@Composable
fun OrderSummary() {
    var expanded by remember {
        mutableStateOf(false)
    }

    // ...
}

When OrderSummary enters the Composition, Compose can keep that remembered value with its place in the Composition.

If OrderSummary recomposes, Compose is still keeping that part of the UI, so the remembered value can be reused.

OrderSummary enters

expanded is remembered

recomposition

same remembered value

recomposition

same remembered value

When OrderSummary actually leaves the Composition, that remembered state no longer belongs to an active part of this Composition.

If OrderSummary appears again later, that is a new Composition lifetime and plain remember should not be treated as though the previous one never ended.

This is why understanding the lifecycle is more useful than counting how many times a composable function executes.

Production thinking

Imagine you are building a shopping app and the checkout can show an optional promo-code section:

@Composable
fun CheckoutScreen(
    hasPromoCode: Boolean
) {
    CheckoutForm()

    if (hasPromoCode) {
        PromoCodeSection()
    }
}

Inside that section, the user can expand some help text:

@Composable
fun PromoCodeSection() {
    var showHelp by remember {
        mutableStateOf(false)
    }

    // ...
}

Now walk through what happens in the real screen.

The user adds a promo code.

hasPromoCode = true

PromoCodeSection enters the Composition and showHelp starts as false.

The user opens the help text:

showHelp = true

That state change can cause recomposition.

Maybe the cart total also changes afterward and the checkout recomposes again.

None of those updates mean the promo section disappeared.

Compose is still keeping that part of the UI, so its remembered showHelp state stays with it.

promo section appears

showHelp = false

user opens help

showHelp = true

checkout updates

promo section recomposes

showHelp is still true

Now the user removes the promo code.

hasPromoCode = false

This is different.

PromoCodeSection() is no longer called, so Compose stops keeping that part of the UI.

The promo section has left the Composition.

Its plain remember state belonged to that place in the Composition, so when the section is removed, that remembered value is forgotten.

If the user adds a promo code again later, the section enters again:

promo section enters

showHelp = false

That is often exactly what you want for temporary UI state.

But now imagine the product requirement changes:

"If the promo section disappears and comes back, restore whether the help was open."

That requirement is telling you something important.

The state now needs to survive longer than this particular Composition lifetime.

At that point, plain remember is no longer enough. You would choose an owner or state-saving mechanism whose lifetime matches the behaviour you actually need.

The same reasoning applies to effects.

If some work should exist only while PromoCodeSection is part of the Composition, its lifetime can naturally follow that UI.

If the work must continue after the promo section disappears, then that composable is too short-lived to own it.

That is the production value of understanding the composition lifecycle.

You stop asking:

"Which Compose API should I use?"

and start with:

"How long should this state or work live?"

Then you compare that requirement with the lifetime of the UI:

Should it live only while this UI is present?

Composition lifetime may be the right owner

Should it survive this UI leaving?

It needs a longer-lived owner or saving mechanism

That is the same ownership thinking that makes remember, effects, state holders, and navigation state much easier to reason about.

Follow-up questions

What separates a senior answer

Key takeaways

Learn more

On this page