Gdy użytkownik przechodzi między ekranami w aplikacji, opuszcza ją i do niej wraca, instancje Activity
w aplikacji przechodzą przez różne stany w swoim cyklu życia.
Klasa Activity udostępnia wiele wywołań zwrotnych, które informują aktywność o zmianie stanu lub o tym, że system tworzy, zatrzymuje lub wznawia aktywność albo niszczy proces, w którym się ona znajduje.
W metodach wywołania zwrotnego cyklu życia możesz zadeklarować, jak Twoja aktywność ma się zachowywać, gdy użytkownik opuści ją i do niej wróci. Jeśli na przykład tworzysz odtwarzacz strumieniowy, możesz wstrzymać odtwarzanie filmu i zakończyć połączenie sieciowe, gdy użytkownik przełączy się na inną aplikację. Gdy użytkownik wróci, możesz ponownie połączyć się z siecią i umożliwić mu wznowienie odtwarzania filmu w tym samym miejscu.
Każde wywołanie zwrotne umożliwia wykonanie określonej pracy odpowiedniej do danego stanu. Wykonywanie odpowiednich działań we właściwym czasie i prawidłowe obsługiwanie przejść sprawiają, że aplikacja jest bardziej niezawodna i wydajna. Na przykład prawidłowe wdrożenie wywołań zwrotnych cyklu życia może pomóc aplikacji uniknąć tych problemów:
- zawieszać się, gdy użytkownik odbiera połączenie telefoniczne lub przełącza się na inną aplikację podczas korzystania z Twojej aplikacji;
- Zużywanie cennych zasobów systemowych, gdy użytkownik nie korzysta aktywnie z urządzenia.
- Utrata postępów użytkownika, jeśli opuści on aplikację i wróci do niej później.
- Aplikacja ulega awarii lub użytkownik traci postępy, gdy ekran obraca się między orientacją poziomą a pionową.
W tym dokumencie szczegółowo opisujemy cykl życia aktywności. Dokument zaczyna się od opisu paradygmatu cyklu życia. Następnie wyjaśniamy, co dzieje się w przypadku każdego wywołania zwrotnego, co musisz w jego ramach wdrożyć i jakie są jego wewnętrzne mechanizmy.
Następnie krótko opisuje związek między stanem działania a podatnością procesu na zamknięcie przez system. Na koniec omówimy kilka tematów związanych z przejściami między stanami aktywności.
Więcej informacji o zarządzaniu cyklami życia, w tym wskazówki dotyczące sprawdzonych metod, znajdziesz w artykułach Cykl życia w Jetpack Compose i Zapisywanie stanów interfejsu. Aby dowiedzieć się, jak zaprojektować niezawodną aplikację o jakości produkcyjnej, która korzysta z aktywności w połączeniu z komponentami architektury, przeczytaj Przewodnik po architekturze aplikacji.
Pojęcia związane z cyklem życia działania
Aby poruszać się między stanami cyklu życia aktywności, klasa Activity udostępnia podstawowy zestaw 6 wywołań zwrotnych: onCreate, onStart, onResume, onPause, onStop i onDestroy. System wywołuje każdą z tych funkcji zwrotnych, gdy aktywność przechodzi w nowy stan.
Rysunek 1 przedstawia wizualizację tego paradygmatu.
Gdy użytkownik zaczyna opuszczać aktywność, system wywołuje metody, aby ją zamknąć. W niektórych przypadkach działanie jest tylko częściowo zamykane i nadal znajduje się w pamięci, np. gdy użytkownik przełącza się na inną aplikację. W takich przypadkach działanie może nadal powrócić na pierwszy plan.
Jeśli użytkownik wróci do działania, zostanie ono wznowione w miejscu, w którym zostało przerwane. Z kilkoma wyjątkami aplikacje nie mogą rozpoczynać działań, gdy są uruchomione w tle.
Prawdopodobieństwo, że system zakończy dany proces wraz z aktywnościami w nim zawartymi, zależy od stanu aktywności w danym momencie. Więcej informacji o zależności między stanem działania a podatnością na usunięcie znajdziesz w sekcji Stan działania i usuwanie z pamięci.
W zależności od złożoności aktywności prawdopodobnie nie musisz implementować wszystkich metod cyklu życia. Warto jednak poznać każdą z nich i wdrożyć te, które sprawią, że aplikacja będzie działać zgodnie z oczekiwaniami użytkowników.
Compose i cykl życia
W funkcji Compose unikaj umieszczania logiki biznesowej lub ręcznej konfiguracji obserwatora bezpośrednio w wywołaniach zwrotnych aktywności, takich jak onStart lub onResume. Zamiast tego używaj efektów uwzględniających cykl życia i obserwatorów uwzględniających stan, które automatycznie dostosowują się do obecności interfejsu na ekranie.
- Kolekcja uwzględniająca cykl życia: użyj
collectAsStateWithLifecycle, aby korzystać z przepływów zViewModel. Ten interfejs API automatycznie rozpoczyna zbieranie danych, gdy interfejs użytkownika przechodzi w stan Started (Uruchomiony), i przestaje to robić, gdy przechodzi w stan background (w tle), co zapobiega niepotrzebnemu zużyciu zasobów. Po zebraniu przepływu jako stanu możesz użyćLifecycleEffects, aby uruchomić kod, gdy wystąpi zdarzenie cyklu życia. - Przebieg logiki: dzięki tym interfejsom API interfejs użytkownika reaguje na stan cyklu życia w naturalny sposób za pomocą drzewa kompozycji, co zapewnia, że logika biznesowa jest wykonywana tylko wtedy, gdy użytkownik aktywnie wchodzi w interakcję z komponentem.
Więcej informacji o Compose i cyklu życia znajdziesz w artykule Cykl życia w Jetpack Compose.
Wywołania zwrotne cyklu życia
Ta sekcja zawiera informacje koncepcyjne i wdrożeniowe dotyczące metod wywołania zwrotnego używanych w cyklu życia aktywności.
Niektóre działania należą do metod cyklu życia aktywności. Umieść jednak kod, który implementuje działania komponentu zależnego, w komponencie, a nie w metodzie cyklu życia działania. Aby to osiągnąć, musisz sprawić, że komponent zależny będzie uwzględniać cykl życia. Aby dowiedzieć się, jak sprawić, by komponenty zależne były uwzględniały cykl życia, przeczytaj artykuł Cykl życia w Jetpack Compose.
onCreate
Musisz zaimplementować to wywołanie zwrotne, które jest wywoływane, gdy system po raz pierwszy tworzy aktywność. Po utworzeniu aktywność przechodzi w stan Utworzono. W metodzie onCreate wykonaj podstawową logikę uruchamiania aplikacji, która jest wykonywana tylko raz w całym cyklu życia aktywności.
Na przykład implementacja onCreate może wiązać dane z listami, przypisywać aktywność do ViewModel i tworzyć instancje niektórych zmiennych w zakresie klasy. Ta metoda otrzymuje parametr savedInstanceState, który jest obiektem Bundle zawierającym wcześniej zapisany stan aktywności. Jeśli aktywność nigdy wcześniej nie istniała, wartość Bundle
obiektu to null.
Jeśli masz komponent uwzględniający cykl życia, który jest powiązany z cyklem życia aktywności, otrzymuje on zdarzenie ON_CREATE. Metoda oznaczona adnotacją @OnLifecycleEvent jest wywoływana, aby komponent uwzględniający cykl życia mógł wykonać kod konfiguracji potrzebny w stanie utworzonym.
Poniższy przykład pokazuje, jak zintegrować komponent Text z aktywnością o minimalnym zakresie:
class ExampleActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { // In here, we can call composables! MaterialTheme { Greeting(name = "compose") } } } } @Composable fun Greeting(name: String) { Text(text = "Hello $name!") }
Aktywność nie pozostaje w stanie Utworzono. Po zakończeniu wykonywania metody onCreate aktywność przechodzi w stan Started, a system wywołuje kolejno metody onStart i onResume.
onStart
Gdy aktywność przejdzie w stan Started (Rozpoczęto), system wywoła funkcję onStart.
To wywołanie sprawia, że aktywność jest widoczna dla użytkownika, gdy aplikacja przygotowuje się do przejścia aktywności na pierwszy plan i umożliwienia interakcji z nią. Na przykład w tej metodzie inicjowany jest kod, który obsługuje interfejs.
Gdy aktywność przejdzie w stan Started, każdy komponent uwzględniający cykl życia powiązany z cyklem życia aktywności otrzyma zdarzenie ON_START.
Metoda onStart kończy się szybko i podobnie jak w przypadku stanu Created aktywność nie pozostaje w stanie Started. Po zakończeniu tego wywołania zwrotnego aktywność przechodzi w stan Resumed, a system wywołuje metodę onResume.
onResume
Gdy aktywność przechodzi w stan wznowienia, pojawia się na pierwszym planie, a system wywołuje wywołanie zwrotne onResume. Jest to stan, w którym aplikacja wchodzi w interakcję z użytkownikiem. Aplikacja pozostaje w tym stanie, dopóki coś nie odwróci uwagi od aplikacji, np. gdy urządzenie odbierze połączenie telefoniczne, użytkownik przejdzie do innej aktywności lub ekran urządzenia się wyłączy.
Gdy aktywność przejdzie w stan wznowienia, każdy komponent powiązany z cyklem życia aktywności otrzyma zdarzenie ON_RESUME. W tym miejscu komponenty cyklu życia mogą włączać dowolne funkcje, które muszą działać, gdy komponent jest widoczny i na pierwszym planie, np. uruchamiać podgląd z kamery.
Gdy wystąpi zdarzenie przerywające, aktywność przechodzi w stan Wstrzymana, a system wywołuje wywołanie zwrotne onPause.
Jeśli aktywność powróci do stanu wznowienia ze stanu wstrzymania, system ponownie wywoła metodę onResume. Z tego powodu zaimplementuj metodę onResume, aby zainicjować komponenty zwalniane podczas wywołania metody onPause i wykonać inne inicjowanie, które musi nastąpić za każdym razem, gdy aktywność przechodzi w stan wznowienia.
Oto przykład komponentu uwzględniającego cykl życia, który uzyskuje dostęp do kamery, gdy otrzyma zdarzenie ON_RESUME:
class CameraComponent : LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun initializeCamera() {
if (camera == null) {
getCamera()
}
}
...
}
Powyższy kod inicjuje kamerę, gdy LifecycleObserver otrzyma zdarzenie ON_RESUME. W trybie wielu okien Twoja aktywność może być jednak w pełni widoczna nawet wtedy, gdy jest wstrzymana. Na przykład gdy aplikacja jest w trybie wielu okien, a użytkownik kliknie okno, które nie zawiera Twojej aktywności, przechodzi ona w stan wstrzymania.
Jeśli chcesz, aby kamera była aktywna tylko wtedy, gdy aplikacja jest wznawiana (widoczna i aktywna na pierwszym planie), zainicjuj ją po zdarzeniu ON_RESUME, które zostało opisane wcześniej. Jeśli chcesz, aby kamera była aktywna, gdy aktywność jest wstrzymana, ale widoczna, np. w trybie wielu okien, zainicjuj kamerę po zdarzeniu ON_START.
Jednak włączenie kamery, gdy aktywność jest wstrzymana, może uniemożliwić dostęp do kamery innej wznowionej aplikacji w trybie wielu okien. Czasami konieczne jest utrzymanie aktywności kamery, gdy aktywność jest wstrzymana, ale może to pogorszyć ogólne wrażenia użytkownika.
Z tego powodu dokładnie przemyśl, w którym momencie cyklu życia najbardziej odpowiednie jest przejęcie kontroli nad udostępnionymi zasobami systemowymi w kontekście trybu wielu okien. Więcej informacji o obsłudze trybu wielu okien znajdziesz w artykule Obsługa trybu wielu okien.
Niezależnie od tego, w którym zdarzeniu przygotowawczym wykonasz operację inicjowania, pamiętaj, aby użyć odpowiedniego zdarzenia cyklu życia do zwolnienia zasobu. Jeśli zainicjujesz coś po zdarzeniu ON_START, zwolnij lub zakończ to po zdarzeniu ON_STOP. Jeśli inicjujesz po zdarzeniu ON_RESUME, zwolnij po zdarzeniu ON_PAUSE.
Powyższy fragment kodu umieszcza kod inicjowania kamery w komponencie uwzględniającym cykl życia. Zamiast tego możesz umieścić ten kod bezpośrednio w wywołaniach zwrotnych cyklu życia działania, takich jak onStart i onStop, ale nie zalecamy tego. Dodanie tej logiki do niezależnego komponentu uwzględniającego cykl życia umożliwia ponowne użycie komponentu w wielu aktywnościach bez konieczności duplikowania kodu. Aby dowiedzieć się, jak utworzyć komponent uwzględniający cykl życia, zapoznaj się z artykułem Cykl życia w Jetpack Compose.
onPause
System wywołuje tę metodę jako pierwszy sygnał, że użytkownik opuszcza aktywność, chociaż nie zawsze oznacza to, że aktywność jest niszczona. Oznacza to, że aktywność nie jest już na pierwszym planie, ale nadal jest widoczna, jeśli użytkownik korzysta z trybu wielu okien. Aktywność może przejść w ten stan z kilku powodów:
- Zdarzenie, które przerywa działanie aplikacji, zgodnie z opisem w sekcji dotyczącej wywołania zwrotnego
onResume, wstrzymuje bieżącą aktywność. To najczęstszy przypadek. - W trybie wielu okien tylko jedna aplikacja jest aktywna, a system wstrzymuje wszystkie pozostałe.
- Otwarcie nowej, półprzezroczystej aktywności, np. okna dialogowego, wstrzymuje aktywność, którą zasłania. Dopóki aktywność jest częściowo widoczna, ale nie jest aktywna, pozostaje wstrzymana.
Gdy aktywność przechodzi w stan Wstrzymana, każdy komponent powiązany z cyklem życia aktywności otrzymuje zdarzenie ON_PAUSE. W tym miejscu komponenty cyklu życia mogą zatrzymać każdą funkcję, która nie musi działać, gdy komponent nie jest na pierwszym planie, np. zatrzymać podgląd z kamery.
Użyj metody onPause, aby wstrzymać lub dostosować operacje, które nie mogą być kontynuowane lub mogą być kontynuowane w ograniczonym zakresie, gdy Activity jest w stanie wstrzymania, i które mają zostać wkrótce wznowione.
Możesz też użyć metody onPause, aby zwolnić zasoby systemowe, uchwyty do czujników (np. GPS) lub inne zasoby, które wpływają na żywotność baterii, gdy aktywność jest wstrzymana, a użytkownik ich nie potrzebuje.
Jednak, jak wspomniano w sekcji dotyczącej onResume, wstrzymana aktywność może być nadal w pełni widoczna, jeśli aplikacja działa w trybie wielu okien. Zamiast onPause używaj onStop, aby w pełni zwalniać lub dostosowywać zasoby i operacje związane z interfejsem, co pozwoli lepiej obsługiwać tryb wielu okien.
Poniższy przykład LifecycleObserver reagującego na zdarzenie ON_PAUSE jest odpowiednikiem poprzedniego przykładu zdarzenia ON_RESUME. Zwalnia on kamerę, która inicjuje się po otrzymaniu zdarzenia ON_RESUME:
class CameraComponent : LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun releaseCamera() {
camera?.release()
camera = null
}
...
}
W tym przykładzie kod zwalniający migawkę aparatu jest umieszczony po odebraniu zdarzenia ON_PAUSE przez LifecycleObserver.
onPause trwa bardzo krótko i nie zawsze daje wystarczająco dużo czasu na wykonanie operacji zapisywania. Z tego powodu nie używaj onPause do zapisywania danych aplikacji lub danych użytkownika, wykonywania połączeń sieciowych ani przeprowadzania transakcji w bazie danych.
Takie działanie może nie zostać ukończone przed zakończeniem metody.
Zamiast tego wykonuj operacje zamykania przy dużym obciążeniu w czasie onStop. Więcej informacji o odpowiednich operacjach do wykonania podczas onStop znajdziesz w następnej sekcji. Więcej informacji o zapisywaniu danych znajdziesz w sekcji zapisywanie i przywracanie stanu.
Zakończenie działania metody onPause nie oznacza, że aktywność przestanie być w stanie wstrzymania. Aktywność pozostaje w tym stanie, dopóki nie zostanie wznowiona lub nie stanie się całkowicie niewidoczna dla użytkownika. Jeśli aktywność zostanie wznowiona, system ponownie wywoła wywołanie zwrotne onResume.
Jeśli aktywność powróci ze stanu Wstrzymana do stanu Wznowiona, system zachowa instancję Activity w pamięci i przywoła ją, gdy wywoła Activity.onResume W takim przypadku nie musisz ponownie inicjować komponentów utworzonych w trakcie żadnej z metod wywołania zwrotnego prowadzących do stanu wznowienia. Jeśli aktywność stanie się całkowicie niewidoczna, system wywoła onStop.
onStop
Gdy aktywność przestaje być widoczna dla użytkownika, przechodzi w stan Zatrzymano, a system wywołuje wywołanie zwrotne onStop. Może się to zdarzyć, gdy nowo uruchomiona aktywność zajmuje cały ekran. System wywołuje też onStop, gdy aktywność kończy działanie i ma zostać zakończona.
Gdy aktywność przejdzie w stan Stopped, każdy komponent powiązany z cyklem życia aktywności otrzyma zdarzenie ON_STOP. W tym miejscu komponenty cyklu życia mogą zatrzymać każdą funkcję, która nie musi działać, gdy komponent nie jest widoczny na ekranie.
W onStop zwalniaj lub dostosowuj zasoby, które nie są potrzebne, gdy aplikacja jest niewidoczna dla użytkownika. Na przykład aplikacja może wstrzymać animacje lub przełączyć się z dokładnych na przybliżone aktualizacje lokalizacji. Użycie onStopzamiast onPause oznacza, że praca związana z interfejsem użytkownika jest kontynuowana, nawet gdy użytkownik wyświetla Twoją aktywność w trybie wielu okien.
Używaj też onStop do wykonywania stosunkowo wymagających operacji zamykania. Jeśli na przykład nie możesz znaleźć lepszego czasu na zapisanie informacji w bazie danych, możesz to zrobić w trakcie onStop. W przykładzie poniżej pokazujemy implementację funkcji
onStop, która zapisuje zawartość notatki w wersji roboczej w pamięci trwałej:
override fun onStop() {
super.onStop()
// Delegate the save operation to the ViewModel, which handles the
// background thread operations (e.g., using Kotlin Coroutines and Room).
noteViewModel.saveDraft()
}
Gdy aktywność przechodzi w stan zatrzymania, obiekt Activity jest przechowywany w pamięci: zachowuje wszystkie informacje o stanie i elementach, ale nie jest powiązany z menedżerem okien. Gdy aktywność zostanie wznowiona, te informacje zostaną przywrócone.
Gdy aktywność jest w stanie zatrzymania, może wrócić do interakcji z użytkownikiem lub zakończyć działanie i zostać zamknięta. Jeśli aktywność zostanie przywrócona, system wywoła metodę onRestart. Jeśli Activity zakończy działanie, system wywoła onDestroy.
onDestroy
onDestroy jest wywoływana przed zniszczeniem aktywności. System wywołuje ten wywołanie zwrotne z jednego z 2 powodów:
- Aktywność dobiega końca, ponieważ użytkownik całkowicie ją odrzucił lub wywołano w niej metodę
finish. - System tymczasowo niszczy aktywność z powodu zmiany konfiguracji, np. obrócenia urządzenia lub przejścia do trybu wielu okien.
Gdy aktywność przechodzi w stan zniszczenia, każdy komponent uwzględniający cykl życia powiązany z cyklem życia aktywności otrzymuje zdarzenie ON_DESTROY. W tym miejscu komponenty cyklu życia mogą zwalniać miejsce, zanim Activity zostanie zniszczony.
Zamiast umieszczać w Activity logikę określającą, dlaczego jest on niszczony, użyj obiektu ViewModel, aby zawierał odpowiednie dane widoku dla Activity. Jeśli Activity zostanie utworzony ponownie z powodu zmiany konfiguracji, ViewModel nie musi nic robić, ponieważ jest zachowywany i przekazywany do następnej instancji Activity.
Jeśli Activity nie zostanie ponownie utworzony, wywoływana jest metoda onCleared, która umożliwia zwolnienie miejsca na wszelkie potrzebne dane przed zniszczeniem.ViewModel Te 2 sytuacje możesz odróżnić za pomocą metody isFinishing.
Jeśli aktywność się kończy, onDestroy jest ostatnim wywołaniem zwrotnym cyklu życia, które otrzymuje aktywność. Jeśli wywołanie funkcji onDestroy nastąpi w wyniku zmiany konfiguracji, system natychmiast utworzy nową instancję aktywności, a następnie wywoła w niej funkcję onCreate w nowej konfiguracji.
Wywołanie zwrotne onDestroy zwalnia wszystkie zasoby, które nie zostały zwolnione przez wcześniejsze wywołania zwrotne, np. onStop.
Stan działania i usuwanie z pamięci
System zamyka procesy, gdy musi zwolnić pamięć RAM. Prawdopodobieństwo, że system zakończy dany proces, zależy od jego stanu w danym momencie. Stan procesu zależy z kolei od stanu działania uruchomionego w procesie. Tabela 1 pokazuje korelacje między stanem procesu, stanem działania a prawdopodobieństwem zakończenia procesu przez system. Ta tabela ma zastosowanie tylko wtedy, gdy proces nie uruchamia innych typów komponentów aplikacji.
Prawdopodobieństwo śmierci |
Stan procesu |
Końcowy stan działania |
Najniższy |
Pierwszy plan (wyostrzony lub w trakcie wyostrzania) |
Wznowiono |
Niski |
Widoczny (bez zaznaczenia) |
Rozpoczęto/wstrzymano |
Wyższe |
Tło (niewidoczne) |
Zatrzymano |
Najwyższy |
Puste |
Zniszczono |
Tabela 1. Związek między cyklem życia procesu a stanem działania.
System nigdy nie zamyka bezpośrednio aktywności, aby zwolnić pamięć. Zamiast tego kończy proces, w którym działa aktywność, niszcząc nie tylko aktywność, ale też wszystko inne, co działa w tym procesie. Aby dowiedzieć się, jak zachować i przywrócić stan interfejsu aktywności w przypadku śmierci procesu zainicjowanej przez system, zapoznaj się z sekcją zapisywania i przywracania stanu.
Użytkownik może też zakończyć proces, korzystając z Menedżera aplikacji w Ustawieniach.
Więcej informacji o procesach znajdziesz w omówieniu procesów i wątków.
Zapisywanie i przywracanie przejściowego stanu interfejsu
Użytkownik oczekuje, że stan interfejsu aktywności pozostanie taki sam podczas zmiany konfiguracji, np. obrócenia ekranu lub przejścia do trybu wielu okien. Gdy jednak nastąpi taka zmiana konfiguracji, system domyślnie niszczy aktywność, usuwając wszelkie stany interfejsu przechowywane w jej instancji.
Podobnie użytkownik oczekuje, że stan interfejsu pozostanie taki sam, jeśli tymczasowo przełączy się z Twojej aplikacji na inną, a potem do niej wróci. System może jednak zniszczyć proces aplikacji, gdy użytkownik jest nieobecny, a aktywność jest zatrzymana.
Gdy ograniczenia systemowe powodują zniszczenie Activity, zachowaj przejściowy stan interfejsu użytkownika za pomocą kombinacji ViewModel (w przypadku złożonej logiki biznesowej i stanu ekranu), interfejsu Jetpack Compose rememberSaveable API (w przypadku lekkiego stanu interfejsu) lub pamięci lokalnej. Więcej informacji o oczekiwaniach użytkowników w porównaniu z zachowaniem systemu oraz o tym, jak najlepiej zachowywać złożone dane o stanie interfejsu w przypadku aktywności inicjowanej przez system i śmierci procesu, znajdziesz w artykule Zapisywanie stanów interfejsu.
rememberSaveable automatycznie przetrwa zmiany konfiguracji i śmierć procesu zainicjowaną przez system, ponieważ w tle łączy stan, zapewniając płynne działanie bez konieczności stosowania kodu standardowego na poziomie aktywności.
Stan instancji
Istnieje kilka scenariuszy, w których aktywność jest niszczona z powodu normalnego działania aplikacji, np. gdy użytkownik naciśnie przycisk Wstecz lub gdy aktywność sygnalizuje własne zniszczenie przez wywołanie metody finish.
Gdy aktywność zostanie zniszczona, ponieważ użytkownik naciśnie przycisk Wstecz lub aktywność sama się zakończy, zarówno system, jak i użytkownik stracą na zawsze pojęcie o tym wystąpieniu Activity. W takich przypadkach oczekiwania użytkownika są zgodne z działaniem systemu i nie musisz niczego dodatkowo robić.
Jeśli jednak system zniszczy aktywność z powodu ograniczeń systemowych (np. zmiany konfiguracji lub braku pamięci), to chociaż rzeczywista instancja Activityzostanie usunięta, system zapamięta, że istniała. Jeśli użytkownik spróbuje wrócić do aktywności, system utworzy nową instancję tej aktywności, używając zestawu zapisanych danych opisujących stan aktywności w momencie jej zniszczenia.
Zapisane dane, których system używa do przywracania poprzedniego stanu, nazywane są stanem instancji. W praktyce jest to zbiór par klucz-wartość. Domyślnie system używa stanu instancji do zapisywania podstawowych informacji o układzie interfejsu, takich jak tekst wpisany przez użytkownika czy pozycje przewijania.
Możesz wykorzystać to działanie systemu za pomocą funkcji rememberSaveable. Jeśli instancja aktywności zostanie zniszczona i utworzona ponownie, każdy stan interfejsu użytkownika opakowany w rememberSaveable zostanie automatycznie przywrócony bez konieczności pisania dodatkowego kodu na poziomie aktywności.
Jednak Twoja aktywność prawdopodobnie będzie zawierać bardziej złożone informacje o stanie, które chcesz przywrócić, takie jak dane użytkownika, odpowiedzi sieciowe lub zmienne członkowskie, które śledzą postępy użytkownika. Mechanizm stanu instancji (a co za tym idzie,rememberSaveable) nie nadaje się do przechowywania więcej niż niewielkiej ilości danych, ponieważ wymaga serializacji w głównym wątku i zużywa pamięć procesu systemowego.
Aby zachować więcej niż niewielką ilość danych, zastosuj podejście łączone, korzystając z trwałego lokalnego przechowywania danych, klasy ViewModel i przenoszenia stanu Compose, zgodnie z opisem w artykule Zapisywanie stanów interfejsu.
Zapisywanie prostego, lekkiego stanu interfejsu za pomocą funkcji rememberSaveable
Gdy aktywność zaczyna się zatrzymywać, system przygotowuje się do zapisania informacji o stanie w pakiecie stanu instancji. Aby skorzystać z tego zachowania systemu, użyj rememberSaveable bezpośrednio w funkcjach typu „composable”.
rememberSaveable automatycznie zapisuje i przywraca przejściowy stan interfejsu, np. wpisany przez użytkownika tekst lub pozycje przewijania, podczas ponownego tworzenia aktywności.
Aby zapisać niestandardowe, lekkie informacje o stanie (np. postępy użytkownika w grze), zadeklaruj stan za pomocą rememberSaveable. Framework Compose
zajmuje się serializacją do pakietu stanu instancji:
var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) { mutableStateOf( TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length)) ) }
Aby zapisać trwałe dane, takie jak preferencje użytkownika lub dane bazy danych, wykorzystuj odpowiednie momenty, gdy Twoja aktywność jest na pierwszym planie. Jeśli taka możliwość się nie pojawi, zapisz trwałe dane w metodzie onStop.
Przywracanie stanu interfejsu aktywności za pomocą zapisanego stanu instancji
Gdy aktywność zostanie ponownie utworzona po wcześniejszym zniszczeniu, przywracanie stanu następuje automatycznie. Gdy używasz rememberSaveable, nie musisz pisać żadnej logiki przywracania, sprawdzać pakietów null ani zastępować wywołań zwrotnych aktywności. Kod, który inicjuje i zapisuje stan, również bezproblemowo przywraca go, gdy aktywność powraca:
var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) { mutableStateOf( TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length)) ) }
Aktywności i nawigacja
Aplikacja prawdopodobnie będzie wielokrotnie przełączać się między ekranami, np. gdy użytkownik naciśnie przycisk Wstecz na urządzeniu lub wybierze nowe miejsce docelowe. Nowoczesne aplikacje na Androida zwykle korzystają z architektury z jednym działaniem.
Zamiast rozpoczynać nową Activity dla każdego ekranu, aplikacja hostuje pojedynczą Activity i używa komponentu Navigation do zamiany ekranów kompozycyjnych w ramach tej aktywności.
Aby dowiedzieć się, jak wdrożyć nowoczesną nawigację opartą na Compose, zapoznaj się z przewodnikiem po bibliotece Navigation 3 Jetpack Compose.
Uruchamianie jednej aktywności z poziomu innej
W pewnym momencie aktywność może potrzebować uruchomić inną aktywność. Jest to potrzebne na przykład wtedy, gdy aplikacja musi przejść z bieżącego ekranu na nowy.
W zależności od tego, czy działanie ma oczekiwać wyniku z nowego działania, które ma się rozpocząć, uruchom nowe działanie za pomocą metody startActivity lub startActivityForResult. W obu przypadkach przekazujesz obiekt Intent.
Obiekt Intent określa dokładną aktywność, którą chcesz rozpocząć, lub opisuje typ działania, które chcesz wykonać. System wybiera odpowiednią aktywność, która może pochodzić nawet z innej aplikacji. Obiekt Intent może też zawierać niewielkie ilości danych, które będą używane przez uruchomione działanie. Więcej informacji o klasie Intent znajdziesz w artykule Intencje i filtry intencji.
startActivity
Jeśli nowo rozpoczęta aktywność nie musi zwracać wyniku, bieżąca aktywność może ją uruchomić, wywołując metodę startActivity.
Podczas pracy w aplikacji często wystarczy uruchomić znaną aktywność. Na przykład poniższy fragment kodu pokazuje, jak uruchomić aktywność o nazwie SignInActivity.
val context = LocalContext.current
Button(onClick = {
val intent = Intent(context, SignInActivity::class.java)
context.startActivity(intent)
}) {
Text("Sign In")
}
Rozpoczynanie działań zewnętrznych
Nawigacją w aplikacji zajmuje się Navigation, ale Activity czasami musi uruchamiać inne działania. Zwykle dzieje się tak, gdy chcesz użyć aplikacji zewnętrznej do wykonania określonego działania, np. otwarcia przeglądarki internetowej, wysłania e-maila lub zrobienia zdjęcia.
Aby to zrobić, używasz obiektu Intent do opisania typu działania, które chcesz wykonać, a system uruchamia odpowiednie działanie z innej aplikacji.
Jeśli na przykład chcesz umożliwić użytkownikowi wysłanie e-maila, możesz utworzyć ten zamiar:
val intent = Intent(Intent.ACTION_SEND).apply {
putExtra(Intent.EXTRA_EMAIL, recipientArray)
}
startActivity(intent)
Jeśli musisz uruchomić aktywność zewnętrzną i uzyskać wynik (np. poprosić aplikację aparatu o zrobienie zdjęcia i zwrócenie obrazu), użyj nowoczesnych Activity interfejsów API wyników zamiast wycofanego wywołania zwrotnego startActivityForResult.
koordynowanie działań,
Gdy jedna aktywność uruchamia drugą, obie przechodzą przez zmiany stanu cyklu życia. Pierwsza aktywność przestaje działać i przechodzi w stan Wstrzymana lub Zatrzymana, a druga aktywność zostaje utworzona. Jeśli te działania współdzielą dane zapisane na dysku lub w innym miejscu, pamiętaj, że pierwsze działanie nie jest całkowicie zatrzymywane przed utworzeniem drugiego. Proces rozpoczynania drugiego projektu nakłada się na proces zatrzymywania pierwszego.
Kolejność wywołań zwrotnych cyklu życia jest dobrze zdefiniowana, zwłaszcza gdy obie aktywności znajdują się w tym samym procesie, czyli w tej samej aplikacji, a jedna z nich uruchamia drugą. Oto kolejność operacji, które występują, gdy aktywność A uruchamia aktywność B:
- Wykonuje się metoda
onPausedziałania A. - Metody
onCreate,onStartionResumedziałania B są wykonywane kolejno. Aktywność B jest teraz aktywna. - Jeśli aktywność A nie jest już widoczna na ekranie, wykonywana jest jej metoda
onStop.
Ta sekwencja wywołań zwrotnych cyklu życia umożliwia zarządzanie przejściem informacji z jednego działania do drugiego.
Dodatkowe materiały
Więcej informacji o cyklu życia działania znajdziesz w tych dodatkowych materiałach: