Cykl życia w Jetpack Compose, część Androida Jetpack.

Komponenty uwzględniające cykl życia wykonują działania w odpowiedzi na zmianę stanu cyklu życia działania hosta. Artefaktandroidx.lifecycle.compose udostępnia dedykowane interfejsy API, które automatycznie zwalniają miejsce, gdy znikają z ekranu lub gdy aplikacja przechodzi w tle.

Najważniejsze interfejsy API to:

Te integracje zapewniają wygodne punkty zaczepienia do zarządzania cyklami życia w hierarchii Compose. Z tego dokumentu dowiesz się, jak możesz ich używać w swojej aplikacji.

Zbieranie stanu cyklu życia za pomocą automatyzacji

Klasa Lifecycle udostępnia właściwość currentStateFlow, która zawiera bieżący stan Lifecycle.State jako obiekt Kotlin StateFlow. Możesz zbierać te Flow jako State. Dzięki temu aplikacja może odczytywać zmiany w cyklu życia podczas tworzenia.

val lifecycleOwner = LocalLifecycleOwner.current
val stateFlow = lifecycleOwner.lifecycle.currentStateFlow

val currentLifecycleState by stateFlow.collectAsState()

Powyższy przykład jest dostępny w module lifecycle-common. Metoda currentStateAsState() jest dostępna w module lifecycle-runtime-compose, który umożliwia wygodne odczytywanie bieżącego stanu cyklu życia za pomocą jednego wiersza. Ilustruje to poniższy przykład:

val lifecycleOwner = LocalLifecycleOwner.current
val currentLifecycleState = lifecycleOwner.lifecycle.currentStateAsState()

Uruchamianie kodu w przypadku zdarzeń cyklu życia

Zamiast tworzyć osobną klasę, która implementuje DefaultLifecycleObserver i ręcznie dodawać ją do cyklu życia, możesz zadeklarować logikę cyklu życia w linii za pomocą określonych efektów. LifecycleEffects umożliwia uruchomienie bloku, gdy w kompozycji wystąpi określone Lifecycle.Event.

LifecycleEventEffect

Użyj LifecycleEventEffect, aby uruchomić blok kodu, gdy wystąpi określone zdarzenie. Jest to najlepsze rozwiązanie w przypadku jednorazowych zdarzeń, takich jak rejestrowanie czy analityka, w których nie jest wymagane powodzenie ani natychmiastowy wynik.

@Composable
fun AnalyticsTracker(screenName: String) {
    // Log an event when the app receives ON_RESUME (e.g. comes to foreground)
    LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
        Analytics.logView(screenName)
    }
}

LifecycleStartEffect

W przypadku sparowanych operacji uruchamiania/zatrzymywania, które muszą być wykonywane, gdy aplikacja jest uruchomiona (widoczna), i zwalniane, gdy aplikacja jest zatrzymana (w tle), użyj LifecycleStartEffect.

Podobnie jak inne efekty Compose (np. LaunchedEffect), LifecycleStartEffect akceptuje klucze. Gdy klucz się zmieni, blok zostanie ponownie uruchomiony.

Gdy nastąpi zdarzenie Lifecycle.Event.ON_STOP lub efekt opuści kompozycję, wykona blok onStopOrDispose, aby zwalniać miejsce, które było częścią bloku początkowego.

@Composable
fun LocationMonitor(locationManager: LocationManager) {
    // Starts monitoring when ON_START is dispatched
    // Stops monitoring when ON_STOP is dispatched
    //   (or the composable leaves the screen)
    LifecycleStartEffect(locationManager) {
        val listener = LocationListener { location ->
            /* update UI */
        }
        locationManager.requestLocationUpdates(listener)
        // The cleanup block automatically runs on ON_STOP or on disposal
        onStopOrDispose {
            locationManager.removeUpdates(listener)
        }
    }
}

Więcej informacji o innych rodzajach efektów ubocznych znajdziesz w artykule Efekty uboczne w Compose.

LifecycleResumeEffect

Funkcja LifecycleResumeEffect działa tak samo jak LifecycleStartEffect, ale jest powiązana ze zdarzeniem Lifecycle.Event.ON_RESUME. Zawiera też blok onPauseOrDispose, który wykonuje czyszczenie, gdy wysyłany jest element ON_PAUSE lub gdy element kompozycyjny znika z ekranu.

Ten interfejs API jest przydatny w przypadku zasobów, które muszą być aktywne tylko wtedy, gdy użytkownik korzysta z aplikacji, np. aparatów lub animacji.

@Composable
fun CameraPreview(cameraController: CameraController) {
    LifecycleResumeEffect(cameraController) {
        cameraController.startPreview()

        onPauseOrDispose {
            cameraController.stopPreview()
        }
    }
}

Dostęp do LifecycleOwner

W Compose element LifecycleOwner jest dostępny niejawnie za pomocą elementu CompositionLocal o nazwie LocalLifecycleOwner. Domyślnie właścicielem jest host główny hierarchii kompozycji.

val lifecycleOwner = LocalLifecycleOwner.current

W przypadku wielu aplikacji wystarczy sprawdzić tego domyślnego właściciela lub przekazać go do efektów uwzględniających cykl życia. W przypadku niestandardowej nawigacji lub złożonych układów możesz jednak utworzyć własny LifecycleOwner, aby ograniczyć stany cyklu życia do określonych sekcji interfejsu. Na przykład biblioteki nawigacyjne (np. Navigation 3) robią to automatycznie, aby każda poszczególna strona miała własny cykl życia.

Tworzenie niestandardowego obiektu LifecycleOwner

