Deferred Navigation — was es ist, Prinzipien und Implementierung

Autor: IT Sectr Veröffentlicht: 2026-06-10 Lesezeit: 9 Min.

Deferred Navigation ist ein Muster der verzögerten Navigation, bei dem der Übergang zum nächsten Bildschirm nach Abschluss einer asynchronen Operation erfolgt, nicht direkt im Moment der Benutzeraktion. Laut Android Developers (2024) hilft die verzögerte Navigation, Wettlaufsituationen zwischen Navigation und Datenladen zu vermeiden und vereinfacht die Handhabung von Übergängen aus Push-Benachrichtigungen und Deeplinks. Der Hauptunterschied — die Route wird berechnet, nachdem alle erforderlichen Daten verfügbar sind.

Wichtige Punkte

  • Deferred Navigation — verzögerte Navigation, bei der der Übergang nach Abschluss asynchroner Operationen erfolgt
  • Direkte Navigation behandelt den Übergang sofort, deferred wartet auf Daten
  • Typische Szenarien: Authentifizierung, Deeplink, Push-Benachrichtigungen, Konfigurationsladen
  • In Android wird es über Navigation Component mit Callbacks und StateFlow implementiert
  • In iOS wird Combine oder async/await mit einem Navigationskoordinator verwendet

Was ist Deferred Navigation

Deferred Navigation ist ein architektonisches Muster, bei dem die Navigationsentscheidung verschoben wird, bis alle erforderlichen Daten verfügbar sind. Im Gegensatz zu einem direkten Übergang, bei dem der Benutzer eine Taste drückt und sofort zu einem neuen Bildschirm gelangt, trennt die verzögerte Navigation das Auslöseereignis und den tatsächlichen Übergang, indem sie eine asynchrone Operation dazwischen schaltet.

Architektonisch basiert Deferred Navigation auf Zustandsänderung: Ein Tastendruck initiiert einen asynchronen Prozess, und ein Abonnement seines Ergebnisses löst die Navigation aus. Dies ist besonders wichtig in Anwendungen mit MVVM- oder MVI-Architektur, bei denen die ViewModel den Zustand verwaltet und die View (Activity, Fragment, SwiftUI View) Änderungen abonniert und mit einem Übergang reagiert. Dieser Ansatz beseitigt die direkte Abhängigkeit zwischen UI und Navigationslogik.

Laut Google I/O 2023 wird die verzögerte Navigation für alle Szenarien empfohlen, in denen die Navigation vom Ergebnis einer Netzwerkanfrage, Authentifizierungsprüfung, Konfigurationsladung oder Berechtigungen abhängt. Das Muster ist auch bei der Verarbeitung von Deeplinks obligatorisch, bei denen die App zuerst starten, den Startbildschirm laden und erst dann zur Zielroute navigieren muss.

Wann wird verzögerte Navigation benötigt

Deferred Navigation wird in Szenarien verwendet, in denen eine direkte Navigation zu einem falschen Bildschirmzustand oder Ladefehlern führt. Betrachten wir vier Hauptfälle, in denen eine verzögerte Navigation erforderlich ist.

Autorisierung und Authentifizierung

Wenn ein Benutzer auf geschützte Inhalte tippt, muss die Anwendung zuerst das Zugriffstoken überprüfen. Direkte Navigation zum Inhaltsbildschirm führt zu einem leeren Bildschirm oder einem 401-Fehler, wenn das Token abgelaufen ist. Die verzögerte Navigation überprüft das Token und navigiert nur bei Erfolg zum Zielbildschirm. Bei Misserfolg wird zum Anmeldebildschirm umgeleitet.

Verarbeitung von Deeplinks

Wenn eine Anwendung über einen externen Link geöffnet wird, muss sie zuerst den Startbildschirm laden, den Navigationszustand wiederherstellen und erst dann den Deeplink-Übergang ausführen. Eine direkte Navigation zum Zielbildschirm ohne Startkontext führt zu Anomalien: einem leeren Navigationsstapel oder einem defekten Rückwärtsstapel.

