Android Coden
Android 4 min lesen

Multi-Back-Stack Navigation

Multi-Back-Stack Navigation bewahrt den Zustand jedes Bottom-Nav-Tabs separat. Du lernst, wie drei NavOptions-Flags das Verhalten aktivieren.

Wer eine App mit Bottom Navigation Bar baut, kennt das Problem: Der Nutzer navigiert in Tab A tief in die Hierarchie, wechselt zu Tab B – und kehrt anschließend zurück, nur um festzustellen, dass Tab A wieder auf seinem Start-Ziel steht. Alles, was er sich erarbeitet hatte, ist weg. Multi-Back-Stack Navigation beseitigt dieses Problem, indem jeder primäre Tab seinen eigenen, unabhängigen Back-Stack beibehält.

Was ist das?

Multi-Back-Stack Navigation ist ein Verhalten des Jetpack Navigation Component, bei dem jeder Tab einer Bottom Navigation Bar oder eines Navigation Drawer einen eigenen Back-Stack verwaltet. Wechselt der Nutzer zwischen Tabs, wird der Stack des verlassenen Tabs eingefroren und bei Rückkehr exakt wiederhergestellt – inklusive der aktuellen Destination, der ViewModel-Zustände und des gesamten Navigationsverlaufs innerhalb dieses Tabs.

Vor Navigation 2.4 war dieses Verhalten nicht ohne aufwändige Custom-Logik realisierbar. Entwickler mussten Back-Stacks manuell sichern oder Zustände per ViewModel auf Umwegen erhalten. Seit Navigation 2.4 ist Multi-Back-Stack ein First-Class-Feature der Bibliothek, und alle modernen Scaffold-Patterns mit BottomAppBar oder NavigationBar aus Material 3 profitieren direkt davon.

Im Kontext der Roadmap-Phase „Modern Android Architecture” ist dieses Thema der navigatorische Ausdruck des Prinzips, Zustand explizit zu modellieren und zu erhalten. Es ergänzt das ViewModel-Konzept um eine Navigationsschicht und macht deutlich: Nicht nur Daten, auch der Navigationspfad des Nutzers ist wertvoller, persistierender Zustand.

Wie funktioniert es?

Das Herzstück sind drei Flags in NavOptionsBuilder, die beim Aufruf von navController.navigate() gesetzt werden:

  • launchSingleTop = true: Verhindert, dass beim Antippen des bereits aktiven Tabs eine neue Instanz der Start-Destination oben auf den Stack gelegt wird.
  • saveState = true innerhalb von popUpTo { ... }: Friert den aktuellen Back-Stack ein, anstatt ihn zu löschen, wenn popUpTo die Destinations entfernt.
  • restoreState = true: Stellt beim nächsten Besuch einer Destination den zugehörigen gespeicherten Stack wieder her.

Intern speichert der NavController die Back-Stacks als Bundle. Das bedeutet, dass die Stacks Konfigurationsänderungen (Gerät drehen, Split-Screen) und sogar eine vollständige Prozesswiederherstellung überleben – vorausgesetzt, alle Destinations verwenden serialisierbare Argumente.

Der System-Back-Button verhält sich dabei intuitiv: Er navigiert innerhalb des aktuell sichtbaren Tab-Stacks rückwärts. Ist der aktive Stack erschöpft, kehrt die App zum vorherigen Tab zurück oder beendet sich, je nachdem, wie popUpTo und die globale Navigation konfiguriert sind.

In der Praxis

Ein vollständiges Beispiel in Compose mit androidx.navigation:navigation-compose:

@Composable
fun BottomNavBar(navController: NavHostController) {
    val navBackStackEntry by navController.currentBackStackEntryAsState()
    val currentRoute = navBackStackEntry?.destination?.route

    NavigationBar {
        listOf("home", "search", "profile").forEach { route ->
            NavigationBarItem(
                selected = currentRoute == route,
                onClick = {
                    navController.navigate(route) {
                        popUpTo(navController.graph.findStartDestination().id) {
                            saveState = true          // Stack einfrieren
                        }
                        launchSingleTop = true        // Keine Duplikate
                        restoreState = true           // Stack wiederherstellen
                    }
                },
                icon = { /* Icon */ },
                label = { Text(route) }
            )
        }
    }
}

Stolperfalle: popUpTo ohne saveState

Der häufigste Fehler stammt aus alten Tutorials und Stack-Overflow-Antworten, die vor Navigation 2.4 geschrieben wurden. Dort sieht man oft:

popUpTo(navController.graph.findStartDestination().id) {
    // saveState fehlt hier!
}

Ohne saveState = true wird der Back-Stack des verlassenen Tabs unwiderruflich gelöscht statt eingefroren. Das Ergebnis ist exakt der frustrierende Tab-Neustarteffekt, den Multi-Back-Stack eigentlich verhindern soll. Der Code kompiliert und läuft fehlerfrei – der Fehler zeigt sich erst im manuellen Test.

Stolperfalle: ViewModel-Lebenszyklus

ViewModel-Instanzen, die an einen NavBackStackEntry gebunden sind, leben nur so lange wie dieser Eintrag im Stack. Werden Daten über Tab-Wechsel hinaus benötigt, müssen sie in einem Activity-scoped oder Application-scoped ViewModel oder in einem Repository-Cache gehalten werden. Bindest du dauerhaft relevante Daten fälschlicherweise an einen Back-Stack-Entry, verlierst du sie beim nächsten popUpTo.

Fazit

Multi-Back-Stack Navigation ist eine kleine Konfigurationsänderung mit großem Effekt auf die User Experience: Drei Flags in NavOptionsBuilder verwandeln eine frustrierende Tab-Erfahrung in eine natürliche, zustandstreue Navigation. Öffne eine eigene App mit Bottom Navigation und überprüfe im Android Studio Layout Inspector, ob die Stacks korrekt aufgebaut und erhalten werden. Navigiere tief in einen Tab, wechsle zu einem anderen und kehre zurück – bleibt der Zustand erhalten? Schreibe anschließend einen Compose-UI-Test, der diesen Wechsel simuliert: Ein grün leuchtender Test ist der zuverlässigste Beweis, dass deine Navigation korrekt konfiguriert ist und bleibt.

Quellen (4)
Redaktion

Geschrieben von

Redaktion

Das Redaktionsteam recherchiert und schreibt Artikel zu aktuellen Themen rund um Tech, Lifestyle und Ratgeber.