Jetpack Navigation zu Navigation Compose migrieren

Mit der Navigation Compose API können Sie zwischen zusammensetzbaren Funktionen in einem Compose-Anwendung erstellen und gleichzeitig die Komponente Jetpack Navigation nutzen, Infrastruktur und Funktionen.

Auf dieser Seite wird beschrieben, wie Sie von einer fragmentierten Jetpack-Navigation zu Navigation Compose ist Teil der größeren, ansichtsbasierten UI-Migration zu Jetpack. Schreiben.

Voraussetzungen für die Migration

Sie können zu Navigation Compose migrieren, sobald Sie alle Ihre Fragmente durch entsprechende Bildschirm-Composeables ersetzt haben. Zusammensetzbare Funktionen des Bildschirms können eine Mischung aus "Inhalt erstellen" und "Inhalt ansehen", aller Navigationsziele müssen jedoch componables, um die Migration von „Navigation Compose“ zu aktivieren. Bis dahin sollten Sie Verwenden Sie weiterhin die Komponente für die fragmentierte Navigation in Ihrer Interoperabilitätsansicht und Codebasis erstellen Weitere Informationen finden Sie in der Dokumentation zur Navigationsinteroperabilität.

Die Verwendung von Navigation Compose in einer reinen Compose-App ist keine Voraussetzung. Sie können weiterhin die Komponente für die fragmentierte Navigation verwenden, Fragmente zum Hosting Ihrer zusammensetzbaren Inhalte

Migrationsschritte

Ob Sie nun unsere empfohlene Migrationsstrategie nutzen oder erreichen Sie einen Punkt, an dem alle Navigationsziele zusammensetzbare Bildschirme, wobei Fragmente nur als zusammensetzbare Container fungieren. In dieser können Sie zu „Navigation Compose“ migrieren.

Wenn Ihre App bereits einem UDF-Designmuster folgt, und unserem Leitfaden zur Architektur durchgeführt werden, sollte die Migration zu Jetpack Compose und Navigation Compose Sie erfordern größere Refaktorierungen anderer Ebenen Ihrer App, abgesehen von der UI-Ebene.

So migrieren Sie zu „Navigation Compose“:

  1. Fügen Sie Ihrer App die Navigation Compose-Abhängigkeit hinzu.
  2. Erstellen Sie eine zusammensetzbare Funktion App-level und fügen Sie sie der Datei Activity als Erstellen Sie den Einstiegspunkt und ersetzen Sie dabei die Einrichtung des Ansichtslayouts:

    class SampleActivity : ComponentActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            // setContentView<ActivitySampleBinding>(this, R.layout.activity_sample)
            setContent {
                SampleApp(/* ... */)
            }
        }
    }

  3. Erstellen Sie Typen für jedes Navigationsziel. data object verwenden für Ziele, die keine Daten erfordern, und data class oder class für für Ziele, für die Daten erforderlich sind.

    @Serializable data object First
    @Serializable data class Second(val id: String)
    @Serializable data object Third
    

  4. Richten Sie die NavController an einem Ort ein, an dem alle zusammensetzbaren Funktionen vorhanden sind, die darauf zugreifen können (diese befindet sich normalerweise in der App zusammensetzbar). Dieser Ansatz folgt den Grundsätzen des Zustands-Hoisting und ermöglicht es, NavController als vertrauenswürdige Quelle für die Navigation zwischen zusammensetzbaren Bildschirmen und die Aufrechterhaltung des Backstacks zu verwenden:

    @Composable
    fun SampleApp() {
        val navController = rememberNavController()
        // ...
    }

  5. Erstellen Sie das NavHost Ihrer App in der zusammensetzbaren Funktion App und übergeben Sie den navController:

    @Composable
    fun SampleApp() {
        val navController = rememberNavController()
    
        SampleNavHost(navController = navController)
    }
    
    @Composable
    fun SampleNavHost(
        navController: NavHostController
    ) {
        NavHost(navController = navController, startDestination = First) {
            // ...
        }
    }

  6. Fügen Sie die composable Ziele hinzu, um Ihren Navigationsgraphen zu erstellen. Wenn jede Bildschirm zuvor zu „Schreiben“ migriert wurde, besteht dieser Schritt nur Extrahieren dieser zusammensetzbaren Funktionen aus Ihren Fragmenten in den composable Ziele:

    class FirstFragment : Fragment() {
    
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View {
            return ComposeView(requireContext()).apply {
                setContent {
                    // FirstScreen(...) EXTRACT FROM HERE
                }
            }
        }
    }
    
    @Composable
    fun SampleNavHost(
        navController: NavHostController
    ) {
        NavHost(navController = navController, startDestination = First) {
            composable<First> {
                FirstScreen(/* ... */) // EXTRACT TO HERE
            }
            composable<Second> {
                SecondScreen(/* ... */)
            }
            // ...
        }
    }

  7. Wenn Sie der Anleitung zum Erstellen Ihrer Compose-UI gefolgt sind: insbesondere wie ViewModels und Navigationsereignisse an zusammensetzbaren Funktionen verwenden, ändern Sie im nächsten Schritt, wie Sie die ViewModel jeder Bildschirm zusammensetzbar ist. Sie können Hilt Injection und die Punkt mit „Schreiben“ und „Navigation über hiltViewModel“:

    @Composable
    fun FirstScreen(
        // viewModel: FirstViewModel = viewModel(),
        viewModel: FirstViewModel = hiltViewModel(),
        onButtonClick: () -> Unit = {},
    ) {
        // ...
    }

  8. Ersetzen Sie alle findNavController()-Navigationsanrufe durch navController-Anrufe und übergeben Sie diese als Navigationsereignisse an jeden zusammensetzbaren Bildschirm, anstatt die gesamte navController zu übergeben. Dieser Ansatz entspricht dem besten Praktiken, wie Ereignisse aus zusammensetzbaren Funktionen für Aufrufer und behält navController die zentrale Informationsquelle bei.

    Daten können an ein Ziel übergeben werden, indem eine Instanz der für dieses Ziel definierten Routenklasse erstellt wird. Sie kann dann entweder direkt aus dem Back-Stack-Eintrag am Ziel oder aus einem ViewModel mit SavedStateHandle.toRoute()

    @Composable
    fun SampleNavHost(
        navController: NavHostController
    ) {
        NavHost(navController = navController, startDestination = First) {
            composable<First> {
                FirstScreen(
                    onButtonClick = {
                        // findNavController().navigate(firstScreenToSecondScreenAction)
                        navController.navigate(Second(id = "ABC"))
                    }
                )
            }
            composable<Second> { backStackEntry ->
                val secondRoute = backStackEntry.toRoute<Second>()
                SecondScreen(
                    id = secondRoute.id,
                    onIconClick = {
                        // findNavController().navigate(secondScreenToThirdScreenAction)
                        navController.navigate(Third)
                    }
                )
            }
            // ...
        }
    }

  9. Entfernen Sie alle Fragmente, relevanten XML-Layouts, unnötige Navigations- und andere Ressourcen sowie veraltete Fragment- und Jetpack Navigation-Abhängigkeiten.

