Jetpack Navigation zu Navigation Compose migrieren

Mit der Navigation Compose API können Sie in einer Composer-Anwendung zwischen zusammensetzbaren Funktionen wechseln und dabei die Komponente, die Infrastruktur und die Features von Jetpack Navigation nutzen.

Auf dieser Seite wird beschrieben, wie Sie von einer fragmentierten Jetpack-Navigation zu Navigation Compose im Rahmen der größeren, ansichtsbasierten UI-Migration zu Jetpack Composer migrieren.

Voraussetzungen für die Migration

Sie können zu „Navigation Compose“ migrieren, sobald Sie alle Fragmente durch entsprechende zusammensetzbare Bildschirmfunktionen ersetzen konnten. Zusammensetzbare Funktionen für Bildschirme können eine Mischung aus „Inhalt erstellen“ und „Inhalt ansehen“ enthalten. Alle Navigationsziele müssen jedoch zusammensetzbar sein, damit die Migration von „Navigationskomposition“ aktiviert werden kann. Bis dahin sollten Sie die Komponente „Fragmentbasierte Navigation“ weiterhin in der Interoperabilitätscodebasis „View and Composer“ verwenden. Weitere Informationen finden Sie in der Dokumentation zu Navigations-Interop.

Die Verwendung der Funktion „Navigation Compose“ in einer reinen Schreibanwendung ist keine Voraussetzung. Sie können die Fragmentbasierte Navigationskomponente weiterhin verwenden, solange Sie Fragmente zum Hosten Ihrer zusammensetzbaren Inhalte aufbewahren.

Migrationsschritte

Unabhängig davon, ob Sie unserer empfohlenen Migrationsstrategie folgen oder einen anderen Ansatz wählen, kommen Sie an einen Punkt, an dem alle Navigationsziele zusammensetzbare Bildschirme sind und Fragmente nur als zusammensetzbare Container fungieren. In dieser Phase können Sie zu „Navigation Compose“ migrieren.

Wenn Ihre Anwendung bereits einem UDF-Designmuster und unserem Leitfaden zur Architektur folgt, sollte die Migration zu Jetpack Compose und Navigation Compose keine größeren Refaktorierungen anderer Ebenen Ihrer Anwendung erfordern, 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 dem Activity als Einstiegspunkt zum Schreiben hinzu. Dadurch wird die Einrichtung des Layouts „View“ ersetzt:

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

  3. Platzieren Sie NavController an einem Ort, an dem alle zusammensetzbaren Funktionen, die darauf verweisen müssen, Zugriff darauf haben. Das befindet sich normalerweise innerhalb der zusammensetzbaren Datei App. Dieser Ansatz folgt den Prinzipien des Zustandshebens und ermöglicht es Ihnen, NavController als Datenquelle für die Navigation zwischen zusammensetzbaren Bildschirmen und die Wartung des Back-Stacks zu verwenden:

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

  4. Erstellen Sie das NavHost Ihrer App in der zusammensetzbaren App und übergeben Sie navController:

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

  5. Fügen Sie die composable-Ziele hinzu, um die Navigationsgrafik zu erstellen. Wenn jeder Bildschirm zuvor zu „Schreiben“ migriert wurde, besteht dieser Schritt nur darin, diese zusammensetzbaren Funktionen aus Ihren Fragmenten in die composable-Ziele zu extrahieren:

    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(/* ... */)
            }
            // ...
        }
    }

  6. Wenn Sie der Anleitung unter UI zum Erstellen von Texten gefolgt sind und vor allem festgelegt haben, wie ViewModels und Navigationsereignisse an zusammensetzbare Funktionen übergeben werden sollen, müssen Sie im nächsten Schritt ändern, wie Sie das ViewModel für jede zusammensetzbare Bildschirmanzeige angeben. Du kannst die Hilt-Einschleusung und den entsprechenden Integrationspunkt häufig über hiltViewModel mit „Compose and Navigation“ verwenden:

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

  7. Ersetzen Sie alle findNavController()-Navigationsaufrufe durch die navController und übergeben Sie diese als Navigationsereignisse an jeden zusammensetzbaren Bildschirm, anstatt den gesamten navController zu übergeben. Dieser Ansatz entspricht den Best Practices für die Bereitstellung von Ereignissen aus zusammensetzbaren Funktionen für Aufrufer und verwendet die navController als Single Source of Truth.

    1. Wenn Sie zuvor das Safe Args-Plug-in zum Generieren von Wegbeschreibungen und Aktionen verwendet haben, ersetzen Sie es durch eine route – einen Stringpfad zu Ihrer zusammensetzbaren Funktion, der für jedes Ziel eindeutig ist.
    2. Informationen zum Ersetzen von sicheren Argumenten beim Übergeben von Daten finden Sie unter Mit Argumenten navigieren.
    3. Informationen zur Typsicherheit in Navigation Compose finden Sie im Abschnitt Sichere Argumente unten.

      @Composable
      fun SampleNavHost(
          navController: NavHostController
      ) {
          NavHost(navController = navController, startDestination = "first") {
              composable("first") {
                  FirstScreen(
                      onButtonClick = {
                          // findNavController().navigate(firstScreenToSecondScreenAction)
                          navController.navigate("second_screen_route")
                      }
                  )
              }
              composable("second") {
                  SecondScreen(
                      onIconClick = {
                          // findNavController().navigate(secondScreenToThirdScreenAction)
                          navController.navigate("third_screen_route")
                      }
                  )
              }
              // ...
          }
      }

  8. Entfernen Sie alle Fragmente, relevante XML-Layouts, unnötige Navigationselemente und andere Ressourcen sowie veraltete Fragment- und Jetpack Navigation-Abhängigkeiten.

