Android-prosessien tutkiminen
Muutama viikko sitten korjasin bugia Android Studiossa ja törmäsin ”android:process”-tunnisteeseen. (Työskentelen Googlella Android Studio -tiimissä.) Tiesin, että tagin avulla voit määrittää prosessin, jossa android-komponentti suoritetaan. Minulle oli kuitenkin tuntematon suuri osa Android-prosessien hienoimmista yksityiskohdista ja perusteluista. Niinpä luin asiasta ja kirjoitin tämän artikkelin jakaakseni oppimani.
Kuten aina, minua korjataan mielelläni kaikesta, mistä olen saanut väärää tietoa.
Yleiskatsaus Android-prosesseihin
Android perustuu linuxiin, joten ”Android-järjestelmä käynnistää sovellukselle uuden Linux-prosessin, jossa on yksi suoritussäie. Oletusarvoisesti kaikki saman sovelluksen osat suoritetaan samassa prosessissa ja säikeessä (jota kutsutaan ”pää ”säikeeksi).”” (from: Process and Threads Overview)
Yleisesti ”pää”-säie on myös ”UI”-säie tai ”tapahtumasäie”, koska kaikki UI:n muokkaus tai tapahtumien käsittely tapahtuu tässä säikeessä. (poikkeus: 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̵. ̵ Olin väärässä, vain järjestelmäsovelluksissa voi olla eri MainThread ja UIThread: ”Rakennustyökalut käsittelevät @MainThread
– ja @UiThread
-annotaatioita vaihdettavissa olevina, joten voit kutsua @UiThread
-metodeja @MainThread
-metodeista ja päinvastoin. On kuitenkin mahdollista, että UI-säie on eri kuin pääsäie, jos kyseessä on järjestelmäsovellus, jossa on useita näkymiä eri säikeissä.”)
Pääprosessi (ja sen käynnistämä pääsäie) toimii oletusarvoisesti prosessin nimellä, joka on sama kuin sovelluksen applicationId (joka on ilmoitettu sovelluksen build.gradle-tiedostossa). Jos siis loisit Android Studiolla oletusprojektin, saisit Android-sovelluksen, joka toimii säikeellä: com.example.<käyttäjätunnus>.myapplication ja koodillesi sopivan oletuspaketin.
Mitä ”android:process”-tunniste tekee
Oletusarvoisesti Android-sovelluksella on vain yksi prosessi. Kaikki komponentit suoritetaan samassa prosessissa. Kun ilmoitat uusia komponentteja sovelluksesi manifestissa, voit käyttää ”android:process”-tagia ilmoittaaksesi uuden prosessin tälle komponentille. Näin:
<activity
android:name=".SettingsActivity"
android:process=":setting"
android:label="@string/title_activity_settings">
</activity>
Yllä olevassa pätkässä julistan SettingActivityn, joka suoritetaan paikallisessa com.example.kelvinma.myapplication:setting
-prosessissa. (lisää paikallisesta vs. globaalista myöhemmin tässä artikkelissa)
Tunnistetta ”android:process” voidaan soveltaa neljään android-komponenttiin:
- Activity
- Service
- Receiver
- Provider
ja myös Application-tunnisteeseen. Kun sitä sovelletaan Application-tunnisteeseen, kaikki sovelluksen komponentit perivät myös android:process-tunnisteen, ellei sitä ylitetä niiden omalla android:process-tunnisteella.
En ole varma, mikä on käyttötapaus tämän tunnisteen käyttämiselle sovellusdeklaraatiossa, kun sen sijaan voi vain muuttaa applicationId:tä. Jos tiedät sellaisen, kerro minulle.
Lyhyt visuaalinen esimerkki
Moniprosessisovelluksen havainnollistamiseksi oletetaan, että käynnistän oletusaktiviteetin Pomodoro-sovelluksessani ja sitten yllä olevan pätkän avulla muutan SettingsActivityn suorittamaan toisessa prosessissa. Sitten sovellukseni käynnistämisen ja SettingsActivityn käynnistämisen jälkeen sovelluksessani on kaksi prosessia:
$ ./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
Mutta kaikki komponentit suoritetaan implisiittisesti oletusprosessissa, ellei process-tunnisteella toisin määritetä. Jos siis lisäät android:process=":setting"
oletusaktiviteettiin ja sitten käynnistät toisen aktiviteetin, sovelluksellasi on 2 prosessia:
com.example.kelvinhanma.pomodoro:setting
com.example.kelvinhanma.pomodoro
Koska käynnistetty aktiviteetti käynnistyy oletusprosessilla, koska sille ei ole asetettu prosessitunnistetta.
Milloin teen sovelluksestani moniprosessisen?
Tietääkseni on 2 syytä luoda moniprosessisovellus:
- Sovelluksessasi on erillisiä toimintoja, jotka on suoritettava itsenäisesti, yleinen esimerkki on musiikkia soittava sovellus, jossa oletusprosessi käsittelee käyttöliittymää ja toinen prosessi käsittelee musiikin soittoa.
- Sovelluksesi törmää muistirajoituksiin. Android rajoittaa RAM-muistin käyttöä prosessikohtaisesti. Voit siis kasvattaa sovelluksesi RAM-kokonaisrajaa ajamalla useita prosesseja. Koska prosessit eivät kuitenkaan jaa muistia, et voi jakaa Singletoneja prosessien välillä.
Lokaali vs. globaali prosessi
Prosessin tyyppi riippuu prosessitunnisteeseen antamastasi arvosta. Jos aloitat kaksoispisteellä (”:”), prosessi on paikallinen, joka on yksityinen sovelluksellesi (koko prosessin nimi olisi applicationId:processName). Jos aloitat pienellä kirjaimella, kyseessä on globaali prosessi.
Globaalia prosessia voidaan jakaa sovellusten kesken. Usein kirjasto toimii globaalissa prosessissa, joten useat sovellukset voivat jakaa prosessin muistin käytön vähentämiseksi.
android:process quiz
Lopetetaan muutamalla skenaariolla, katso pystytkö ennustamaan vastauksen.
Kysymys: Mitä tapahtuu, jos käytät globaalia prosessia asettaaksesi prosessin pakettisi id:lle? android:process="com.example.kelvinhanma.pomodoro"
A: Prosessisi pysyy muuttumattomana ja tämä on sallittua. Tosin se on turhaa ja typerää.
K: Entä jos käytät sitä asettaaksesi prosessisi toisen sovelluksen pakettiin? Oletetaan, että minulla on com.example.kelvinhanma.pomodoro
käynnissä laitteessani. Asetan toisen sovelluksen globaalin prosessin samannimiseksi ja otan sen käyttöön.
Minulla olisi lopulta kaksi prosessia, joilla on sama nimi!
./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
Mutta se on hyvä. Prosessien nimien ei tarvitse olla uniikkeja. Huomaa, että käyttäjät ovat erilaisia (u0_a181, u0_a179) ja prosessien id:t ovat uniikkeja.
Toivottavasti pidit artikkelista ja opit jotain. Kerro rohkeasti, jos jokin on väärin!