Push-Benachrichtigungen mit Inhalt

Beim Tippen auf eine Push-Benachrichtigung kann sich die Anwendung in einem von drei Zuständen befinden: geschlossen, im Hintergrund oder aktiv. Deferred Navigation bestimmt den Anwendungszustand, lädt den erforderlichen Inhalt und zeigt erst dann den Zielbildschirm an. iOS ermöglicht die Verarbeitung dieses Szenarios über UNNotificationContentExtension.

Dynamisches Feature-Flag

Wenn die Funktionalität eines Bildschirms durch ein Feature-Flag vom Server gesteuert wird, ermöglicht die verzögerte Navigation, zuerst die Konfiguration anzufordern und erst dann den Bildschirm anzuzeigen. Wenn die Funktion deaktiviert ist — sieht der Benutzer alternative Inhalte oder einen Platzhalter anstelle eines leeren Bildschirms.

SzenarioDirekte NavigationDeferred Navigation
AutorisierungLeerer Bildschirm bei abgelaufenem TokenUmleitung zum Login
DeeplinkDefekter RückwärtsstapelKorrekter Navigationsstapel
PushLaden ohne KontextDaten bereit vor dem Übergang
Feature-FlagAnzeige nicht verfügbarer FunktionPlatzhalter oder Alternative

Deferred Navigation vs direkte Navigation

Direkte Navigation ist ein traditioneller Ansatz, bei dem der Übergang sofort als Reaktion auf ein Ereignis ausgeführt wird. Der Benutzer drückt eine Taste und der UI-Router wechselt sofort den Bildschirm. Dieser Ansatz ist einfach und vorhersagbar, aber in Szenarien, die Daten vom Server oder Bedingungsprüfungen erfordern, eingeschränkt.

Deferred Navigation fügt eine Schicht in Form eines asynchronen Zustands hinzu. Ein Benutzerereignis startet eine Operation, und ein Abonnement des Ergebnisses steuert die Navigation. Dies erhöht die Codekomplexität, bietet aber Flexibilität: Derselbe Auslöser kann je nach geladenen Daten zu verschiedenen Bildschirmen führen.

Die Wahl zwischen den beiden Ansätzen hängt von den Anforderungen ab: Wenn für die Anzeige eines Bildschirms keine asynchronen Daten erforderlich sind — verwenden Sie die direkte Navigation. Wenn der Bildschirm vom Ergebnis einer Anfrage, Autorisierung oder externen Bedingungen abhängt — ist eine verzögerte Navigation erforderlich. Ein hybrider Ansatz, bei dem einige Übergänge direkt und einige verzögert sind, ist in industriellen Anwendungen die gängigste Praxis.

Implementierung in Android: Navigation Component und ViewModel

Android Jetpack bietet Mechanismen zur Implementierung von Deferred Navigation auf Architekturebene. Die Grundidee ist, dass die ViewModel den Zustand verwaltet, während die Activity oder Fragment Änderungen abonniert und die Navigation über NavController auslöst.

Deferred Navigation mit StateFlow

StateFlow in Kotlin-Koroutinen ist das ideale Werkzeug für verzögerte Navigation. Die ViewModel aktualisiert einen StateFlow mit einem Navigationsereignis, und die Activity beobachtet es und führt den Übergang aus. Nach der Verarbeitung des Ereignisses wird der StateFlow gelöscht, um eine wiederholte Navigation zu verhindern.

kotlin
class MainViewModel : ViewModel() {
    private val _navigation = MutableSharedFlow<NavigationEvent>()
    val navigation: SharedFlow<NavigationEvent> = _navigation

    fun onDeepLinkReceived(link: String) {
        viewModelScope.launch {
            val data = resolveDeepLink(link)
            _navigation.emit(NavigationEvent.GoToScreen(data))
        }
    }
}

