一步一步揭開Android應(yīng)用程序的神秘面紗
Android應(yīng)用程序是用Java語言寫的,通過aapt工具把應(yīng)用程序所需要的任何數(shù)據(jù)、資源文件打包成apk文件,這個文件是一個將應(yīng)用安裝到手機上的一個載體。
有很多方式,每個Android應(yīng)用程序存在于不同的世界:
(1)默認的,每個應(yīng)用在他自己的Linux進程中運行,當應(yīng)用中的任何代碼需要執(zhí)行時Android就啟動相應(yīng)的進程,當不需要執(zhí)行時并且系統(tǒng)資源被其他應(yīng)用請求時android就關(guān)閉相應(yīng)的進程。
(2)每個進程都有他自己的虛擬機對象(VM),所以應(yīng)用程序代碼與其他的應(yīng)用運行是彼此隔離的。
(3)默認的,每個應(yīng)用被分配一個唯一的Linux user ID,都被設(shè)置權(quán)限以便應(yīng)用程序的文件只對用戶可見或者只對應(yīng)用自己可見。
安排兩個應(yīng)用程序共享一個user ID是可能的,這種情況下他們彼此之間是可以看見對方的文件的,為了保護系統(tǒng)資源,擁有相同ID的應(yīng)用也能被安排運行在一個相同的Linux進程中,共享相同的VM。
1、應(yīng)用組件(Application Components)
Android一個核心的特點就是一個應(yīng)用能使用另一個應(yīng)用的元素(如果另一個應(yīng)用允許的話),你的應(yīng)用不需要包含你用到的另一個應(yīng)用的代碼也不需要你連接這些代碼,相反的,只是當應(yīng)用需要這些代碼時,就啟動另一個應(yīng)用相應(yīng)的代碼(不是讓另一個應(yīng)用全部啟動)
為了這個能工作,當一個應(yīng)用的任何部分被需要時系統(tǒng)必須能啟動這個應(yīng)用進程,并且將這個部分實例化成java對象,因此,和其他大多數(shù)系統(tǒng)不同的是,android應(yīng)用程序沒有一個單獨的程序入口(例如:沒有main()函數(shù)),相反的,android應(yīng)用有必要的組件以便當需要時系統(tǒng)能實例化并運行它,android中有四種組件:
(1)Activity
一個Activity是一個可見的用戶可以使用的用戶界面,如果一個應(yīng)用中有多個Activity,雖然彼此結(jié)合形成一個應(yīng)用在一起工作,但是每個Activity是彼此獨立的,每個都是Activity的一個子類。
一個應(yīng)用程序可能由一個或多個Activity組成,這些Activity這么樣顯示,需要多少個Activity,依賴于這個應(yīng)用的設(shè)計者,一般的,有一個Activity應(yīng)該被標記成當這個應(yīng)用啟動時第一個呈現(xiàn)出來給用戶的。
每個Activity默認的被給予一個窗口來繪制,一般的,這個窗口占滿整個屏幕,但是他可以比屏幕小并且浮在另一個窗口的上面。
一個窗口中的可見的內(nèi)容是由一些具有層次關(guān)系的view組成的,都是繼承自View類的,每個view都控制一個窗口中的特定的矩形框,parent view 包含children view和組織children view的布局,leaf view(那些在繼承層次最底層的view)繪制在他們所控制的矩形框中,并且對用戶的動作做出直接的回應(yīng),因此view就是Activity和用戶交互的地方,android有很多已經(jīng)做好的view你可以使用,包括buttons,text fields,scroll bars,menu items,check boxes等等
一個view hierarchy是通過Activity.setContentView()方法被放到一個Activity的window中的,content view是view hierarchy中最頂端的那個view。
(2)Services
一個service不是一個用戶可見的組件,在不確定的一段時間內(nèi)運行在后臺,每個service都繼承自Service類。
你可以連接(connect)或者綁定(bind)到一個正在運行的service(如果這個service還沒運行的話就啟動它),當連接到service后,你可以通過一個service暴露出來的接口和這個service交流,對music service來說,這個接口可以是允許用戶暫停,后退,停止,重新播放。
和Activity或者其他組件一樣,service運行在這個應(yīng)用進程的主線程中,所以他不會阻塞其他的組件或者用戶界面,他們經(jīng)常為那些耗時長的任務(wù)單獨開一個線程。
(3)Broadcast receivers
一個broadcast receiver這樣一個組件,他只是接收廣播并作出反應(yīng),在系統(tǒng)中有很多已有的廣播,比如反應(yīng)時區(qū)變化(timezone)的,電池變化(battery)的,用戶修改了系統(tǒng)語言時的廣播,應(yīng)用程序也可以自己定義廣播,比如定義這樣一個廣播,讓其他的應(yīng)用知道某些數(shù)據(jù)已經(jīng)下載完畢了可以使用了。
一個應(yīng)用可以有任意多個broadcast receiver來對他所關(guān)心的廣播進行監(jiān)聽并作出反應(yīng)。所有的receiver都繼承自BroadcastReceiver類。
BroadcastReceiver不顯示在用戶界面上,然而,他們可以啟動一個Activity來作為他們接收到的信息一種反應(yīng),或者他們可以使用NotificationManager來提示用戶,Notifications可以通過不同的方式獲得用戶的注意,比如點亮呼吸燈,震動電話,播放一個聲音等等,他們一般放一個圖標在狀態(tài)欄上,來讓用戶可以打開獲得這些信息。
(4)Content providers
Content providers是一個應(yīng)用程序數(shù)據(jù)的集合,來讓其他的應(yīng)用可以訪問這些數(shù)據(jù),這些數(shù)據(jù)可以被存在文件系統(tǒng)中,SQLite數(shù)據(jù)庫中,或者其他可以存數(shù)據(jù)的地方,Content providers是一個基本的方法集合來使其他的應(yīng)用可以獲得和存儲這些數(shù)據(jù),然而應(yīng)用不直接調(diào)用這些方法,而是使用一個ContentResolver對象來調(diào)用這些方法,一個ContentResolver可以和任何的Content providers交流,他和provider協(xié)作來管理系統(tǒng)中任何進程間的通信。
無論何時一個請求都應(yīng)該由一個特定的組件來處理,android系統(tǒng)來確保包含這個組件的應(yīng)用進程運行,如果需要就啟動它,如果需要就為這個組件創(chuàng)造一個實例,確保這個組件的一個適當?shù)膶嵗梢员坏玫健?/p>
2、啟動組件:intent
當有一個來自于content resolver的請求指向Content provider時,content provider啟動,其他的三個組件(Activity,service,broadcast receiver)是通過一個叫做intent的異步的消息來啟動的,一個intent持有一個message的內(nèi)容,對Activity和service來說,他是一個被要求的動作(action)和在該動作上的數(shù)據(jù)的URI,對broadcast receiver來說,intent對象是一個被廣播的動作。
針對每種組件分別有對應(yīng)的方法來啟動它:
(1)一個Activity是通過傳遞一個Intent對象到Context.startActivity()或者Activity.startActivityForResult()來啟動的(或者去做一些新的任務(wù)),被啟動的這個Activity可以通過getIntent()來獲得導(dǎo)致他啟動的那個intent的。
(2)一個service是通過傳遞一個Intent對象到Context.startService()來啟動的(或者給一些新的命令給正在運行的service),android調(diào)用service的onStart()方法,并且把Intent對象傳遞給他,同樣的,一個Intent可以傳遞到Context.bindService()方法里來建立一個介于正在運行的service和調(diào)用他的組件之間的連接,這個service通過onBind()方法來接收這個Intent對象,(如果這個service還沒有運行,bindservice()能選擇性的啟動它),在后面的部分,關(guān)于綁定service的更多詳細的信息請查看遠程調(diào)用。
(3)一個應(yīng)用可以通過傳遞一個Intent對象給像Context.sendBroadcast(), Context.sendOrderedBroadcast(), Context.sendStickyBroadcast()這樣的方法來開始一個廣播,android通過調(diào)用對應(yīng)的onReceive()方法將intent傳遞給所有對這個廣播感興趣的broadcast receiver。
3、關(guān)閉組件(Shutting down components)
當對來自于content resolver的請求作出回應(yīng)時content provider就啟動了,當有一個感興趣的broadcast message被廣播時,broadcast receiver啟動,所以我們需要知道怎么關(guān)閉這些組件。
(1)Activity可以通過調(diào)用它自己的finish()方法來關(guān)閉,一個Activity也可以通過調(diào)用finishActivity()來關(guān)閉另一個Activity(這個Activity是通過調(diào)用startActivityForResult()來啟動的)。
(2)一個service可以通過調(diào)用自己的stopSelf(),或者Context.stopService()來關(guān)閉。
當組件不再使用時或者android為了更多組件能運行而回收內(nèi)存時,android系統(tǒng)是關(guān)閉這些組件的,在后面的部分,可以在組件的生命周期中看到更多更詳細的介紹。
4、Activities and Tasks
一個Activity可以啟動另一個Activity,即使這個Activity是定義在另一個應(yīng)用里的,比如說,你想展示給用戶一條街的地圖,現(xiàn)在已經(jīng)有一個Activity可以做這件事,那么現(xiàn)在你需要做的就是將你請求的信息放進一個Intent對象里,并且通過startActivity()傳遞給他,這個地圖就可以顯示出來了,但用戶按下BACK鍵時,你的Activity又重新出現(xiàn)在屏幕上。
對用戶來說,顯示地圖的Activity和你的Activity好像在一個應(yīng)用中的,即使是他們是定義在不用的應(yīng)用中的,運行在各自的應(yīng)用進程中,android將兩個Activity放進一個task里,一個task是一組彼此聯(lián)系的Activity,被安排在一個堆棧中,堆棧中的根Activity就是開辟這個task的,一般的,他是用戶選擇應(yīng)用后首先啟動的那個Activity,堆棧頂部的Activity是當前正在運行的Activity,當一個Activity啟動另一個Activity時,新的Activity被壓進堆棧中,成為運行的Activity,當用戶按下BACK鍵,當前的Activity彈出堆棧,先前的Activity恢復(fù)成為運行的Activity。
一個task就是一組Activity的堆棧,不是在manifest文件里的一個類,一個元素,所以沒有方法來為一個task里的Activity獨立的設(shè)置值,對task設(shè)置值是在root Activity里設(shè)置的。
一個task里的所有Activity組成一個單元,整個task(整個Activity堆棧)可以在前臺,也可以在后臺(應(yīng)用程序的切換就是task的前后臺的切換),假設(shè),當前的task有四個Activity在堆棧里,用戶按下HOME鍵,去開啟另一個應(yīng)用(實際上是一個新的task),那么當前的task就退到后臺運行,新開啟的應(yīng)用的root Activity此時就顯示出來了,然后,過了一段時間,用戶回到主界面,又重新選擇了以前的那個應(yīng)用(先前的那個task),那么先前的那個task此時又回到了前臺了,當用戶按下BACK鍵時,屏幕不是顯示剛剛關(guān)閉的那個應(yīng)用,而是移除回到前臺的這個task堆棧棧頂Activity,將下一個Activity顯示出來。
剛才描述的情況是Activity和task默認的行為,但是有很多的方法來對幾乎所有的方面進行修改,如Activity和task的聯(lián)系。task里Activity的行為,是受啟動它的Intent對象的flag和在manifest文件中的Activity的屬性集合共同影響的。
Flag:
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_SINGLE_TOP
taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
5、Affinities and new tasks
默認的,一個應(yīng)用里的所有Activity都有聯(lián)系,所有都是屬于一個task的,然而,可以通過
FLAG_ACTIVITY_NEW_TASK
一個Activity調(diào)用startActivity()啟動一個新的Activity時,新的Activity會壓入到相同的task中的,如果傳遞給startactivity()的Intent對象含有FLAG_ACTIVITY_NEW_TASK標志,系統(tǒng)就會尋找一個新的task來裝這個新的Activity,然而,也不總是這么做,如果已經(jīng)有一個task和這個新的的Activity有相同的關(guān)系,那么就把這個新的Activity放進這個task里,如果沒有,就啟動一個新的task。
allowTaskReparenting屬性
如果一個Activity的allowTaskReparenting屬性設(shè)置為true,這個Activity就可以從啟動時的那個task移動到一個和他有關(guān)系的當前在前臺的一個task里,比如,假設(shè)現(xiàn)在有一個天氣預(yù)報的Activity被定義在一個旅行的應(yīng)用里,他和這個應(yīng)用里的其他Activity有相同的關(guān)系(默認的關(guān)系),并且他允許reparenting,現(xiàn)在你自己應(yīng)用有一個Activity啟動這個天氣預(yù)報的Activity,那么天氣預(yù)報Activity就會移動到你的Activity所在的task里,當旅行的應(yīng)用又回到前臺時,天氣預(yù)報Activity重新回到以前的那個task并顯示。(個人觀點:如果說沒有設(shè)置這個屬性,或者這個屬性設(shè)置為false,那么一個應(yīng)用里的Activity調(diào)用另一個應(yīng)用里的Activity時,系統(tǒng)是為另一個應(yīng)用里的Activity創(chuàng)建一個實例,然后放到同一個task里,但是如果設(shè)置了allowTaskReparenting為true,那么另一個應(yīng)用里的Activity是可以在不同的task間來回移動的,那個task在前臺就移動到那個task里)
6、啟動方式
"standard" (the default mode)
"singleTop"
"singleTask"
"singleInstance"
這些不同的方式可以從下面的四點來說:
(1)對一個Intent作出回應(yīng)時哪個task應(yīng)該去持有這個Activity。
對standard和singleTop方式來說,新的Activity和通過startActivity調(diào)用他的Activity處在同一個task中,如果調(diào)用時Intent對象里含有FLAG_ACTIVITY_NEW_TASK標志,那么就像前面講的那樣的尋找一個新的task。
相反的,singTask和singleInstance方式,總是標志Activity為task的root Activity,他們不會進入到其他的task中。
(2)一個Activity是否可以有多個實例。
一個standard或者singleTop屬性的Activity可以實例化多次,他們可以屬于多個不同的task。
相反的,singleTask或者singleInstance屬性的Activity只能有一個實例(單例)。
(3)實例是否能允許在task里有其他的Activity。
一個singleInstance屬性的Activity單獨的在他自己的task里,并且這個task里只能有他自己一個Activity,如果他啟動了另一個Activity,那個Activity會根據(jù)啟動模式來啟動并裝進一個不同的task里。其他的方面,singleInstance和singleTask一樣的。
其他三個方式允許有多個Activity在一個task里,一個singleTask屬性的Activity總是一個task里的root Activity,但是他可以啟動另外的Activity并且將這個新的Activity裝進同一個task里,standard和singleTop屬性的Activity可以出現(xiàn)在task的任何地方。
(4)一個類(Activity)的對象是否可以被啟動來處理一個新的Intent。
對默認的standard方式,會實例化一個對象來處理每一個新的Intent,每個實例處理一個新的Intent,對singleTop方式,如果一個已經(jīng)存在的實例是在task的棧頂,那么就重用這個實例來處理這個新的Intent,如果這個實例不在棧頂,那就不復(fù)用他,而是重新創(chuàng)建一個實例來處理這個新的Intent并且將這個實例壓入堆棧。
例如現(xiàn)在有一個task堆棧ABCD,A是root Activity,D是棧頂Activity,現(xiàn)在有一個啟動D的Intent來了,如果D是默認的standard方法,那么就會創(chuàng)建一個新的實例來處理這個Intent,所以這個堆棧就變?yōu)锳BCDD,然而如果D是singleTop方式,這個已經(jīng)存在的棧頂?shù)腄就會來處理這個Intent,所以堆棧還是ABCD。D此時調(diào)用onNewIntent(),此時D可以調(diào)用getIntent()來獲得最初的Intent,或者調(diào)用setIntent()來更新這個Intent。
如果現(xiàn)在有一個Intent來啟動B,不管B是standard還是singleTop(因為現(xiàn)在B不在棧頂),都會創(chuàng)建一個新的實例,所以堆棧變?yōu)锳BCDB
在一個task里,對singleTask和singleInstance屬性的Activity只能有一個實例。所以這僅有的一個會來處理所以的Intent,一個singleInstance屬性Activity總在棧頂(因為task里就只有他一個Activity),所以他會處理所以的Intent,但是一個singleTask屬性的Activity必須是task的root Activity(也就是必須在棧底),不能確定他的上面是否還有其他的Activity,如果沒有,就可以處理,如果還有其他的Activity,那么如果現(xiàn)在有一個Intent來啟動這個singleTask屬性的Activity,這個Intent將會被丟掉(即使是這個Intent被丟掉,他的到來還是會導(dǎo)致這個task回到前臺)。
當創(chuàng)建一個類(Activity)的實例來處理一個新的Intent時,用戶可以按下BACK鍵回到上一個Activity,但是如果是用已經(jīng)存在的棧頂?shù)腁ctivity來處理Intent的話,按下BACK鍵是不能回到以前的狀態(tài)的(沒處理這個Intent之前)。
7、清理堆棧
當用戶離開一個task一段時間后,系統(tǒng)就會清理掉task里出了rootActivity以外的Activity,如果用戶又回來了,顯示的是rootActivity,就像是用戶離開又回來,是放棄以前的東西,開始新的東西。
上面說的是默認的情況,有一些Activity的屬性可以用來控制和修改這些行為。
alwaysRetainTaskState
如果一個task里的root Activity的alwaysRetainTaskState屬性設(shè)置為true,那么前面描述的默認情況就不會出現(xiàn)了,task即使過了一段時間也會一直保留所有的Activity。
clearTaskOnLaunch
如果一個task里的root Activity的clearTaskOnLaunch屬性設(shè)置為true,和alwaysRetainTaskState相反,即使是一瞬間的離開,系統(tǒng)馬上就會清理掉task里出rootActivity以外的所有Activity。
finishOnTaskLaunch
這個屬性和clearTaskOnLaunch一樣,但是他是對一個Activity起作用,不是整個task,他能引起所有的Activity離開,包括root Activity,當這個屬性設(shè)置為true,只是當用戶使用這個應(yīng)用時Activity才在task里,一旦用戶離開后重新回來,顯示的不是當前的界面。
還有其他的方法來從task里強制移動Activity,如果一個Intent對象里包含F(xiàn)LAG_ACTIVITY_CLEAR_TOP標志,并且目標task里已經(jīng)一個在自己task里可以處理Intent的Activity(就是處理這個Intent無需實例化另外一個Activity),那么在這個Activity之上的所有Activity將被清除,能處理這個Intent的Activity就移到棧頂來處理這個Intent,例如ABCD堆棧,含有FLAG_ACTIVITY_CLEAR_TOP標志的Intent來啟動B,那么清除CD,B到達棧頂來響應(yīng)Intent,此時是AB,如果B設(shè)置了standard屬性,那么還是清楚CD,然后再創(chuàng)建一個實例來響應(yīng)Intent,此時是ABB,因為standard屬性的Activity總是創(chuàng)建一個新的實例來響應(yīng)新的Intent。
8、進程和線程(Processes and Threads)
當一個應(yīng)用的第一個組件需要運行時,android系統(tǒng)就為這個組件啟動一個只有一個線程的Linux進程,默認的,應(yīng)用的所有組件都運行這個進程中的這個線程中。
但是,你可以安排組件運行在其他的進程中,并且為你的任意的進程增加若干線程。
1、 進程
組件運行的進程是在manifest文件里控制的,四大組件都一個process屬性可以指定進程來運行,這些屬性可以被設(shè)置為了每個組件都可以運行在他自己的進程中,或者幾個組件共享一個進程,或者不共享,如果兩個應(yīng)用共享一個Linux user ID并且有相同的權(quán)限,那么就可以使這兩個應(yīng)用中的組件運行在相同的進程中,
所有的組件都在指定的進程中的主線程中實例化,系統(tǒng)調(diào)用這些組件就是從主線程里發(fā)出的,其他的線程將不會對每個組件再實例化,所有作為調(diào)用的回應(yīng)的這些方法,比如說View.onKeyDown()還是組件的生命周期函數(shù)等等都是運行在這個主線程中的,這就意味著當系統(tǒng)調(diào)用這個組件時,這個組件不能長時間的阻塞線程(比如說網(wǎng)絡(luò)操作,循環(huán)計算),因為這樣會阻塞這個進程中的其他組件,你可以將很耗時的任務(wù)分到其他的線程中。
當內(nèi)存不足或者有其他更緊急的進程要求時,Android系統(tǒng)可能關(guān)閉一個進程,運行在這個進程中的應(yīng)用組件因此被銷毀,當用戶又重新回來時,進程才被重新啟動。
至于究竟要停止哪個進程,android系統(tǒng)是通過衡量哪個進程對用戶來說更重要來實現(xiàn)的
2、 線程
你可以限制你的應(yīng)用運行在一個進程中,但是有的時候你需要新開一個線程在后臺運行,用戶界面需要隨時對用戶的要求做出反應(yīng),所以一些很耗時的工作應(yīng)該重新啟動一個線程來做,以免阻塞主進程。
Android系統(tǒng)提供了一系列方便的類來管理線程(Looper,Handler,HandlerThread)
3、 遠程調(diào)用(Remote procedure calls)
Android系統(tǒng)有一個輕量級的遠程調(diào)用機制(RPC)-----一個方法在本地調(diào)用,但是在遠程執(zhí)行(在另外一個進程里),返回給調(diào)用端的所有結(jié)果都必須的系統(tǒng)能理解的,將數(shù)據(jù)從本地進程和地址空間傳遞到遠程的進程和地址空間,并在遠端重新裝配,返回值的時候傳輸方向相反,android系統(tǒng)會去做這些傳輸?shù)墓ぷ?,讓你能夠集中精力來定義你的RPC
一個RPC接口只能包含方法,默認的,即使是沒有值返回,所有的方法都是同步執(zhí)行的,就是說本地方法一直會阻塞直到遠端的方法執(zhí)行完畢)。
簡單的說,這個遠程調(diào)用的機制是這樣工作的:
首先你需要用IDL(interface definition language)聲明你的RPC接口,然后android系統(tǒng)會使用aidl工具來形成一個java接口,并且這個java接口是本地進程和遠端進程都可以獲得的,這個java接口包含了兩個內(nèi)部類,請看下圖:
這兩個內(nèi)部類有管理遠程調(diào)用(你用IDL聲明的接口)的所以代碼,兩個內(nèi)部類都實現(xiàn)IBinder接口,一個是在本地(內(nèi)部)使用,這個你可以不用自己寫代碼,另外一個叫做Stub,繼承自Binder類的,包含所有完成進程間通信(IPC)的代碼,他包含你在RPC接口中聲明的所有方法,你應(yīng)該繼續(xù)繼承Stub類來實現(xiàn)這些方法。
一般的,遠端進程應(yīng)該由一個service來管理(因為一個service能通知系統(tǒng)關(guān)于這個進程和他連接到的其他進程)。
9、進程的生命周期(Processes and lifecycles)
Android系統(tǒng)總是盡最大的努力來維持一個應(yīng)用的進程,但系統(tǒng)的內(nèi)存不足時就可能需要關(guān)閉一些舊的進程了,但是決定關(guān)閉哪個進程呢,android系統(tǒng)把所以的進程放進一個重要性樹里,最低重要性的進程將會被停止,系統(tǒng)有5種重要性等級,重要性從高到低如下:
(1)、前臺進程。一個前臺進程是當前執(zhí)行用戶請求的進程,如果有如下的一種情形的那么他就是前臺進程:
a、這個進程里運行著一個正在和用戶交互的Activity(這個Activity的onResume()方法被調(diào)用)。
b、這個進程里有綁定到當前正在和用戶交互的Activity的一個service
c、這個進程里有一個service對象,這個service對象執(zhí)行了至少一個他生命周期的函數(shù)(onCreate(), onStart(), or onDestroy()).
d、這個進程里有一個執(zhí)行了onReceive()方法的broadcastreceiver對象
只有一定數(shù)量的前臺進程在任何時間都存在,他們只有在最后的時刻被停止---系統(tǒng)的內(nèi)存太少了而不能運行這些僅有的前臺進程了),一般的,在那個時刻,手機會重新設(shè)置內(nèi)存頁的狀態(tài),所以停止一些前臺的進程是為了保持對用戶操作的快速響應(yīng)。
(2)可見進程。一個可見進程一個沒有任何前臺顯示的組件,但是仍然可以影響到用戶當前屏幕所看見的東西,如果有如下的一種情形那么他就是可見進程。
a、 這個進程里一個Activity,但是這個Activity當前不是在前臺顯示,但是仍然對用戶是可見的(這個Activity的onPause()方法被調(diào)用),比如說一個Activity調(diào)用一個dialog,那么這個dialog是當前顯示的組件,這個Activity不是在前臺顯示,但是對用戶是可見的。
b、 這個進程里有一個綁定到一個可見Activity(如上所述的Activity)的service
一個可見進程是極端重要的,只有在為了顯示所有前臺進程時,即顯示前臺進程都不夠時,才會停止可見進程。
(3)、服務(wù)進程。一個服務(wù)進程是一個通過startService()啟動的但是沒有在前兩個分類中的進程,雖然服務(wù)進程不是用戶直接能看見的,但是他也總是做一些用戶很關(guān)心的事(如在后臺播放mp3,從網(wǎng)絡(luò)上下載東西),所以系統(tǒng)會一直保持服務(wù)進程運行,除非內(nèi)存不足以運行服務(wù)進程,前臺進程,可見進程。
(4)后臺進程。一個后臺進程是運行一個當前對用戶是不可見的Activity(這個Activity的onStop()被調(diào)用),這些進程對用戶體驗沒有什么直接的影響,當內(nèi)存不足以運行前臺進程,可見進程,服務(wù)進程時,可以隨時停止后臺進程,通常有很多的后臺進程在運行,系統(tǒng)會把這些后臺進程放進一個LRU中(最近使用隊列),最近使用的就最后停止。
(5)空進程。一個空進程就是進程里沒有任何活動的應(yīng)用組件,維持這種進程的唯一原因就是作為一種緩存,當一個組件需要啟動時加快啟動的速度,系統(tǒng)為了平衡進程緩存和核心緩存會停止這些空的進程。
Android系統(tǒng)會取一個進程里的所以組件的最高重要性來安排進程的重要性,比如說,一個進程里有一個service和一個可見的Activity,那么這個進程會被安排成一個可見進程,而不是服務(wù)進程。
另外,一個進程的重要性有可能會因為其他進程的依賴而升高,一個進程不能比他所服務(wù)的進程的重要性低,比如有進程A里的service綁定到了進程B的組件上,那么進程A的重要性至少和進程B的一樣,或者更高。
因為一個服務(wù)進程的重要性比運行一個后臺Activity的進程高,所以,當一個Activity做一些長時間運行的任務(wù)時,最好啟動一個service來做,而不是放到一個線程里去做,特別是這個任務(wù)的時間可能比Activity運行的時間還長的時候,比如在后臺播放音樂,或者上傳一張圖片到網(wǎng)上,使用一個service保證了這個任務(wù)至少是服務(wù)進程的重要性,broadcast receiver也是一樣,長時間運行的任務(wù)也最好是放到一個service里,而不是放到一個線程里。
原文標題:Android 應(yīng)用程序基礎(chǔ)(Application Fundamentals)
鏈接:http://www.cnblogs.com/TerryBlog/archive/2010/07/12/1775624.html
【編輯推薦】