Expert checklist and prompts for auditing and fixing Android accessibility issues, especially in Jetpack Compose.
The English summary is being prepared. Showing the original description.
Implement navigation in Jetpack Compose using Navigation 3. Use when asked to build state-driven navigation, manage back stacks, scope ViewModels, implement adaptive layouts, or migrate from Navigation Compose.
The English summary is being prepared. Showing the original description.
See how to installReview the instructions the agent will receive before you install.
Implement state-driven navigation in Jetpack Compose using Navigation 3. Unlike Navigation Compose, Navigation 3 models navigation as application state rather than through a NavController. This skill covers navigation keys, back stack management, ViewModel scoping, entry decorators, adaptive layouts, deep links, animations, state restoration, and testing.
Add the Navigation 3 dependencies:
// build.gradle.kts
dependencies {
implementation("androidx.navigation3:navigation3-runtime:1.0.0-alpha08")
implementation("androidx.navigation3:navigation3-ui:1.0.0-alpha08")
// Lifecycle integration
implementation("androidx.lifecycle:lifecycle-viewmodel-navigation3:2.9.2")
// Serialization
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1")
}
// Enable serialization plugin
plugins {
kotlin("plugin.serialization") version "2.2.0"
}
Navigation destinations are represented by immutable serializable objects.
import kotlinx.serialization.Serializable
@Serializable
data object Home
@Serializable
data class Profile(
val userId: String
)
@Serializable
data class Product(
val productId: String,
val showReviews: Boolean = false
)
@Serializable
data object Settings
Keys become your navigation state.
Navigation 3 replaces NavController with a mutable state back stack.
@Composable
fun MyApp() {
val backStack = remember {
mutableStateListOf<Any>(Home)
}
AppNavDisplay(backStack)
}
@Composable
fun AppNavDisplay(
backStack: SnapshotStateList<Any>
) {
NavDisplay(
backStack = backStack,
onBack = {
if (backStack.size > 1) {
backStack.removeLast()
}
}
) { key ->
when (key) {
Home ->
HomeScreen(
onProfileClick = {
backStack += Profile(it)
}
)
is Profile ->
ProfileScreen(
userId = key.userId
)
is Product ->
ProductScreen(
productId = key.productId,
showReviews = key.showReviews
)
Settings ->
SettingsScreen()
}
}
}
backStack += Profile("user123")
backStack.removeLast()
backStack[backStack.lastIndex] = Home
backStack.clear()
backStack += Home
while (backStack.size > 1) {
backStack.removeLast()
}
Arguments already exist inside the navigation key.
when (val key = currentKey) {
is Profile -> {
ProfileScreen(
userId = key.userId
)
}
is Product -> {
ProductScreen(
productId = key.productId
)
}
}
// CORRECT
backStack += Profile(user.id)
// Fetch object inside ViewModel
class ProfileViewModel(
savedStateHandle: SavedStateHandle,
repository: UserRepository
) : ViewModel() {
val profile = savedStateHandle.toRoute<Profile>()
val user =
repository.getUser(profile.userId)
}
// INCORRECT
backStack += User(...)
backStack += ProductRepository(...)
backStack += ProductViewModel(...)
Navigation 3 scopes ViewModels using entry decorators.
NavDisplay(
backStack = backStack,
entryDecorators = listOf(
rememberSceneSetupNavEntryDecorator(),
rememberSavedStateNavEntryDecorator(),
rememberViewModelStoreNavEntryDecorator()
)
) { key ->
// destinations
}
class ProfileViewModel(
savedStateHandle: SavedStateHandle
) : ViewModel() {
val profile =
savedStateHandle.toRoute<Profile>()
}
Navigation 3 uses decorators to attach lifecycle functionality.
rememberSceneSetupNavEntryDecorator()
Creates the navigation scene for each entry.
rememberSavedStateNavEntryDecorator()
Automatically restores destination state after process recreation.
rememberViewModelStoreNavEntryDecorator()
Scopes ViewModels to each navigation entry.
Navigation 3 integrates with Material Adaptive layouts.
NavDisplay(
backStack = backStack,
sceneStrategy = rememberListDetailSceneStrategy()
)
Use adaptive scene strategies to automatically switch between:
Deep links should resolve into navigation keys.
fun handleDeepLink(uri: Uri) {
val userId =
uri.lastPathSegment ?: return
backStack += Profile(userId)
}
Avoid manually constructing route strings.
Navigation transitions are defined using scene transitions.
NavDisplay(
backStack = backStack,
transitionSpec = {
fadeIn() togetherWith fadeOut()
}
)
Navigation 3 animation APIs may evolve while in alpha.
Navigation keys are serializable and automatically restored.
val backStack = rememberSaveable(
saver = navBackStackSaver()
) {
mutableStateListOf(Home)
}
Always ensure keys are serializable.
Navigation becomes simple because it is state-driven.
@Test
fun navigateToProfile() {
val backStack =
mutableStateListOf<Any>(Home)
backStack += Profile("123")
assertEquals(
Profile("123"),
backStack.last()
)
}
Compose UI tests can verify screen rendering by inspecting the current back stack.
| Navigation Compose | Navigation 3 |
|---|---|
NavController | Mutable back stack |
NavHost | NavDisplay |
navigate() | backStack += Key |
popBackStack() | removeLast() |
| String routes | Serializable keys |
composable() | when(key) |
| Navigation graph | State-driven destinations |
navigation/
AppNavigation.kt
NavigationKeys.kt
NavigationDisplay.kt
feature/
home/
profile/
settings/
rememberSaveable for state restorationNo reviews yet. Tell others what you thought.
No login needed. Share how it worked for you, ask a question, or note where it did not run.
No comments yet. Be the first to write one.
Expert checklist and prompts for auditing and fixing Android accessibility issues, especially in Jetpack Compose.
The English summary is being prepared. Showing the original description.
Expert guidance on setting up and maintaining a modern Android application architecture using Clean Architecture and Hilt. Use this when asked about project structure, module setup, or dependency injection.
The English summary is being prepared. Showing the original description.
Authoritative rules and patterns for production-quality Kotlin Coroutines onto Android. Covers structured concurrency, lifecycle integration, and reactive streams.
The English summary is being prepared. Showing the original description.
Guidance on implementing the Data Layer using Repository pattern, Room (Local), and Retrofit (Remote) with offline-first synchronization.
The English summary is being prepared. Showing the original description.
Production-ready scripts for Android app testing, building, and automation. Provides semantic UI navigation, build automation, log monitoring, and emulator lifecycle management. Optimized for AI agents with minimal token output.
The English summary is being prepared. Showing the original description.
Expert guidance on setting up scalable Gradle build logic using Convention Plugins and Version Catalogs.
The English summary is being prepared. Showing the original description.