Dieselben Schritte finden Sie auch in der Dokumentation zur Einrichtung

Gängige Anwendungsfälle

Unabhängig davon, welche Navigationskomponente Sie verwenden, gelten dieselben Navigationsprinzipien.

Gängige Anwendungsfälle für die Migration:

Weitere Informationen zu diesen Anwendungsfällen finden Sie unter Navigation mit Schreiben:

Komplexe Daten beim Navigieren abrufen

Wir raten dringend davon ab, bei der Navigation komplexe Datenobjekte zu übergeben. Geben Sie stattdessen die mindestens erforderlichen Informationen an, etwa eine eindeutige Kennung oder andere Art von ID als Argumente beim Ausführen von Navigationsaktionen. Sie sollten Speichern komplexer Objekte als Daten in einer einzigen Quelle der Wahrheit, wie z. B. den Daten Ebene Weitere Informationen finden Sie unter Abrufen komplexer Daten beim Navigieren.

Wenn Ihre Fragmente komplexe Objekte als Argumente übergeben, sollten Sie Ihren Code zuerst so umstrukturieren, dass diese Objekte in der Datenebene gespeichert und abgerufen werden können. Weitere Informationen finden Sie im Repository „Now in Android“ für Beispiele.

Beschränkungen

In diesem Abschnitt werden die aktuellen Einschränkungen für Navigation Compose beschrieben.

Inkrementelle Migration zu Navigation Compose

Derzeit können Sie „Navigation Compose“ nicht verwenden, während Sie Fragmente weiterhin als Ziele in Ihrem Code an. Um die Funktion „Navigation Compose“ zu verwenden, Ziele müssen zusammensetzbar sein. Sie können den Status dieser Funktionsanfrage im Issue Tracker verfolgen.

Übergangsanimationen

Ab Navigation 2.7.0-alpha01, Unterstützung für das Festlegen benutzerdefinierter (bisher AnimatedNavHost) werden jetzt direkt in NavHost unterstützt. Weitere Informationen finden Sie in den Versionshinweisen.

Weitere Informationen

Weitere Informationen zur Migration zu Navigation Compose finden Sie in den folgenden Ressourcen:

  • Codelab zu Navigation Compose: In diesem Codelab lernen Sie die Grundlagen von Navigation Compose kennen.
  • Now in Android-Repository: eine voll funktionsfähige Android-App Vollständig mit Kotlin und Jetpack Compose erstellt, das dem Android-Design folgt und Best Practices für die Entwicklung. Dazu gehört „Navigation Compose“.
  • Sunflower zu Jetpack Compose migrieren: In diesem Blogpost wird die Migration der Beispiel-App „Sunflower“ von Views zu Compose dokumentiert, einschließlich der Migration zu Navigation Compose.
  • Jetnews für jeden Bildschirm: In diesem Blogpost wird die Umstrukturierung und Migration des Jetnews-Beispiels beschrieben, um alle Bildschirme mit Jetpack Compose und Navigation Compose zu unterstützen.