cswork / libraryOpen practice workspace

Articles

Android Process Death Interview Questions: Saved State, Navigation, and Recovery

Prepare for Android process death questions with state ownership, navigation restoration, durable drafts, and safe recovery of uncertain submissions.

Your Android form survives rotation, so the state handling looks finished. Then the user backgrounds the app, the system removes its process, and reopening the task loses the draft or submits it twice. A rotation test did not exercise the same failure boundary.

Android process death interview questions test whether you know where state lives and how a screen can be reconstructed without the old process. The strongest answer starts with ownership and recovery rules, then selects APIs. A ViewModel, saved-state mechanism, and database serve different lifetimes.

Evidence boundary: Android Developers documentation provides the platform facts below. The expense draft, recovery ledger, and test protocol are original interview exercises, not candidate reports or claims about an employer's assessment. Apply the recovery reasoning to Design an Offline Multi-Device E-Book Reader.

Why is process death different from a configuration change?

Official platform distinction: Android's Save UI states guidance distinguishes ViewModel memory, saved state, and persistent storage. A ViewModel can survive a configuration change but does not survive system-initiated process death. Saved state can support reconstruction after that process loss; durable storage serves longer-lived application data.

During rotation, an activity may be recreated while the application process remains alive. A correctly scoped ViewModel can continue holding a loaded object or draft. When the process is gone, its heap is gone too: singletons, static fields, caches, and ViewModel instances are no longer a recovery source.

The restored application must create new objects. It may receive saved information from the system and load application records from storage, but it does not resume by finding the old ViewModel waiting in memory.

Ask the interviewer which dismissal is in scope. Returning to an existing task after system reclamation differs from a fresh launch after the user intentionally removes the task. A product may want a durable draft in both situations, while transient navigation state only returns in the first.

This distinction prevents an overclaim such as “SavedStateHandle persists everything across every restart.” Name the lifecycle boundary before choosing the mechanism.

What should go into each state store?

Use an original expense-entry screen. The user has selected draft D42, entered a description, attached a receipt, and scrolled to the category field. Separate the domain record from the UI's current way of displaying it.

ItemSuggested owner in this exerciseRecovery rule
Draft ID D42Navigation argument or lightweight saved stateLoad the draft by stable identity
Expanded category pickerUI saved state if worth restoringRecreate the control state
Scroll anchorLightweight UI saved stateApply after matching content is available
Durable draft textLocal repository/databaseReload the latest committed draft
Receipt image bytesFile storage with a database referenceVerify the referenced file is available
Derived validation messagesRecomputed UI stateRevalidate restored input
In-flight request objectProcess memory onlyReconcile the operation using durable identity

These are design choices for the exercise, not a universal schema. A short search query may belong in saved state, while a long document draft deserves durable persistence. The important question is what the user expects to survive and how much data must be reconstructed.

Avoid putting a bitmap or a large response graph into the saved-state payload just because it is serializable. Store an identifier and reload the data. Serialization cost and shared state-transport limits make “save the entire screen object” a poor default.

Also avoid using both saved state and a database as independent authorities for the same text without a precedence rule. If the saved copy is older, blindly applying it after loading the repository can overwrite newer work. Record a revision or choose one authoritative draft source.

How do SavedStateHandle and Compose state fit?

Official API guidance: Android's Saved State module for ViewModel describes SavedStateHandle as a way to retain small values needed for reconstruction. Its saved record is tied to the task stack. It is not equivalent to durable storage after task dismissal, force-stop, or reboot.

For screen logic owned by a ViewModel, a saved query or selected item ID can help reconstruct the screen. The new ViewModel reads that value, then asks the repository for the relevant data. The repository should not depend on an activity instance that disappeared with the old process.

For local Compose UI state, Save UI state in Compose documents saveable state mechanisms and custom saving behavior. remember alone retains values across recompositions, not across process death. Use an appropriate saved-state mechanism for small restorable values, with APIs matched to the project's Compose version.

Keep custom savers focused on stable data. A saver can encode a selection key; it should not attempt to serialize a live coroutine, open stream, or UI controller. Restoration constructs fresh runtime objects around the recovered data.

Lifecycle timing matters too. Android documents that saved-state capture is associated with the host activity stopping; writes while it is already stopped may not be captured unless another start/stop cycle occurs. Do not treat every assignment to a saved-state handle as an immediately durable write.

If the product must not lose an edit after acknowledging “Saved,” persist the edit through the repository and define that acknowledgment against the storage operation. A saved-state API is not a substitute for that product guarantee.

Why is onDestroy not a reliable last chance to save?

Official lifecycle fact: Android's Processes and app lifecycle documentation explains that the system manages process importance and may terminate a process without calling onDestroy. Recovery cannot rely on a final cleanup callback executing before the heap disappears.

Save meaningful user work as part of the normal workflow. For the expense draft, define whether edits persist immediately, after a debounce, or at an explicit save action. If using a debounce, state the possible loss window rather than promising perfect preservation.

