Android-folyamatok felfedezése
Pár hete egy hibát javítottam az Android Studio-ban, és találkoztam az “android:process” címkével. (A Google-nél dolgozom az Android Studio csapatában.) Tudtam, hogy a tag lehetővé teszi, hogy megadjuk, hogy az android komponens milyen folyamaton fusson. Azonban sok finomabb részlet és az Android folyamatok mögötti érvelés ismeretlen volt számomra. Ezért utánaolvastam, és megírtam ezt a cikket, hogy megosszam, amit megtudtam.
Mint mindig, örömmel veszem, ha kijavítanak bármiben, amiről rosszul informált vagyok.
Az Android folyamatok áttekintése
Az Android a linuxon alapul, így “az Android rendszer egy új Linux folyamatot indít az alkalmazás számára egyetlen végrehajtószállal. Alapértelmezés szerint ugyanazon alkalmazás minden összetevője ugyanabban a folyamatban és szálban (az úgynevezett “fő” szálban) fut”. (from: Process and Threads Overview)
A “fő” szál általában a “UI” szál vagy az “esemény” szál is, mivel minden UI módosítás vagy eseménykezelés ezen a szálon történik. (kivétel: 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̵. ̵ Tévedtem, csak a rendszeralkalmazásoknál lehetséges, hogy különböző MainThread és UIThread legyen: “A build eszközök a @MainThread
és @UiThread
annotációkat felcserélhetőnek tekintik, így @MainThread
metódusokból @MainThread
metódusok hívhatók @UiThread
metódusok és fordítva. Azonban lehetséges, hogy egy UI szál különbözik a főszáltól a több nézetet különböző szálakon tartalmazó rendszeralkalmazások esetében.”)
A főfolyamat (és az általa indított főszál) alapértelmezés szerint olyan folyamatnévvel fut, amely megegyezik az alkalmazás applicationId-jával (az alkalmazás build.gradle fájljában deklarálva). Tehát ha létrehoznál egy alapértelmezett projektet az Android Studio segítségével, akkor egy Android alkalmazást kapnál, amely a következő szálon fut: com.example.<felhasználónév>.myapplication és a kódodnak megfelelő alapértelmezett csomagot.
Mit csinál az “android:process” tag
Egy Android alkalmazásnak alapértelmezés szerint csak egyetlen folyamata van. Minden komponens ugyanabban a folyamatban fog futni. Amikor új komponenseket deklarál az alkalmazás manifesztjében, akkor az “android:process” tag segítségével új folyamatot deklarálhat az adott komponens számára. Például így:
<activity
android:name=".SettingsActivity"
android:process=":setting"
android:label="@string/title_activity_settings">
</activity>
A fenti részletben egy SettingActivity-t deklarálok, amely a helyi com.example.kelvinma.myapplication:setting
folyamaton fog futni. (a lokális vs globálisról bővebben később ebben a cikkben)
Az “android:process” tag alkalmazható a 4 android komponensre:
- Activity
- Service
- Receiver
- Provider
és az Application tagre is. Ha az Application tag-en alkalmazzuk, az alkalmazás minden komponense is örökli az android:process-t, hacsak nem írja felül a saját android:process tag-jük.
Nem vagyok benne biztos, hogy mi a felhasználási módja annak, hogy ezt a tag-et használjuk az alkalmazás deklarációnkban, amikor ehelyett egyszerűen megváltoztathatjuk az applicationId-t. Ha tudsz egyet, kérlek, mondd el nekem.
Egy rövid vizuális példa
A többfolyamatos alkalmazás illusztrálására tegyük fel, hogy elindítom az alapértelmezett tevékenységet a Pomodoro alkalmazásomon, majd a fenti snippet felhasználva megváltoztatom a SettingsActivity-t, hogy egy másik folyamatban fusson. Ekkor az alkalmazásom elindítása és a SettingsActivity elindítása után az alkalmazásomnak 2 folyamata lesz:
$ ./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
Minden komponens azonban implicit módon az alapértelmezett folyamaton fut, hacsak a process tag másként nem határozza meg. Tehát ha az alapértelmezett aktivitáshoz hozzáadod a android:process=":setting"
et, majd elindítasz egy másik aktivitást, akkor az alkalmazásodnak 2 folyamata lesz:
com.example.kelvinhanma.pomodoro:setting
com.example.kelvinhanma.pomodoro
Mert az elindított aktivitás az alapértelmezett folyamaton fog elindulni, mivel nincs beállítva process tag.
Mikor tehetem az alkalmazásomat többfolyamatossá?
2 okot ismerek arra, hogy többfolyamatos alkalmazást hozzunk létre:
- Az alkalmazásodnak különálló műveletei vannak, amelyeket egymástól függetlenül kell futtatni, a leggyakoribb példa egy zenelejátszó alkalmazásnál az alapértelmezett folyamat kezeli a felhasználói felületet és egy másik folyamat a zenelejátszást.
- Az alkalmazásod memória korlátokba ütközik. Az Android folyamatonként korlátozza a RAM-használatot. Így több folyamat futtatásával növelheti az alkalmazás teljes RAM-korlátját. Mivel azonban a folyamatok nem osztják meg a memóriát, nem oszthatja meg a Singletonokat a folyamatok között.
Lokális vs. globális folyamat
A folyamat típusa a process tagben megadott értéktől függ. Ha kettősponttal (“:”) kezded, akkor a folyamat helyi, az alkalmazásod számára privát (a teljes folyamat neve applicationId:processName lenne). Ha kisbetűvel kezdődik, akkor globális folyamatról van szó.
A globális folyamat megosztható az alkalmazások között. Gyakran előfordul, hogy egy könyvtár egy globális folyamaton fut, így több alkalmazás megoszthatja a folyamatot a memóriahasználat csökkentése érdekében.
android:process quiz
Végezzük néhány forgatókönyvvel, hátha meg tudja jósolni a választ.
K: Mi történik, ha egy globális folyamat segítségével a folyamatot a csomag azonosítójára állítjuk? android:process="com.example.kelvinhanma.pomodoro"
A: A folyamatod változatlan marad, és ez megengedett. Bár ez egy értelmetlen és buta dolog.
K: Mi van, ha arra használod, hogy a folyamatodat egy másik alkalmazás csomagjára állítsd be? Tegyük fel, hogy egy com.example.kelvinhanma.pomodoro
fut a készülékemen. Beállítom egy másik alkalmazás globális folyamatát ugyanarra a névre, és telepítem.
A végén 2 azonos nevű folyamatot kapnék!
./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
De ez rendben van. A folyamatneveknek nem kell egyedinek lenniük. Figyeld meg, hogy a felhasználók különbözőek (u0_a181, u0_a179) és a folyamatok azonosítói egyediek.
Remélem, tetszett a cikk és tanultál valamit. Nyugodtan szólj, ha valami hibás!