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

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

Z tej strony dowiesz się, jak przeprowadzić migrację z Jetpack Navigation opartego na fragmentach do Navigation Compose w ramach większej migracji interfejsu opartego na widokach do Jetpack Compose.

Wymagania wstępne migracji

Migrację do Navigation Compose możesz przeprowadzić, gdy zastąpisz wszystkie fragmenty odpowiednimi komponentami ekranu. Komponenty ekranu mogą zawierać treści Compose i View, ale wszystkie miejsca docelowe nawigacji muszą być komponentami, aby umożliwić migrację do Navigation Compose. Do tego czasu w kodzie View i Compose należy nadal używać komponentu Navigation opartego na fragmentach. Więcej informacji znajdziesz w dokumentacji dotyczącej interoperacyjności nawigacji for more information.

Kroki migracji

Niezależnie od tego, czy stosujesz naszą zalecaną strategię migracji, czy inne podejście, w pewnym momencie wszystkie miejsca docelowe nawigacji będą funkcjami kompozycyjnymi ekranu, a fragmenty będą pełnić tylko rolę kontenerów funkcji kompozycyjnych. Na tym etapie możesz przeprowadzić migrację do 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 przeprowadzić migrację do Navigation Compose:

  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. W przypadku miejsc docelowych, które nie wymagają żadnych danych, użyj data object, a w przypadku miejsc docelowych, które wymagają danych, użyj data class lub class.

    @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 komponenty, które muszą się do niego odwoływać (zwykle jest to w komponencie App ). To podejście jest zgodne z zasadami przenoszenia stanu i umożliwia używanie NavController jako źródła informacji o poruszaniu się między ekranami komponentów i utrzymywaniu stosu wstecznego:

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

  5. Utwórz NavHost aplikacji w komponencie 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 funkcji kompozycyjnej, zamiast przekazywać cały navController. To podejście jest zgodne z najlepszymi praktykami dotyczącymi udostępniania zdarzeń z funkcji kompozycyjnych do wywołujących i utrzymuje navController jako jedyne źródło informacji.

    Dane można przekazywać do miejsca docelowego, tworząc instancję klasy trasy zdefiniowanej dla tego miejsca docelowego. Można je następnie pobrać bezpośrednio z wpisu w 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, niepotrzebne nawigacje i inne zasoby oraz nieaktualne zależności fragmentów i Jetpack Navigation.

Te same kroki i więcej szczegółów związanych z Navigation Compose znajdziesz w dokumentacji konfiguracji.

Częste zastosowania

Niezależnie od tego, którego komponentu Navigation 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 Nawigowanie za pomocą Compose.

Pobieranie złożonych danych podczas nawigacji

Zdecydowanie zalecamy, aby podczas nawigacji nie przekazywać złożonych obiektów danych. Zamiast tego podczas wykonywania działań nawigacyjnych przekazuj jako argumenty minimalne niezbędne informacje, takie jak unikalny identyfikator lub inna forma identyfikatora. 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 umożliwić przechowywanie i pobieranie tych obiektów z warstwy danych. Przykłady znajdziesz w repozytorium Now in Android for.

Ograniczenia

W tej sekcji opisujemy aktualne ograniczenia Navigation Compose.

Stopniowa migracja do Navigation Compose

Obecnie nie możesz używać Navigation Compose, jeśli nadal używasz fragmentów jako miejsc docelowych w kodzie. Aby zacząć korzystać z Navigation Compose, wszystkie miejsca docelowe muszą być komponentami. Prośbę o dodanie tej funkcji możesz śledzić 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 obsługiwana bezpośrednio 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 Navigation Compose: poznaj podstawy Navigation Compose w praktycznym ćwiczeniu.
  • 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 opisuje proces migracji przykładowej aplikacji Sunflower z widoków do Compose, w tym migrację do Navigation Compose.
  • Jetnews na każdym ekranie: post na blogu, który opisuje refaktoryzację i migrację przykładu Jetnews, aby obsługiwał wszystkie ekrany za pomocą Jetpack Compose i Navigation Compose.