Procesy i cykl życia aplikacji

W większości przypadków każda aplikacja na Androida działa we własnym procesie systemu Linux. Proces ten jest tworzony dla aplikacji, gdy część jej kodu musi działać i pozostaje uruchomiona, dopóki system nie będzie musiał odzyskać pamięci do wykorzystania przez inne aplikacje, przez co nie jest już potrzebny.

Wyjątkową i podstawową cechą Androida jest to, że czas działania aplikacji nie jest bezpośrednio sterowana przez samą aplikację. System określa natomiast działanie aplikacji na podstawie kombinacji uruchomionych części aplikacji, ich znaczenia dla użytkownika i ilości ogólnej ilości pamięci dostępnej w systemie.

Deweloperzy aplikacji powinni wiedzieć, jak różne jej komponenty (w szczególności Activity, Service i BroadcastReceiver) wpływają na przebieg procesu aplikacji. Niewłaściwe użycie tych komponentów może spowodować, że system zamknie proces aplikacji podczas wykonywania ważnych zadań.

Typowym przykładem błędu cyklu życia procesu jest BroadcastReceiver, który rozpoczyna wątek, gdy otrzymuje Intent w metodzie BroadcastReceiver.onReceive(), a następnie zwraca z funkcji. Po powrocie system uzna, że BroadcastReceiver nie jest już aktywny, a jego proces hostingu nie jest już potrzebny, chyba że są w nim aktywne inne komponenty aplikacji.

System może więc zakończyć ten proces w dowolnym momencie, aby odzyskać pamięć, co spowoduje zakończenie utworzonego wątku. Rozwiązaniem tego problemu jest zwykle zaplanowanie działania funkcji JobService z parametru BroadcastReceiver, aby system wiedział, że w trakcie realizacji jest wykonywana aktywna praca.

