Poznanie procesów Androida

Kilka tygodni temu naprawiałem błąd w Android Studio i natknąłem się na tag „android:process”. (Pracuję w Google w zespole Android Studio.) Wiedziałem, że ten tag pozwala na określenie procesu, na którym będzie działał komponent androida. Jednak wiele drobnych szczegółów i rozumowania stojącego za procesami Androida było mi nieznanych. Więc przeczytałem o tym i napisałem ten artykuł, aby podzielić się tym, czego się nauczyłem.

Jak zawsze, jestem szczęśliwy, gdy zostanę poprawiony w czymkolwiek, o czym jestem źle poinformowany.

Przegląd Procesów Androida

Android jest oparty na linuxie, więc „system Android rozpoczyna nowy proces Linux dla aplikacji z pojedynczym wątkiem wykonania. Domyślnie wszystkie komponenty tej samej aplikacji działają w tym samym procesie i wątku (zwanym „głównym” wątkiem).” (od: Process and Threads Overview)

Generalnie wątek „główny” jest również wątkiem „UI” lub wątkiem „zdarzeń”, ponieważ wszelkie modyfikacje UI lub obsługa zdarzeń występują w tym wątku. (wyjątek: y̵o̵u̵ ̵c̵a̵n̵ ̵c̵h̵a̵n̵g̵e̵ ̵t̵h̵i̵s̵ ̵b̵y̵ ̵u̵s̵i̵n̵g̵ ̵T̵h̵r̵e̵a̵d̵ ̵A̵n̵n̵o̵t̵a̵t̵i̵o̵n̵s̵.̵ Pomyliłem się, jest to możliwe tylko dla aplikacji systemowych, aby mieć różne MainThread i UIThread: „Narzędzia do budowania traktują adnotacje @MainThread i @UiThread jako wymienne, więc możesz wywoływać metody @UiThread z metod @MainThread i odwrotnie. Jednak możliwe jest, aby wątek UI był inny niż główny wątek w przypadku aplikacji systemowych z wieloma widokami na różnych wątkach.”)

Domyślnie główny proces (i główny wątek, który uruchamia) działa z nazwą procesu, która jest taka sama jak applicationId aplikacji (zadeklarowana w build.gradle twojej aplikacji). Więc jeśli miałbyś stworzyć domyślny projekt z Android Studio, otrzymałbyś aplikację na Androida, która będzie działać na wątku: com.example.<username>.myapplication i pasujący domyślny pakiet dla twojego kodu.

Co robi tag „android:process”

Domyślnie aplikacja na Androida będzie miała tylko jeden proces. Wszystkie komponenty będą działać na tym samym procesie. Podczas deklarowania nowych komponentów w manifeście twojej aplikacji, możesz użyć tagu „android:process” aby zadeklarować nowy proces dla tego komponentu. Na przykład:

<activity
android:name=".SettingsActivity"
android:process=":setting"
android:label="@string/title_activity_settings">
</activity>

W powyższym fragmencie deklaruję SettingActivity, który będzie działał na lokalnym procesie com.example.kelvinma.myapplication:setting. (więcej o local vs global w dalszej części tego artykułu)

Tag „android:process” może być zastosowany na 4 komponentach android:

  • Activity
  • Service
  • Receiver
  • Provider

a także na tagu Application. Po zastosowaniu na tagu Application, wszelkie komponenty aplikacji również dziedziczą android:process, chyba że nadpisane przez ich własny tag android:process.

Nie jestem pewien, jaki jest przypadek użycia tego tagu na deklaracji aplikacji, gdy możesz po prostu zmienić swój applicationId zamiast tego. Jeśli znasz jeden, proszę powiedz mi.

Krótki przykład wizualny

