Navigation (Fragment & Compose) Interview Questions
UI › Material & Nav
Walk me through how you'd decide whether a new set of screens belongs in the same navigation graph as an existing flow or in its own nested graph.
What a strong answer covers: Nested graphs earn their keep when a group of destinations forms a self-contained flow with its own clear entry and exit points and, often, a shared ViewModel scoped to the graph itself, like a multi-step checkout or onboarding flow, since scoping a ViewModel to the nested graph's route lets those screens share state without leaking it to the rest of the app. The trap is nesting purely for file organization; if screens don't share scoped state or a common start and end point, a flat graph with clear route naming is simpler to reason about and avoids extra back stack bookkeeping.
Why does mishandling the back stack, say with popUpTo or launchSingleTop, tend to surface as subtle bugs rather than crashes? Give a concrete example.
What a strong answer covers: Back stack mistakes don't throw exceptions, they just leave extra or wrong entries on the stack, so the bug only shows up later as unexpected behavior, like pressing back from a success screen and landing on a stale form instead of the list, or repeatedly tapping a bottom-nav tab and stacking duplicate copies of the same destination. A concrete example: navigating from login to home without popUpTo(loginRoute) { inclusive = true } means pressing back from home returns to the login screen, a bug that's easy to miss in manual testing because nobody presses back immediately after logging in.
You're migrating a Fragment-based app with deep links to Compose Navigation. What are the trickiest parts to get right, and what would you watch for around process death and back stack restoration?
What a strong answer covers: The hardest part is usually that a deep link needs to reconstruct the whole back stack up to the target, not just jump to it, so back behaves correctly, and Compose Navigation's type-safe @Serializable routes mean deep link arguments must deserialize into the same route types used elsewhere, which is easy to get subtly wrong with optional or nullable fields. On process death, the trap is assuming NavController's saved state alone restores everything; any state that lived in a ViewModel scoped to a destroyed back stack entry needs SavedStateHandle-based persistence, and a weak answer forgets that a deep link received while the app is already running follows a different code path than one that triggers a cold start, so both need explicit testing.