Aby określić, które procesy zakończyć przy małej ilości pamięci, Android umieszcza każdy proces w hierarchii ważności na podstawie uruchomionych w nich komponentów oraz stanu tych komponentów. Oto typy procesów według znaczenia:

  1. Proces na pierwszym planie jest wymagany do tego, co użytkownik obecnie robi. Różne komponenty aplikacji mogą powodować różne traktowanie jej procesów na pierwszym planie. Proces jest uznawany za działający na pierwszym planie, jeśli spełniony jest któryś z tych warunków:
  2. W systemie jest tylko kilka takich procesów. Są one zatrzymywane w ostateczności tylko wtedy, gdy ilość pamięci jest na tyle mała, że nawet te procesy nie mogą działać. Zwykle w takim przypadku urządzenie osiągnęło stan stronicowania pamięci, więc to działanie jest wymagane do reagowania interfejsu użytkownika.

  3. Widoczny proces wykonuje działanie, z którego użytkownik jest w danym momencie świadomy, więc jego zamknięcie ma zauważalnie negatywny wpływ na jego wrażenia. Proces jest uważany za widoczny, gdy:
    • Korzysta z interfejsu Activity, który jest widoczny dla użytkownika na ekranie, ale nie na pierwszym planie (wywołano jego metodę onPause()). Może się tak zdarzyć, np. jeśli element Activity na pierwszym planie jest wyświetlany jako okno, w którym widać za nim poprzedni element Activity.
    • Ma Service, który działa jako usługa na pierwszym planie przez Service.startForeground() (która prosi, aby system traktował usługę jako coś, o czym użytkownik jest świadomy lub w zasadzie tak, jakby była widoczna).
    • To hostowana usługa, z której system korzysta na potrzeby konkretnej funkcji, o której użytkownik wie, takiej jak animowana tapeta lub usługa metody wprowadzania.

    Liczba tych procesów działających w systemie jest mniej ograniczona niż w przypadku procesów na pierwszym planie, ale wciąż stosunkowo kontrolowana. Procesy te są uważane za bardzo ważne i nie są zatrzymywane, chyba że jest to konieczne do utrzymania działania wszystkich procesów na pierwszym planie.

  4. Proces usługi to proces przechowujący Service, który został rozpoczęty z użyciem metody startService(). Chociaż te procesy nie są bezpośrednio widoczne dla użytkownika, zazwyczaj wykonują one działania, na których użytkownikowi zależy (np. przesyłanie lub pobieranie danych sieciowych w tle), więc system zawsze utrzymuje takie procesy, chyba że ilość pamięci jest wystarczająca do zachowania wszystkich procesów widocznych na pierwszym planie.

    Znaczenie usług działających od dłuższego czasu (np. 30 minut lub dłużej) może być obniżone, aby ich procesy trafiały na listę w pamięci podręcznej.

    Procesy, które muszą działać przez dłuższy czas, można tworzyć za pomocą setForeground. Jeśli jest to proces okresowy, który wymaga krótkiego czasu na wykonanie, możesz go zaplanować w AlarmManager. Więcej informacji znajdziesz w artykule na temat pomocy dla długotrwałych instancji roboczych. Pomaga to uniknąć sytuacji, gdy długo działające usługi zużywają nadmiarowe zasoby, na przykład przez wyciek pamięci, co uniemożliwia prawidłowe działanie systemu.

  5. Proces w pamięci podręcznej nie jest obecnie potrzebny, więc system może go wyłączyć w razie potrzeby, gdy zasoby takie jak pamięć są potrzebne w innym miejscu. W normalnie działającym systemie są to jedyne procesy związane z zarządzaniem zasobami.

    Dobrze działający system ma zawsze dostępnych wiele procesów w pamięci podręcznej, co umożliwia wydajne przełączanie się między aplikacjami i w razie potrzeby regularnie zamyka aplikacje z pamięci podręcznej. Tylko w bardzo krytycznych sytuacjach system dochodzi do punktu, w którym wszystkie procesy z pamięci podręcznej są kończone i musi rozpocząć kończenie procesów usługi.

    Ponieważ procesy z pamięci podręcznej mogą zostać zakończone przez system w każdej chwili, aplikacje w stanie pamięci podręcznej powinny przestać działać. Jeśli aplikacja musi wykonywać zadania o znaczeniu krytycznym dla użytkowników, powinna używać powyższych interfejsów API do uruchamiania zadań w aktywnym stanie procesu.

    Procesy w pamięci podręcznej często zawierają co najmniej 1 instancję Activity, która nie jest obecnie widoczna dla użytkownika (metoda onStop() została wywołana i zwrócona). Jeśli użytkownik prawidłowo wdroży cykl życia Activity, gdy system zakończy takie procesy, nie wpłynie to na wygodę użytkownika, gdy powróci do tej aplikacji. Może przywrócić wcześniej zapisany stan, gdy powiązana aktywność zostanie odtworzona w nowym procesie. Pamiętaj, że nie ma gwarancji, że funkcja onDestroy() zostanie wywołana w przypadku zakończenia procesu przez system. Więcej informacji: Activity.

    Począwszy od Androida 13 czas wykonywania procesu aplikacji może być ograniczony lub może nie być wykonywany, dopóki nie znajdzie się w jednym z powyższych aktywnych stanów cyklu życia.

    Procesy z pamięci podręcznej są przechowywane na liście. Dokładna zasada kolejności w przypadku tej listy to szczegóły implementacji platformy. Zwykle stara się zachować bardziej przydatne procesy, takie jak hostowanie aplikacji domowej użytkownika lub ostatnie działanie wykonane przez użytkownika przed innymi typami procesów. Możesz też zastosować inne zasady procesów wyłączania, np. ustawić sztywne limity liczby dozwolonych procesów lub ograniczyć czas, przez jaki proces może być stale buforowany.

Podczas podejmowania decyzji o sklasyfikowaniu procesu system opiera swoją decyzję na najważniejszym poziomie spośród wszystkich aktywnych obecnie komponentów. Więcej informacji o tym, jak każdy z tych komponentów wpływa na ogólny cykl życia procesu i aplikacji, znajdziesz w dokumentacji Activity, Service i BroadcastReceiver.

Priorytet procesu może też zostać zwiększony zależnie od innych zależności, jakie musi od niego uzyskać. Jeśli na przykład proces A jest powiązany z elementem Service z flagą Context.BIND_AUTO_CREATE lub używa ContentProvider w procesie B, klasyfikacja procesu B jest zawsze co najmniej tak samo ważna jak proces A.