Przenieś nawigację Jetpack do tworzenia wiadomości w Nawigacji

Interfejs Navigation Compose API umożliwia poruszanie się między elementami kompozytowymi w aplikacji Compose, wykorzystując komponent, infrastrukturę i funkcje Jetpack Navigation.

Na tej stronie opisujemy, jak przejść z nawigacji Jetpack opartej na fragmentach na Navigation Compose w ramach większej migracji interfejsu opartego na widokach do Jetpack Compose.

Wymagania wstępne migracji

Możesz przejść na Navigation Compose, gdy będziesz w stanie zastąpić wszystkie fragmenty odpowiednimi komponentami ekranu. Komponenty ekranu mogą zawierać połączenie treści Compose i View, ale wszystkie miejsca docelowe nawigacji muszą być komponentami, aby umożliwić migrację do Navigation Compose. Do tego czasu nadal używaj komponentu nawigacji opartego na fragmentach w bazie kodu widoku i Compose. Więcej informacji znajdziesz w dokumentacji dotyczącej współdziałania nawigacji.

Kroki migracji

Niezależnie od tego, czy stosujesz naszą zalecaną strategię migracji, czy inne podejście, dojdziesz do momentu, w którym wszystkie miejsca docelowe nawigacji będą funkcjami kompozycyjnymi ekranu, a fragmenty będą działać tylko jako kontenery funkcji kompozycyjnych. Na tym etapie możesz przejść na Navigation Compose.

Jeśli Twoja aplikacja korzysta już ze wzorca projektowego UDF i naszego przewodnika po architekturze, migracja do Jetpack Compose i Navigation Compose nie powinna wymagać większych zmian w innych warstwach aplikacji poza warstwą interfejsu.

Aby przejść na Navigation Compose, wykonaj te czynności:

  1. Dodaj do aplikacji zależność Navigation Compose.
  2. Utwórz komponent App-level i dodaj go do Activity jako punkt wejścia do Compose, zastępując konfigurację układu View:

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

  3. Utwórz typy dla każdego miejsca docelowego nawigacji. Użyj data object w przypadku miejsc docelowych, które nie wymagają żadnych danych, oraz data class lub class w przypadku miejsc docelowych, które wymagają danych.

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

  4. Skonfiguruj NavController w miejscu, w którym wszystkie elementy kompozycyjne, które muszą się do niego odwoływać, mają do niego dostęp (zwykle jest to element kompozycyjny App). To podejście jest zgodne z zasadami przenoszenia stanu i pozwala używać NavController jako źródła informacji do nawigacji między ekranami funkcji kompozycyjnych i utrzymywania stosu wstecznego:

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

  5. Utwórz NavHost aplikacji w funkcji kompozycyjnej App i przekaż navController:

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

  6. Dodaj miejsca docelowe composable, aby utworzyć wykres nawigacji. Jeśli każdy ekran został wcześniej przeniesiony do Compose, ten krok polega tylko na wyodrębnieniu tych funkcji kompozycyjnych ekranu z fragmentów do miejsc docelowych composable:

    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. Jeśli postępujesz zgodnie ze wskazówkami dotyczącymi projektowania interfejsu Compose, a w szczególności z informacjami o tym, jak przekazywać ViewModel i zdarzenia nawigacji do komponentów, kolejnym krokiem jest zmiana sposobu przekazywania ViewModel do każdego komponentu ekranu. Wstrzykiwania Hilt i jego punktu integracji z Compose i Navigation możesz często używać za pomocą hiltViewModel:

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

  8. Zastąp wszystkie wywołania nawigacji findNavController() wywołaniami navController i przekaż je jako zdarzenia nawigacji do każdego ekranu kompozycyjnego, zamiast przekazywać cały navController. To podejście jest zgodne ze sprawdzonymi metodami udostępniania zdarzeń z funkcji typu „composable” elementom wywołującym i utrzymuje navController jako jedno źródło wiarygodnych danych.

    Dane można przekazywać do miejsca docelowego, tworząc instancję klasy trasy zdefiniowanej dla tego miejsca docelowego. Można go następnie uzyskać bezpośrednio z wpisu na stosie wstecznym w miejscu docelowym lub z ViewModel za pomocą 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. Usuń wszystkie fragmenty, odpowiednie układy XML, niepotrzebną nawigację i inne zasoby oraz nieaktualne zależności fragmentów i nawigacji Jetpack.

Te same kroki z dodatkowymi informacjami dotyczącymi Navigation Compose znajdziesz w dokumentacji konfiguracji.

Częste przypadki użycia

Niezależnie od tego, którego komponentu nawigacji używasz, obowiązują te same zasady nawigacji.

Typowe przypadki użycia podczas migracji:

Więcej informacji o tych przypadkach użycia znajdziesz w artykule Nawigacja za pomocą Compose.

pobieranie złożonych danych podczas nawigacji,

Zdecydowanie odradzamy przekazywanie złożonych obiektów danych podczas nawigacji. Zamiast tego podczas wykonywania działań związanych z nawigacją przekazuj jako argumenty minimalne niezbędne informacje, takie jak unikalny identyfikator lub inną formę identyfikatora. Złożone obiekty należy przechowywać jako dane w jednym źródle wiarygodnych danych, np. w warstwie danych. Więcej informacji znajdziesz w artykule Pobieranie złożonych danych podczas nawigacji.

Jeśli fragmenty przekazują złożone obiekty jako argumenty, rozważ najpierw refaktoryzację kodu w sposób, który umożliwia przechowywanie i pobieranie tych obiektów z warstwy danych. Przykłady znajdziesz w repozytorium Now in Android.

Ograniczenia

W tej sekcji opisano obecne ograniczenia dotyczące Navigation Compose.

Stopniowa migracja do Navigation Compose

Obecnie nie można używać Navigation Compose, jeśli w kodzie nadal używasz fragmentów jako miejsc docelowych. Aby zacząć korzystać z Navigation Compose, wszystkie miejsca docelowe muszą być funkcjami kompozytowymi. Możesz śledzić tę prośbę o dodanie funkcji w narzędziu Issue Tracker.

Animacje przejścia

Od wersji Navigation 2.7.0-alpha01 obsługa ustawiania niestandardowych przejść, wcześniej dostępna w AnimatedNavHost, jest teraz bezpośrednio obsługiwana w NavHost. Więcej informacji znajdziesz w informacjach o wersji.

Więcej informacji

Więcej informacji o migracji do Navigation Compose znajdziesz w tych materiałach:

  • Ćwiczenie z programowania dotyczące Navigation Compose: poznaj podstawy Navigation Compose dzięki praktycznemu ćwiczeniu z programowania.
  • Repozytorium Now in Android: w pełni funkcjonalna aplikacja na Androida zbudowana w całości w Kotlinie i Jetpack Compose, która jest zgodna z najlepszymi praktykami projektowania i tworzenia aplikacji na Androida oraz zawiera Navigation Compose.
  • Migracja Sunflower do Jetpack Compose: post na blogu, który dokumentuje proces migracji przykładowej aplikacji Sunflower z widoków do Compose, w tym migrację do Navigation Compose.
  • Jetnews na każdy ekran: post na blogu, który dokumentuje refaktoryzację i migrację przykładowej aplikacji Jetnews, aby obsługiwała wszystkie ekrany za pomocą Jetpack Compose i Navigation Compose.