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

Interfejs Navigation Compose API umożliwia poruszanie się między komponentami w aplikacji Compose przy użyciu komponentu, infrastruktury i funkcji Jetpack Navigation.

Na tej stronie opisano, jak przejść z fragmentu w Jetpack Compose do nawigacji w Jetpack Compose, co jest częścią większej migracji interfejsu użytkownika opartego na widoku do Jetpack Compose.

Wymagania wstępne migracji

Możesz przejść na komponenty nawigacyjne, gdy zastąpisz wszystkie fragmenty odpowiednimi komponentami ekranu. Komponenty ekranu mogą zawierać mieszankę treści typu Compose i View, ale wszystkie miejsca docelowe nawigacji muszą być komponentami, aby umożliwić migrację komponentu Compose. Do tego czasu w kodzie źródłowym interoperacyjności View i Compose nadal używaj komponentu nawigacji opartej na fragmencie. Więcej informacji znajdziesz w dokumentacji dotyczącej interoperacyjności nawigacji.

Korzystanie z komponentu Nawigacja w aplikacji, która zawiera tylko komponent, nie jest warunkiem wstępnym. Możesz nadal używać komponentu Nawigacja na podstawie fragmentów, o ile zachowasz fragmenty, które przechowują treści do łączenia.

Etapy migracji

Niezależnie od tego, czy stosujesz naszą zalecaną strategię migracji, czy też stosujesz inne podejście, w końcu dojdziesz do punktu, w którym wszystkie elementy nawigacji będą elementami składanymi na ekranie, a fragmenty będą pełnić tylko funkcję składanych kontenerów. Na tym etapie możesz przejść na edycję nawigacji.

Jeśli Twoja aplikacja jest już zgodna z wzorcem projektowania UDF i naszym przewodnikiem po architekturze, przejście na Jetpack Compose i Navigation Compose nie powinno wymagać gruntownego przeprojektowania innych warstw aplikacji (poza warstwą UI).

Aby przejść na kartę Edytowanie w układce Nawigacja:

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

    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żywaj 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 komponent NavController w miejscu, do którego mają dostęp wszystkie komponenty, które muszą do niego odwoływać się (zazwyczaj jest to komponent App). Takie podejście jest zgodne z zasadami podnoszenia stanu i pozwala używać elementu NavController jako źródła informacji o przechodzeniu między składanymi ekranami i zarządzaniu stosem wstecz:

    @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 composable miejsca docelowe, aby utworzyć graf nawigacyjny. Jeśli wszystkie ekrany zostały już przeniesione do usługi Compose, ten krok będzie polegał tylko na wyodrębnieniu tych ekranów z komponentów docelowych w Fragments: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 z instrukcjami dotyczącymi projektowania interfejsu użytkownika Compose, w szczególności dotyczącymi przekazywania zdarzeń ViewModel i nawigacji do komponentów, następnym krokiem jest zmiana sposobu udostępniania ViewModel do każdego komponentu ekranu. Często używasz wstrzyknięcia Hilta i punktu integracji z Compose i Nawigacją 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 przekazuj je jako zdarzenia nawigacji do każdego ekranu kompozytowego zamiast przekazywać cały obiekt navController. To podejście jest zgodne ze sprawdzonymi metodami udostępniania wywołującym zdarzeń z funkcji składanych i utrzymuje navController jako jedyne źródło danych.

    Dane można przekazać do miejsca docelowego, tworząc instancję klasy trasy zdefiniowanej dla tego miejsca. Można go uzyskać bezpośrednio z poziomu wpisu w grupie elementów na docelowym poziomie lub za pomocą funkcji ViewModel (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 elementy nawigacji i inne zasoby oraz nieaktualne zależności od fragmentów i nawigacji Jetpacka.

Te same czynności wraz z dodatkowymi informacjami na temat tworzenia aplikacji znajdziesz w dokumentacji konfiguracji.

Typowe zastosowania

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 zastosowaniach znajdziesz w artykule Przeglądanie za pomocą okna tworzenia.

Pobieranie złożonych danych podczas nawigacji

Stanowczo zalecamy, aby podczas nawigacji nie przekazywać złożonych obiektów danych. Zamiast tego podczas wykonywania działań związanych z nawigacją należy przekazywać jako argumenty minimalne wymagane 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, zastanów się nad zrefaktoryzowaniem kodu w taki sposób, aby umożliwić przechowywanie i pobieranie tych obiektów z warstwy danych. Przykłady znajdziesz w repozytorium Now na Androidzie.

Ograniczenia

Ta sekcja opisuje obecne ograniczenia dotyczące tworzenia trasy.

Przyrostowa migracja do Compose w Nawigacji

Obecnie nie można używać funkcji Navigation Compose, jeśli w kodzie nadal używasz fragmentów jako miejsc docelowych. Aby zacząć korzystać z kompozycji nawigacji, wszystkie miejsca docelowe muszą być kompozycjami. Możesz śledzić to żądanie funkcji w panelu Problem Tracker.

Animacje przejścia

Począwszy od wersji Navigation 2.7.0-alpha01 obsługa ustawiania niestandardowych przejść, która wcześniej była dostępna w AnimatedNavHost, jest teraz obsługiwana bezpośrednio w NavHost. Aby dowiedzieć się więcej, przeczytaj informacje o wersji.

Więcej informacji

Więcej informacji o przechodzeniu na narzędzie do tworzenia mapy znajdziesz w tych materiałach:

  • Ćwiczenie praktyczne z komponentem Nawigacja: poznaj podstawy komponentu Nawigacja za pomocą ćwiczenia praktycznego.
  • W repozytorium Androida: w pełni funkcjonalna aplikacja na Androida, która została w pełni napisana w Kotlinie i Jetpack Compose, zgodnie ze sprawdzonymi metodami projektowania i tworzenia aplikacji na Androida. Zawiera ona też Navigation Compose.
  • Migracja aplikacji Sunflower do Jetpack Compose: wpis na blogu, który opisuje proces migracji przykładowej aplikacji Sunflower z Views do Compose, w tym migrację do Nawigacji Compose.
  • Jetnews na każdym ekranie: post na blogu opisujący refaktoryzację i migrację przykładowej aplikacji Jetnews w celu obsługi wszystkich ekranów za pomocą Jetpack Compose i Navigation Compose.