標籤:
組件生命週期(一)
引言
應用程式組件有一個生命週期——一開始Android執行個體化他們響應意圖,直到結束執行個體被銷毀。在這期間,他們有時候處於啟用狀態,有時候處於非啟用狀態;對於活動,對使用者有時候可見,有時候不可見。組件生命週期將討論活動、服務、廣播接收者的生命週期——包括在生命週期中他們可能的狀態、通知狀態改變的方法、及這些狀態的組件寄宿的進程被終結和執行個體被銷毀的可能性。
本文主要討論活動的生命週期及他們可能的狀態、通知狀態改變的方法。分為以下三部分:
1、活動生命週期
一個活動有三個基本狀態:
- 啟用狀態或運行狀態,這時它運行在螢幕的前台(處於當前任務活動棧的最上面)。這個活動有使用者的操作的焦點。
- 暫停狀態,這時活動失去焦點但是它對使用者仍可見。也就是說,另一個活動在它的上面且那個活動是透明的或者沒有覆蓋整個螢幕,因此通過它可以看見暫停狀態的活動。一個暫停活動完全是活著的(它維護著所有的狀態和成員資訊,且仍然依附在視窗管理器),但是當記憶體極小時可以被系統殺掉。
- 停止狀態,這時活動完全被其他活動掩蓋。它仍然保留所有狀態和成員資訊,但是對使用者它不可見,因此它的視窗時隱藏的且當其他地方需要記憶體時它往往被系統殺掉。
如果一個活動被暫停或停止,系統可以將它從記憶體移除,通過要求它結束(通過調用它的finish()方法),或簡單地殺掉它的進程。當它再次顯示給使用者時,必須要完全重新啟動和恢複到之前的狀態。隨著活動從一個狀態轉為另一個狀態,通過調用下面的受保護的方法通知該改變:
- void onCreate(Bundle saveInstanceState)
- void onStart()
- void onRestart()
- void onResume()
- void onPause()
- void onStop()
- void onDestroy()
所有這些方法都是鉤子,你可以重寫當狀態改變時做適當的工作。所有的活動必須要實現onCreate()去做一些初始化的設定,當對象第一次執行個體化的時候。很多活動也會實現onPause()去提交資料修改或準備停止與使用者互動。
將他們合并在一起,這七個方法定義了活動的整個生命週期。有三個嵌套的迴圈,你可以通過這七個方法監視:
- 活動的整個生命時間,從第一次調用onCreate()開始直到調用onDestroy()結束。一個活動在onCreate()中做所有的“全域”狀態的初始設定,在onDestroy()中釋放所有保留的資源。舉例來說,有一個線程運行在後台從網路上下載資料,它可能會在onCreate()中建立線程,在onDestroy()中結束線程。
- 活動的可視生命時間,從調用onStart()到相應的調用onStop() 。在這期間,使用者可以在螢幕上看見活動,雖然它可能不是運行在前台且與使用者互動。在這兩個方法之間,你可以保持顯示活動所需要的資源。舉例來說,你可以在onStart()中註冊一個廣播接收者監視影響你的UI的改變,在onStop() 中登出。因為活動在可視和隱藏之間來回切換,onStart()和onStop() 可以調用多次。
- 活動的前台生命時間,從調用onResume()到相應的調用onPause()。在這期間,頻繁地在重用和暫停狀態轉換——例如,當裝置進入睡眠狀態或一個新的活動啟動時調用onPause(),當一個活動返回或一個新的意圖被傳輸時調用onResume()。因此,這兩個方法的代碼應當是相當輕量級的。
下面這個圖解釋了這三個迴圈和狀態之間狀態的可能路徑。著色的橢圓表示活動的主要狀態,矩形表示當活動在狀態之間轉換時你可以執行的回調方法。
圖1、活動生命週期(來源:Android SDK)
下面的表格對每個方法更詳細的描述和在活動的整個生命週期中的定位。
注意上面表格的Killable列,它表示當方法返回時沒有執行活動的其它代碼,系統是否能殺死活動寄宿的進程。三個方法(onPause()、onStop()、onDestroy())標記為Yes。因為onPause()是唯一一個保證在進程被殺之前會調用的,因此你應該使用onPause()來寫任何持久化儲存資料。
被標記為No的方法保護活動寄宿的進程在他們調用的時候不會被殺掉。因此活動是可殺掉狀態,例如onPause()返回到onResume()調用期間。直到onPause()再次返回,活動是不可殺掉的。其實,沒有標記為Killable的活動也是可以系統被殺掉的,不過這僅僅發生在極端困難的情況下,沒有有任何其他資源可用。
2、儲存活動狀態
當系統而不是使用者關閉一個活動來節省記憶體時,使用者可能希望返回到活動且是它之前的狀態。為了獲得活動被殺之前的狀態,你可以執行活動的onSaveInstanceState()方法。Android在活動容易被銷毀前調用這個方法,也就是調用onPause()之前。該方法的參數是一個Bundle對象,在這個對象你可以以名值對記錄活動的動態狀態。當活動再次啟動時,Bundle同時被傳遞到onCreate()和調用onCreate()之後的方法,onRestoreInstanceState(),因此使用一個或兩個可以重新建立捕獲的狀態。
因為onSaveInstanceState()方法不總是被調用,你應該僅使用onSaveInstanceState()它來記錄活動的臨時狀態,而不是持久的資料。應該使用onPause()來儲存持久資料。
3、協調活動
當一個活動啟動另一個活動,他們都經曆生命週期轉換。一個暫停或許是停止,然而另一個啟動。有時,你可能需要協調這些活動。生命週期的回調順序是明確界定的,特別是當這兩個活動在同一個進程中:
- 當前活動的onPause()方法被調用。
- 接下來,啟動活動的onCreate()、onStart()、onResume()方法按序被調用。
- 然後,如果獲得不再在螢幕上可見,它的onStop()方法被調用。
修正:第一節——活動生命週期中的表格第一、二行中的第二列(description)中的onRestart()應該為onStart()。
1000多的點擊,居然沒有人發現這個錯誤,看了大家根本就沒認真看或者說根本沒有靜心看園子裡的任何博文,心痛!還是水帖比較受歡迎。
組件生命週期(二)
引言
應用程式組件有一個生命週期——一開始Android執行個體化他們響應意圖,直到結束執行個體被銷毀。在這期間,他們有時候處於啟用狀態,有時候處於非啟用狀態;對於活動,對使用者有時候可見,有時候不可見。組件生命週期將討論活動、服務、廣播接收者的生命週期——包括在生命週期中他們可能的狀態、通知狀態改變的方法、及這些狀態的組件寄宿的進程被終結和執行個體被銷毀的可能性。
上篇Android開發之旅:組件生命週期(一)講解了論活動的生命週期及他們可能的狀態、通知狀態改變的方法。本篇將介紹服務和廣播接收者的生命週期:
1、服務生命週期
一個服務可以用在兩個方面:
- 它可以啟動且允許一直運行直到有人停止它,或者它自己停止。在這種模式,通過調用Context.startService()啟動服務及通過調用Context.stopService()停止服務。服務也可以通過調用Service.stopSelf()或Service.stopSelfResult()停止自己。僅需要調用一次stopService()停止服務,而不管調用startService()了多少次。
- 通過使用相關介面可以編程地操作服務。用戶端建立與Service對象的一個串連及使用該串連調入服務。串連通過調用Context.bindService()建立,通過調用Context.unbindService()關閉。多個用戶端可以綁定到同一個服務。如果服務尚未啟動,bindService()可以選擇啟動它。
這兩種模式並不是完全分離的。你可以綁定到一個用startService()啟動的服務。例如,一個後台音樂服務可以通過使用定義了音樂播放的Intent對象調用startService()啟動。直到後來,使用者可能想對播放器做一些控制或者擷取當前歌曲的一些資訊,一個活動將調用bindService()與服務建立串連。在這種情況下,實際上直到最後一個綁定關閉stopService()並不會停止。
像活動一樣,一個服務也有生命週期方法,你可以執行監視它的狀態改變。但是比活動的生命週期方法更少,只有三個且它們是公有的(public)而不是受保護的(protected)(說明:活動的生命週期方法是protected的):
- void onCreate()
- void onStart(Intent intent)
- void onDestory()
通過這三個方法,你可以監視服務生命週期的兩個嵌套迴圈:
- 服務的整個生命時間(entire lifetime),從調用onCreate()到相應地調用onDestory()。像一個活動一樣,服務在onCreate()中做一些初始設定,且在中釋放所有的資源。例如,一個音樂播放服務可以在onCreate()中建立線程,然後在onDestory()中停止線程。
- 服務的活躍生命時間(active lifetime),從調用onStart()開始。這個方法傳遞參數是傳送給startService()的Intent對象。音樂服務將開啟Intent,瞭解播放哪個音樂並且開始播放。
沒有相應的回調方法,因為服務停止沒有onStop()方法。
startService()和onDestory()被所有服務調用,不管是通過Context.startService()啟動還是通過Context.bindService()啟動的。然而,onStart()僅被通過startService()啟動的服務調用。
如果一個服務允許別的綁定到它,有一些額外的回調方法來實現它:
- IBinder onBind(Intent intent)
- boolean onUnbind(Intent intent)
- void onRebind(Intent intent)
onBind()回調傳遞的參數是傳給bindService()的Intent對象,onUnbind()回調傳遞的參數是傳給unbindService()的Intent對象。如果服務允許綁定,onBind()返回用戶端與服務互動的通訊通道。onUnbind()方法可以要求調用onRebind(),如果一個新的用戶端串連到服務。
解釋了服務的回調方法。雖然,它分離了由startService()啟動的服務和由bindService()啟動的服務,記住任何服務,無論它怎麼啟動的,都可能允許用戶端綁定到它,因此任何服務可能接收onBind()和onUnbind()調用。
2、廣播接收者生命週期
一個廣播接收者有一個回調方法:void onReceive(Context curContext, Intent broadcastMsg)。當一個廣播訊息到達接收者是,Android調用它的onReceive()方法並傳遞給它包含訊息的Intent對象。廣播接收者被認為僅當它執行這個方法時是活躍的。當onReceive()返回後,它是不活躍的。
有一個活躍的廣播接收者的進程是受保護的,不會被殺死。但是系統可以在任何時候殺死僅有不活躍組件的進程,當佔用的記憶體別的進程需要時。
這帶來一個問題,當一個廣播訊息的響應時費時的,因此應該在獨立的線程中做這些事,遠離使用者介面其它組件啟動並執行主線程。如果onReceive()衍生線程然後返回,整個進程,包括新的線程,被判定為不活躍的(除非進程中的其它應用程式組件是活躍的),將使它處於被殺的危機。解決這個問題的方法是onReceive()啟動一個服務,及時服務做這個工作,因此系統知道進程中有活躍的工作在做。
組件生命週期(三)
Android系統試圖儘可能長地保持一個應用程式進程,但是當記憶體低時它最終還是需要移除舊的進程。為了決定保持哪個進程及殺死哪個進程,Android將每個進程放入一個基於運行於其中的組件的重要性等級和這些組件的狀態。重要性最低的進程首先被殺死,然後是次低,以此類推。總共有5個層次等級。下列清單按重要性順序列出:
- 前台進程,使用者當前工作所需要的。一個進程如果滿足下列任何條件被認為是前台進程:
- 它正運行著一個正在與使用者互動的活動(Activity對象的onResume()方法已經被調用)。
- 它寄宿了一個服務,該服務與一個與使用者互動的活動綁定。
- 它有一個Service對象執行它的生命週期回調(onCreate()、onStart()、onDestroy())。
- 它有一個BroadcastReceiver對象執行他的onReceive()方法。
在給定時間內僅有少數的前台進程存在。僅作為最後採取的措施他們才會被殺掉——如果記憶體太低以至於他們不能繼續運行。一般來說,就在那時,裝置達到一個記憶體???狀態,因此殺掉某些前台進程以保持使用者介面響應。
- 可視進程,他沒有任何前台組件,但是仍然能影響使用者在螢幕上看到東西。一個進程滿足下面任何一個條件都被認為是可視的:
- 它寄宿著一個不是前台的活動,但是它對使用者仍可見(它的onPause()方法已經被調用)。舉例來說,這可能發送在,如果一個前台活動是一個對話方塊且運行之前的活動在其後面仍可視。
- 它寄宿著一個服務,該服務綁定到一個可視的活動。
一個可視進程被認為是及其重要的且不會被殺死,除非為了保持前台進程運行。
- 服務進程,是一個運行著一個用startService()方法啟動的服務,並且該服務並沒有落入上面2種分類。雖然服務進程沒有直接關係到任何使用者可見的,它們通常做使用者關心的事(諸如在背景播放mp3或者從網路上下載資料),因此系統保持它們運行,除非沒有足夠記憶體隨著所有的前台進程和可視進程保持它們。
- 後台進程,是一個保持著一個當前對使用者不可視的活動(已經調用Activity對象的onStop()方法)。這些進程沒有直接影響使用者體驗,並且可以在任何時候被殺以收回記憶體用於一個前台、可視、服務進程。一般地有很多後台進程運行著,因此它們保持在一個LRU(least recently used,即最近最少使用,如果您學過作業系統的話會覺得它很熟悉,跟記憶體的頁面置換演算法LRU一樣。)列表以確保最近使用最多的活動的進程最後被殺。如果一個活動執行正確地執行它的生命週期方法,且捕獲它當前的狀態,殺掉它對使用者的體驗沒有有害的影響。
- 空進程,是一個沒有保持活躍的應用程式組件的進程。保持這個進程可用的唯一原因是作為一個cache以提高下次啟動組件的速度。系統進程殺死這些進程,以在進程cache和潛在的核心cache之間平衡整個系統資源。
Android把進程標記為它可以的最進階,即進程中活躍的組件中重要性最高的那個(選取重要性最高的那個作為進程的重要性層級)。例如,有一個進程寄宿著一個服務和一個可視活動,進程的層級被設定為可視進程層級,而不是服務進程層級(因為可視進程層級比服務進程層級高)。
此外,一個進程的排名因為其他進程依賴它而上升。一個進程服務其它進程,它的排名從不會比它服務的進程低。例如,進程A中的一個內容提供者服務進程B中的一個客戶,或者進程A中的一個服務綁定到進程B中的一個組件,進程A總是被認為比進程B重要。
因為一個運行一個服務進程排名比一個運行後台活動的進程排名高,一個活動啟動一個服務來初始化一個長時間運行操作,而不是簡單地衍生一個線程——特別是如果操作很可能會拖垮活動。這方面的例子是在背景播放音樂和上傳相機拍攝的圖片到一個網站。使用服務保證操作至少有“服務進程”的優先順序,無論活動發生什麼情況。
【轉】Android開發之旅:組件生命週期