Do not turn every keystroke into an unbounded disk operation on the main thread. A repository can coordinate asynchronous writes and expose saving status, but it still needs ordering and failure handling. An older write completing later must not replace a newer revision.

An interview follow-up might ask whether moving the app to the background guarantees the latest draft reached disk. The answer depends on the write protocol, not simply on receiving a lifecycle event. Track completion of the write that defines the durable revision.

Use lifecycle callbacks to coordinate work where appropriate, but make the underlying data ownership and persistence policy explicit. The application should recover correctly even when no farewell callback is delivered.

How should navigation recover without stale objects?

Restore destinations using stable identities rather than serialized copies of complex domain objects. A route pointing to D42 gives a newly created screen a clear lookup target. Passing an entire mutable expense object through navigation creates a second copy that can become stale.

Android's navigation documentation describes the navigation system and its back-stack concepts. The exact restoration integration depends on the navigation library and version, so verify the project configuration rather than asserting that every custom navigator saves itself automatically.

For the exercise, define a recovery sequence: reconstruct the destination, obtain the draft ID, load the draft, verify it still belongs to the current account, then restore the relevant local UI state. Show loading or an unavailable state while the record is being resolved.

A missing draft is a valid outcome. It may have been deleted, submitted on another device, or removed after sign-out. Do not crash because saved navigation information referenced an object that no longer exists. Choose a useful destination and explain what happened without revealing another account's data.

Apply a scroll position only after the expected content is present. A raw index from an older list may point at a different item after sorting or filtering changes. A stable item anchor plus an offset may better express the user's place, depending on the list implementation.

Navigation restoration is therefore a request to reconstruct context, not proof that yesterday's data and permissions are still valid.

What happens if the process dies during submission?

This is the most consequential part of the expense example. The user presses Submit. The server commits the expense, but the app process disappears before receiving the response. On recovery, a local isSubmitting=true flag cannot tell you whether the remote operation succeeded.

Persist an operation identity before sending work when the workflow requires safe recovery. Use the service's documented idempotency or operation-status contract to reconcile that identity. The recovered app can discover the completed submission or retry within the contract without creating a duplicate expense.

This is system-design reasoning, not an Android API guarantee. A saved-state handle cannot create server-side deduplication. Likewise, a durable background-work mechanism does not make a non-idempotent remote API safe by itself.

Write the ambiguous-outcome sequence explicitly:

  1. Persist draft D42 and submission identity S9.
  2. Send S9 with the intended draft revision.
  3. Allow the server to commit while withholding the response.
  4. Terminate the app process through the controlled test setup.
  5. Restore D42 and S9, then reconcile the server outcome.
  6. Show the submitted expense without sending a second logical submission.

Also test the alternate branch where the server never committed. The same recovery protocol must eventually allow progress. A design that avoids duplicates by leaving every uncertain submission stuck forever is incomplete.

Separate “resume the screen” from “resume the operation.” Some work needs a durable scheduler, some can wait until the user returns, and some requires explicit user confirmation because the underlying data changed. Explain the choice for the operation in the prompt.

How do you test real process-death recovery?

Start with a controlled debug build and a known fixture. Navigate to the expense screen, create the draft state, and background the app so the intended lifecycle save point can occur. Record the process identity before terminating it through an appropriate test mechanism, then return through the existing task.

Verify that a new process was created. Seeing the same screen after pressing Home is not evidence that any process died. Do not use force-stop as if it were interchangeable with system-initiated reclamation; it changes the task and restart conditions you are trying to test.

Similarly, “Don't keep activities” and activity recreation tests are useful for activity lifecycle coverage, but they do not by themselves establish recovery from a completely lost process heap. Keep those tests as separate rows in the test plan.

For the expense exercise, assert the restored draft ID, durable text revision, available receipt reference, correct account, and sensible navigation destination. Check that no duplicate submission occurs and that stale loading indicators are replaced by reconciled state.

Repeat with a missing draft, unavailable network, invalid saved value, and changed authentication. A happy-path restore from a perfectly intact database is only one branch. Test the intended product behavior after deliberate task dismissal separately, because persistent drafts may survive even when transient saved UI state does not.

Record what you actually exercised: device or emulator version, app/library versions, termination method, preconditions, and observed process change. This article describes the protocol; it does not claim an emulator run or device-specific result.

How should you summarize the design in an interview?

A concise answer might be: “The ViewModel holds live screen state, but I assume it disappears with the process. I save small reconstruction inputs and persist user-owned drafts in the repository. On restore, I load by identity, recheck account and record validity, rebuild navigation, and reconcile any uncertain submission before allowing another one.”

Then name a trade-off. Immediate durable writes cost more than keeping edits in memory. A debounce has a loss window. Restoring every visual detail can add complexity without helping the user. Choose the policy that matches the screen's value and expectations.

The key is a recoverable data model. Adding more lifecycle callbacks cannot compensate for not knowing which record is authoritative or whether a remote operation already happened.

Sources and Further Reading