Dieselben Schritte finden Sie in der Dokumentation zur Einrichtung unter „Navigation Compose“.

Gängige Anwendungsfälle

Unabhängig davon, welche Navigationskomponente Sie verwenden, gelten die gleichen Prinzipien der Navigation.

Häufige Anwendungsfälle bei der Migration:

Weitere Informationen zu diesen Anwendungsfällen finden Sie unter Mit dem Editor navigieren.

Safe Args

Im Gegensatz zu Jetpack Navigation unterstützt Navigation Compose nicht die Verwendung des Safe Args-Plug-ins zur Codegenerierung. Stattdessen können Sie Typsicherheit mit Navigation Compose erreichen, indem Sie Ihren Code so strukturieren, dass er zur Laufzeit typsicher ist.

Komplexe Daten beim Navigieren abrufen

Die Funktion „Navigation Compose“ ist routenbasiert auf String-Basis und unterstützt im Gegensatz zu Jetpack Navigation nicht die Übergabe benutzerdefinierter Parcelables und Serializables als Argumente.

Wir raten dringend davon ab, bei der Navigation komplexe Datenobjekte zu übergeben. Übergeben Sie stattdessen bei Navigationsaktionen die mindestens erforderlichen Informationen, z. B. eine eindeutige Kennung oder eine andere Art von ID, als Argumente. Komplexe Objekte sollten als Daten in einer einzigen Datenquelle gespeichert werden, z. B. in der Datenschicht. Weitere Informationen finden Sie unter Komplexe Daten während der Navigation abrufen.

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

Einschrä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 weiterhin Fragmente als Ziele in Ihrem Code nutzen. Damit Sie „Navigation Compose“ verwenden können, müssen alle Ziele zusammensetzbar sein. Sie können die Funktionsanfrage in der Problemverfolgung einsehen.

Übergangsanimationen

Ab Navigation 2.7.0-alpha01 wird das Festlegen benutzerdefinierter Übergänge (früher über AnimatedNavHost) 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 „Navigation Compose“: In diesem praxisorientierten Codelab lernen Sie die Grundlagen von „Navigation Compose“.
  • Jetzt im Android-Repository: Eine voll funktionsfähige Android-App, die vollständig mit Kotlin und Jetpack Compose erstellt wurde. Die App entspricht den Best Practices für Design und Entwicklung von Android und beinhaltet Navigation Compose.
  • Sunflower zu Jetpack Compose migrieren: In diesem Blogpost wird die Migration der Sunflower-Beispielanwendung von Views zu Composer dokumentiert. Dazu gehört auch die Migration zu Navigation Compose.
  • Jetnews for Everyscreen: Ein Blogpost, der die Refaktorierung und Migration des Jetnews-Beispiels dokumentiert, um alle Bildschirme mit Jetpack Compose und Navigation Compose zu unterstützen.