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

Interfejs Navigation Compose API umożliwia poruszanie się między funkcjami kompozycyjnymi w aplikacji Compose przy jednoczesnym korzystaniu z komponentu, infrastruktury i funkcji Jetpack Navigation.

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

Wymagania wstępne migracji

Możesz przejść na Navigation Compose, gdy zastąpisz wszystkie Fragmenty odpowiednimi komponentami ekranu. Kompozycje ekranu mogą zawierać treści z Compose i View, ale wszystkie miejsca docelowe nawigacji muszą być kompozycjami, aby umożliwić migrację do Navigation Compose. Do tego czasu w kodzie View i Compose, który jest używany w ramach interoperacyjności, należy nadal używać komponentu nawigacji opartej na fragmentach. Więcej informacji znajdziesz w dokumentacji dotyczącej interoperacyjności nawigacji.

Korzystanie z Navigation Compose w aplikacji opartej wyłącznie na Compose nie jest wymagane. Możesz nadal używać komponentu Nawigacja oparta na fragmentach, o ile będziesz używać fragmentów do hostowania treści, które można komponować.

Etapy migracji

Niezależnie od tego, czy korzystasz z naszej zalecanej strategii migracji, czy stosujesz inne podejście, w pewnym momencie wszystkie miejsca docelowe nawigacji będą komponentami ekranu, a fragmenty będą pełnić rolę tylko kontenerów komponentów. Na tym etapie możesz przejść na Navigation Compose.

Jeśli Twoja aplikacja korzysta już z 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 przeprowadzić migrację do Navigation Compose, wykonaj te czynności:

  1. Dodaj do aplikacji zależność Navigation Compose.
  2. Utwórz App-level funkcję kompozycyjną i dodaj ją 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, do którego mają dostęp wszystkie funkcje kompozycyjne, które muszą się do niego odwoływać (zwykle jest to w funkcji kompozycyjnej App). To podejście jest zgodne z zasadami przenoszenia stanu i umożliwia używanie NavController jako źródła informacji do poruszania się między ekranami kompozycyjnymi i utrzymywania stosu wstecznego:

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

  5. Utwórz NavHost aplikacji w kompozycyjnym 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 composable miejsc docelowych:

    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 z wskazówkami dotyczącymi projektowania interfejsu Compose, a zwłaszcza sposobu przekazywania ViewModel i zdarzeń nawigacji do komponentów kompozycyjnych, kolejnym krokiem jest zmiana sposobu dostarczania ViewModel do każdego komponentu kompozycyjnego 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 z kompozycją, zamiast przekazywać całą wartość findNavController().navController To podejście jest zgodne ze sprawdzonymi metodami udostępniania zdarzeń z funkcji kompozycyjnych wywołującym i utrzymuje navController jako jedyne źródło 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 pozycji na liście wstecznej 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 czynności z większą liczbą szczegółów dotyczących Navigation Compose znajdziesz w dokumentacji konfiguracji.

Częste przypadki użycia

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

Typowe przypadki użycia podczas migracji to:

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

Pobieranie złożonych danych podczas nawigacji

Stanowczo odradzamy przekazywanie złożonych obiektów danych podczas nawigacji. Zamiast tego podczas wykonywania działań związanych z nawigacją przekazuj jako argumenty tylko niezbędne informacje, takie jak unikalny identyfikator lub inny identyfikator. Złożone obiekty należy przechowywać jako dane w jednym źródle informacji, 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, najpierw rozważ refaktoryzację kodu w taki sposób, aby można było przechowywać te obiekty w warstwie danych i pobierać je z niej. Przykłady znajdziesz w repozytorium Now in Android.

Ograniczenia

W tej sekcji opisujemy obecne ograniczenia biblioteki Navigation Compose.

Stopniowa migracja do Navigation Compose

Obecnie nie możesz 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 kompozycyjnymi. Możesz śledzić to zgłoszenie funkcji w narzędziu Issue Tracker.

Animacje przejścia

Od wersji Navigation 2.7.0-alpha01 ustawianie niestandardowych przejść, które wcześniej było możliwe w AnimatedNavHost, jest teraz obsługiwane bezpośrednio w NavHost. Więcej informacji znajdziesz w informacjach o wersji.

Więcej informacji

Więcej informacji o przechodzeniu na Navigation Compose znajdziesz w tych materiałach:

  • Ćwiczenie z Navigation Compose: poznaj podstawy Navigation Compose w praktyce.
  • Now in Android repository: w pełni funkcjonalna aplikacja na Androida zbudowana w całości w Kotlinie i Jetpack Compose, która jest zgodna ze sprawdzonymi metodami projektowania i tworzenia aplikacji na Androida oraz zawiera Navigation Compose.
  • Migracja aplikacji Sunflower do Jetpack Compose: post na blogu, w którym opisujemy proces migracji aplikacji Sunflower z widoków do Compose, w tym do Navigation Compose.
  • Jetnews na każdym ekranie: post na blogu, w którym opisujemy refaktoryzację i migrację aplikacji Jetnews, aby obsługiwała wszystkie ekrany za pomocą Jetpack Compose i Navigation Compose.