Deferred Navigation mit NavController

In der Activity löst ein Abonnement der Navigation den NavController mit der Route aus der ViewModel aus. Um wiederholte Navigation bei Bildschirmdrehung zu verhindern, wird ein NavigationEventWrapper verwendet, der das Ereignis nur einmal verarbeitet. Jetpack Navigation 2.7+ unterstützt Safe Args für typsichere Argumentübergabe.

kotlin
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val vm: MainViewModel by viewModels()
        repeatOnLifecycle(Lifecycle.State.STARTED) {
            vm.navigation.collect { event ->
                when (event) {
                    is NavigationEvent.GoToScreen ->
                        findNavController(R.id.nav_host)
                            .navigate(event.route)
                }
            }
        }
    }
}

Implementierung in iOS: Coordinator Pattern und Combine

iOS hat keine eingebaute Navigation Component ähnlich wie Android Jetpack, daher implementieren Entwickler Deferred Navigation durch das Coordinator Pattern in Kombination mit Combine oder async/await. Der Coordinator verwaltet den Bildschirmstapel und trifft Navigationsentscheidungen basierend auf geladenen Daten.

Coordinator mit Combine

Coordinator ist ein Objekt, das die Navigation zwischen ViewControllern verwaltet. In Kombination mit Combine veröffentlicht die ViewModel Ereignisse über PassthroughSubject, und der Coordinator abonniert sie und führt den Übergang aus. Dieser Ansatz trennt die UI vollständig von der Navigationslogik und folgt den Empfehlungen von Apple für die Anwendungsarchitektur.

swift
final class AppCoordinator {
    private var cancellables = Set<AnyCancellable>()

    func start(viewModel: MainViewModel) {
        viewModel.$navigationDestination
            .compactMap { $0 }
            .sink { [weak self] destination in
                self?.navigateTo(destination)
            }
            .store(in: &cancellables)
    }
}

Deferred Navigation mit async/await

Swift 5.5 führte strukturierte Nebenläufigkeit ein, die es ermöglicht, verzögerte Navigation über async/await ohne Combine zu implementieren. Die ViewModel stellt eine async-Funktion bereit, die nach dem Laden von Daten eine Route zurückgibt. Der Coordinator ruft diese Funktion in einem Task auf und führt den Übergang basierend auf der empfangenen Route aus.

swift
class AuthViewModel: ObservableObject {
    func resolveDeeplink(_ url: URL) async -> AppRoute? {
        guard let token = await AuthService.shared.getValidToken() else { return .login }
        return await DeeplinkRouter.resolve(url, token: token)
    }
}

// In Coordinator:
Task {
    if let route = await viewModel.resolveDeeplink(url) {
        navigateTo(route)
    }
}

Häufige Fehler und Best Practices

Deferred Navigation vereinfacht die Handhabung asynchroner Szenarien, erfordert jedoch einen disziplinierten Ansatz bei der Zustandsverwaltung. Betrachten wir die häufigsten Fehler, die Entwickler bei der Implementierung der verzögerten Navigation machen.

Fehler: Navigation vor Abschluss der Initialisierung

Der häufigste Fehler ist der Versuch, Deferred Navigation durchzuführen, bevor der Startbildschirm vollständig initialisiert und der NavController oder Coordinator für den Übergang bereit ist. In Android führt dies zu IllegalStateException, in iOS — zu einem undefinierten UI-Zustand. Die Lösung besteht darin, sicherzustellen, dass sich der Lebenszyklus der Komponente im Zustand STARTED oder RESUMED befindet, bevor die Navigation ausgelöst wird.

Fehler: Wiederholte Navigation bei Rückkehr zu einem Bildschirm