Interfejs API rememberLifecycleOwner() umożliwia tworzenie i zapamiętywanie niestandardowychLifecycleOwner. Jest to szczególnie przydatne w przypadku komponentów takich jak HorizontalPager, w których chcesz, aby tylko widoczna, ustabilizowana strona była RESUMED, a sąsiednie strony poza ekranem miały maxState ustawione na STARTED.

val pagerState = rememberPagerState(pageCount = { 10 })

HorizontalPager(state = pagerState) { pageNum ->
    val pageLifecycleOwner = rememberLifecycleOwner(
        maxState = if (pagerState.settledPage == pageNum) {
            Lifecycle.State.RESUMED
        } else {
            Lifecycle.State.STARTED
        }
    )

    CompositionLocalProvider(LocalLifecycleOwner provides pageLifecycleOwner) {
        // Your pages here. Their lifecycle-aware components respect the
        // custom maxState defined above.
    }
}

Więcej informacji o CompositionLocal znajdziesz w artykule Dane o lokalnym zakresie z użyciem CompositionLocal.

Sprawdzone metody dotyczące komponentów uwzględniających cykl życia

  • Staraj się, aby kontrolery interfejsu były jak najprostsze. Nie powinny one próbować pozyskiwać własnych danych. Zamiast tego powinny używać ViewModel, aby to zrobić, i obserwować StateFlow, aby odzwierciedlać zmiany w interfejsie.
  • Staraj się tworzyć interfejsy oparte na danych, w których kontroler interfejsu użytkownika odpowiada za aktualizowanie interfejsu w miarę zmian danych lub powiadamianie ViewModel o działaniach użytkownika.
  • Umieść logikę danych w klasie ViewModel. ViewModel powinien pełnić rolę łącznika między kontrolerem interfejsu a pozostałą częścią aplikacji. Pamiętaj jednak, że pobieranie danych (np. z sieci) nie jest zadaniem ViewModel. Zamiast tego ViewModel powinien wywołać odpowiedni komponent, aby pobrać dane, a następnie przekazać wynik do kontrolera interfejsu.
  • Używaj współprogramów Kotlin do zarządzania długotrwałymi zadaniami i innymi operacjami, które mogą być wykonywane asynchronicznie.
  • Logikę uruchamiania i zatrzymywania umieszczaj w funkcji kompozycyjnej, która jej potrzebuje. Dzięki temu logika jest automatycznie usuwana, jeśli dany element interfejsu zostanie usunięty z ekranu (np. w grafie nawigacji lub gdy widoczność jest warunkowa).
  • Używaj collectAsStateWithLifecycle do przesyłania danych. Nie rozpoczynaj ani nie zatrzymuj ręcznie zbierania danychFlow na podstawie zdarzeń związanych z cyklem życia. Zamiast tego użyj collectAsStateWithLifecycle, aby wydajnie przekształcać strumienie w stan interfejsu. Pozwala to oszczędzać baterię i zasoby, ponieważ Flow są wstrzymywane, gdy aplikacja działa w tle.

Więcej informacji o Flow znajdziesz w sekcji Inne obsługiwane typy stanu.

Przypadki użycia komponentów uwzględniających cykl życia

Komponenty uwzględniające cykl życia mogą znacznie ułatwić zarządzanie cyklami życia w różnych przypadkach. Oto kilka przykładów:

  • Przełączanie się między przybliżonymi a dokładnymi aktualizacjami lokalizacji. Użyj LifecycleStartEffect, aby włączyć szczegółowe aktualizacje lokalizacji, gdy aplikacja jest widoczna (ON_START), i automatycznie wyczyścić odbiornik lub przełączyć się na przybliżone aktualizacje, gdy aplikacja działa w tle (ON_STOP).
  • wstrzymywanie i wznawianie buforowania filmu; Używaj LifecycleResumeEffect, aby odłożyć odtwarzanie filmu do momentu, gdy aplikacja będzie w pełni widoczna i interaktywna (ON_RESUME), oraz aby mieć pewność, że odtwarzanie zostanie wstrzymane, a zasoby zwolnione, gdy aplikacja będzie działać w tle (ON_PAUSE).
  • rozpoczynanie i zatrzymywanie transmisji sieciowej; Użyj collectAsStateWithLifecycle, aby obserwować ciągłe strumienie danych (np. Kotlin Flow z gniazda sieciowego). Dzięki temu możesz na bieżąco aktualizować dane, gdy aplikacja jest na pierwszym planie, i automatycznie anulować zbieranie danych, gdy aplikacja przechodzi w tło.
  • wstrzymywanie i wznawianie wymagających zadań; Używaj LifecycleResumeEffect, aby wstrzymywać intensywne aktualizacje wizualne, gdy aplikacja działa w tle, i wznawiać je, gdy aplikacja działa na pierwszym planie.

Bezpieczna obsługa zdarzeń ON_STOP

Funkcja Pisanie została zaprojektowana tak, aby bezpiecznie obsługiwać zdarzenia ON_STOP.

  • Stan jest bezpieczny: możesz w każdej chwili zaktualizować MutableState (np. za pomocą uiState.value = ...), nawet gdy aplikacja działa w tle. Compose czeka, aż aplikacja będzie widoczna, aby wyrenderować zmiany.
  • Automatyczne czyszczenie: w przypadku efektów takich jak LifecycleStartEffect blok czyszczenia (onStopOrDispose) jest uruchamiany dokładnie wtedy, gdy cykl życia przechodzi do stanu STOPPED. Zapobiega to wykorzystywaniu przez aplikację w tle zasobów o dużej mocy obliczeniowej (takich jak aparat czy lokalizacja).

Więcej informacji o MutableState znajdziesz w artykule Stan i Jetpack Compose.

Dodatkowe materiały

Więcej informacji o obsłudze cykli życia za pomocą komponentów uwzględniających cykl życia znajdziesz w tych materiałach.

Wyświetlanie treści