Aby zilustrować aplikację wieloprocesową, załóżmy, że uruchamiam domyślną aktywność w mojej aplikacji Pomodoro, a następnie używając powyższego snippetu, zmieniam moje SettingsActivity, aby uruchomić na innym procesie. Następnie po uruchomieniu mojej aplikacji i uruchomieniu SettingsActivity, moja aplikacja będzie miała 2 procesy:

$ ./adb shell ps | grep kelvin
u0_a61 32175 1669 1292180 47600 SyS_epoll_ b738f2b5 S com.example.kelvinhanma.pomodoro
u0_a61 32223 1669 1284796 43736 SyS_epoll_ b738f2b5 S com.example.kelvinhanma.pomodoro:setting

Jednakże, wszystkie komponenty domyślnie działają na domyślnym procesie, chyba że inaczej określono przez znacznik procesu. Więc jeśli dodasz android:process=":setting" do domyślnej aktywności, a następnie uruchomisz inną aktywność, twoja aplikacja będzie miała 2 procesy:

com.example.kelvinhanma.pomodoro:setting
com.example.kelvinhanma.pomodoro

Ponieważ rozpoczęta aktywność uruchomi się na domyślnym procesie, ponieważ nie ma ustawionego znacznika procesu.

Kiedy mogę uczynić moją aplikację wieloprocesową?

Są 2 powody, o których wiem, aby utworzyć aplikację wieloprocesową:

  1. Twoja aplikacja ma oddzielne działania, które muszą być uruchamiane niezależnie, powszechnym przykładem jest aplikacja do odtwarzania muzyki, która miałaby domyślny proces obsługujący UI i inny proces do obsługi odtwarzania muzyki.
  2. Twoja aplikacja trafia w ograniczenia pamięci. Android ogranicza użycie pamięci RAM na podstawie każdego procesu. Możesz więc zwiększyć całkowity limit pamięci RAM swojej aplikacji, uruchamiając wiele procesów. Jednak ponieważ procesy nie współdzielą pamięci, nie możesz współdzielić Singletonów między procesami.

Local vs Global process

Typ procesu zależy od wartości, którą wpisujesz w tagu procesu. Jeśli zaczynasz od dwukropka („:”) to proces jest procesem lokalnym, który jest prywatny dla twojej aplikacji (pełna nazwa procesu to applicationId:processName). Jeśli zaczynasz od małej litery, to jest to proces globalny.

Proces globalny może być współdzielony między aplikacjami. Często biblioteka będzie działać na procesie globalnym, więc wiele aplikacji może współdzielić proces, aby zmniejszyć zużycie pamięci.

android:process quiz

Na koniec kilka scenariuszy, zobacz, czy możesz przewidzieć odpowiedź.

Q: Co się stanie, jeśli użyjesz procesu globalnego, aby ustawić swój proces na id pakietu? android:process="com.example.kelvinhanma.pomodoro"

A: Twój proces pozostaje niezmieniony i jest to dozwolone. Chociaż jest to bezsensowna i głupia rzecz do zrobienia.

Q: Co jeśli użyjesz go do ustawienia swojego procesu na pakiet innej aplikacji? Załóżmy, że mam com.example.kelvinhanma.pomodoro uruchomiony na moim urządzeniu. Ustawiam globalny proces innej aplikacji na tę samą nazwę i wdrażam go.

Skończyłbym z 2 procesami o tej samej nazwie!

./adb shell ps | grep kelvin
u0_a181 28008 630 4324212 66060 SyS_epoll_wait 0 S com.example.kelvinhanma.pomodoro
u0_a179 28287 630 4327384 66200 SyS_epoll_wait 0 S com.example.kelvinhanma.pomodoro

Ale to jest w porządku. Nazwy procesów nie muszą być unikalne. Zauważ, że użytkownicy są różni (u0_a181, u0_a179), a identyfikatory procesów są unikalne.

Mam nadzieję, że podobał Ci się ten artykuł i czegoś się nauczyłeś. Nie krępuj się dać mi znać, jeśli coś jest niepoprawne!