Wenn der StateFlow oder Subject das Ereignis nach der Verarbeitung nicht löscht, kann der Benutzer bei der Rückkehr zum vorherigen Bildschirm automatisch auf denselben Bildschirm umgeleitet werden. Verwenden Sie SharedFlow mit replay=0 in Android oder CurrentValueSubject mit nil nach der Verarbeitung in iOS, damit das Navigationsereignis nur einmal ausgelöst wird.

Best Practice: Einzelner NavController oder Coordinator

Verwenden Sie eine zentrale Komponente für die gesamte Navigation in der Anwendung. Wenn jede Activity, jeder Fragment oder ViewController einen eigenen Navigationscontroller hat, wird die verzögerte Navigation zwischen verschiedenen Teilen der Anwendung chaotisch. Ein einziger Coordinator vereinfacht das Debuggen und Testen von Navigationsszenarien.

Best Practice: Testen von Szenarien der verzögerten Navigation

Deferred Navigation ist schwieriger zu testen als die direkte Navigation, da asynchrone Operationen einen Zeitfaktor einführen. Verwenden Sie TestDispatcher in Android (kotlinx-coroutines-test) und XCTestExpectation in iOS, um das Laden von Daten zu simulieren und zu überprüfen, ob die Navigation der erwarteten Route folgt. Mocken Sie Autorisierungs- und Deeplink-Dienste für isolierte Tests jedes Szenarios.

Häufig gestellte Fragen

Wie unterscheidet sich Deferred Navigation von Deep Link?

Deferred Navigation ist ein Muster für verzögerte Übergänge, das in jedem asynchronen Szenario angewendet werden kann. Deep Link ist ein Auslöser für die verzögerte Navigation, aber nicht der einzige. Auch Authentifizierung und Feature-Flags verwenden verzögerte Navigation.

Kann man verzögerte und direkte Navigation kombinieren?

Ja, die meisten Anwendungen verwenden einen hybriden Ansatz. Ein Produktlistenbildschirm (ohne asynchrone Abhängigkeiten) kann direkte Navigation verwenden, während ein Detailbildschirm mit Datenladen verzögerte Navigation verwendet. Die Trennung wird durch die Architektur des jeweiligen Bildschirms bestimmt.

Wie vermeidet man Wettlaufsituationen bei verzögerter Navigation?

Verwenden Sie SharedFlow ohne replay in Android und combineLatest ohne Pufferung in iOS. Brechen Sie vorherige Abonnements bei einem neuen Auslöser ab. Dies stellt sicher, dass nur das letzte Navigationsereignis verarbeitet wird.

Unterstützt Jetpack Compose verzögerte Navigation?

Ja, in Compose wird die verzögerte Navigation durch Abonnement des ViewModel-StateFlow und Aufruf von NavController.navigate in LaunchedEffect implementiert. Google empfiehlt die Verwendung von Navigation Compose mit einem ereignisgesteuerten Modell für verzögerte Szenarien.

Wie behandelt man verzögerte Navigation bei minimierter App?

Verschieben Sie die Navigation, bis die Anwendung wieder aktiv wird. In Android verwenden Sie Lifecycle.State.STARTED, um Ereignisse zu filtern. In iOS überprüfen Sie UIApplication.State in Combine- oder async/await-Blöcken.

Zusammenfassung

  • Deferred Navigation — ein Muster, bei dem der Übergang nach Abschluss einer asynchronen Operation erfolgt
  • Hauptszenarien: Authentifizierung, Deeplink, Push-Benachrichtigungen, Feature-Flags
  • StateFlow/SharedFlow in Android und Combine/async-await in iOS sind Implementierungswerkzeuge
  • Deferred Navigation verursacht im Gegensatz zur direkten Navigation keine Wettlaufsituationen beim asynchronen Laden
  • Navigation Component in Android und Coordinator Pattern in iOS sind die grundlegenden Architekturen
  • Ein einziger NavController/Coordinator ist für eine konsistente Navigation obligatorisch
  • Testen von Deferred Navigation erfordert TestDispatcher und Mocks für asynchrone Dienste

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch