1. 程式人生 > >Android學習筆記2-生命週期

Android學習筆記2-生命週期

元件的生命週期

 

應用程式元件都有一個生命週期,從響應Intent的Android例項開始到這個例項被銷燬。在這期間,他們或許有效或許無效,有效時或許對使用者可見或許不可見。下面我們就來討論四個基本元件的生命週期,包括在生命週期內的各種狀態,以及狀態之間的轉換。這幾種狀態可能的結果是:程序讓他們停止, 然後例項被銷燬。

 

activity生命週期

 

一個activity有三個基本的狀態:

 

@ 當activity在前臺執行時(在activity當前任務的堆疊頂),為活動或者執行狀態。這時activity會響應使用者的操作。

@ 當activity失去焦點但是對使用者仍然可見時為paused暫停狀態。此時,別的activity在他的上面,透明或者備有被全部覆蓋。所以其中一些暫停的activity也可以被顯示。一個暫停的activity是處於活動狀態的(他維護著所有的狀態儲存著資訊,並且依然附著在視窗管理器)。

@ 如果一個activity完全被另一個activity所掩蓋那他會處於stop狀態。但仍然儲存著原來的狀態和資訊。然而,如果別的地方需要更多的記憶體而且這個activity仍一直處於隱藏狀態,那麼系統有可能會殺死他的程序。

 

如果一個activity是暫停或者停止狀態,系統可以清理他們佔用的記憶體,或者呼叫finish()方法,或者直接結束他的程序。當他再次顯示給使用者時,會完全的重新執行並且載入以前所儲存的資訊。

 

activity狀態之間的轉換,是通過以前的受保護方法完成的:

 

void onCreate(Bundle savedInstanceState) 

void onStart() 

void onRestart() 

void onResume() 

void onPause() 

void onStop() 

void onDestroy()

 

這些都是鉤子函式,你可以重寫他們,當狀態改變時做一些適當的處理。所有的activity在首次執行時必須實現onCreate()方法來初始化安裝。activity可以實現onPause()來提交資料改變,然後準備停止與使用者的互動。

 

呼叫超類

 

每一個實現的activity生命週期方法都會先呼叫一下父類的方法,例如:

[java]  view plain copy
  1. protected void onPause() {  
  2.     super.onPause();  
  3.     . . .  
  4. }  
 

 

通過這兩者比較?,這7個方法定義了一個activity的整個生命週期的方法。你可以實現並且監測這三個巢狀迴圈:

 

@ 整個生命週期

呼叫onCreate()方法和onDestroy()之間稱為一個activity的完整的生命週期。activity會在onCreate()裡執行所有的初始化安裝,在onDestroy()方法裡釋放所有的剩餘資源。例如:一個從網路下載程式的執行緒,就需要在onCreate()方法裡建立,在onDestroy()方法裡銷燬。

 

@ 可見生命週期

可見生命週期是從onStart()方法到onStop()方法的時間。這段時間,使用者會在螢幕上看到這個activity。儘管他可能不是在最頂層顯示,也沒有和使用者進行任何互動。這兩個方法之間,你可以保持需要向用戶顯示的資源。例如:你可以在onStart()方法時註冊一個BroadcastReceiver檢測某些變化來改變你的介面,當用戶看不到這個activity的介面時可以在onStop()裡登出這個BroadcastReceiver。這兩個方法可以被呼叫很多次,在可見和對使用者隱藏時,作為候補的activity待命。

 

@ 前臺顯示週期

一個activity從onResume()方法指導一個onPause()方法稱為前臺顯示週期。此時他在其他的activity之上顯示並且與使用者互動。一個activity可以頻繁的在這兩個方法之間過度,例如:當裝置休眠或者另一個新的activity啟動時,它會進入onPause()狀態,當一個activity執行結束或者新的接收到Intent請求時,activity的onResume()會被呼叫。因此,這兩個方法裡的程式碼量會很少。

 

下圖說明了上面說的幾個迴圈,裡面的箭頭說明了兩個狀態之間是否可以相互轉換。有色的橢圓是activity主要的幾個狀態。正方形和長方形代表activity在狀態之間轉變時我們可以實現的一些回撥方法。

 

 

注意killable這列,它指明瞭程序在呼叫方法返回後是否可以被系統殺死,而不執行其他的程式碼。onPause(), onStop(), and onDestroy()這三個方法可以,因為onPause方法首先被執行,他是唯一一個一定會被呼叫的方法當程序被殺死時,但是onStop()和onDestroy()方法不會。因此,你可以在onPause()方法裡儲存一些連續的資料,例如編輯。

 

killable這列被標記成no的方法,保護activity防止他們被呼叫時,被程序殺死。例如:一個activity是處於可被殺死的狀態,當activity從onPause()方法跳轉到onResume()方法時,在OnPause方法回撥之前是不會被殺死的。

 

正如後面的章節:程序和生命週期,一個沒有定義為“killable”的activity仍然可以被系統結束,但這時會發生在特殊情況下,比如沒有其他資源時。

 

儲存activity的狀態

 

當系統(而不是使用者)關閉一個activity來節省記憶體時,使用者希望再次啟動activity時會回到當時的狀態。

 

為了在activity被殺死之前捕獲他的狀態,你可以實現 onSaveInstanceState()方法,Android會在一個activity將要被關閉時呼叫這個方法,也就是在onPause()方法之前。他回傳遞給方法一個Bandle物件,你可以用key-value的方式儲存你的資料。當activity再次執行時。這個Bandle物件會傳遞給onCreate()方法、onStart()方法、onRestoreInstanceState()方法。這幾個方法都能重建當時的activity狀態。

 

不像onPause()和剛才討論的其他幾個方法,onSaveInstanceState()和onRestoreInstanceState()方法不是生命週期方法。不是不是總被呼叫。例如:Android在activity將要被系統銷燬之前呼叫onSaveInstanceState()方法,當activity例項被使用者的操作銷燬時(例如按下Back鍵),是不會呼叫這個方法的。這種情況下沒有理由儲存他的狀態。

 

Coordinating activities

 

當一個activity啟動了另一個activity,他們都經歷了生命週期的轉換。一個暫停了或者結束了,其他的activity啟動。一種情況你可能需要調節這些activity:

生命週期方法的回撥順序都是定義好的,尤其當兩個activity在同一程序下:

 

1.當前執行的activity的onPause()方法被呼叫。

2.然後將要執行的activity的onCreate()、onStart()、onResume()方法被依次呼叫。

3.然後,如果將要執行的activity不太可見,那麼onstop()方法會被呼叫。


service生命週期

 

service生命週期一般有兩種使用方式。

 

@ service可以被啟動或者允許被啟動知道有人停止了他或者他自己停止了。在這種模式下,他通過Context.startService()方法開始,通過Context.stopService()方法停止。他可以通過Service.stopSelf()方法或者Service.stopSelfResult()方法來停止自己。只要呼叫一次stopService()方法便可以停止服務,無論呼叫了多少次的啟動服務方法。

 

@ 他可以通過定義好的介面來程式設計,客戶端建立一個與Service的連結,並使用此連結與Service進行通話。通過Context.bindService()方法來繫結服務,Context.unbindService()方法來關閉服務。多個客戶端可以繫結同一個服務。如果Service還未被啟動,bindService()方法可以啟動服務。

 

這兩種模式是完全獨立的。你可以繫結一個已經通過startService()方法啟動的服務。例如:一個後臺播放音樂服務可以通過startService()和一個intend物件來播放音樂。可能使用者在播放過程中要執行一些操作比如獲取歌曲的一些資訊,此時activity可以通過呼叫bindServices()方法與Service建立連線。這種情況下,stopServices()方法實際上不會停止服務,直到最後一次繫結關閉。

像一個activity那樣,一個service有些可以用來改變狀態的生命週期方法。但是比activity的方法少,service生命週期方法只有三個,而且都是public修飾。

void onCreate() 

void onStart(Intent intent) 
void onDestroy()

通過實現這三個生命週期方法,你可以監聽service的兩個巢狀迴圈的生命週期(?):


@ 整個生命週期

service的整個生命週期是在onCreate()和onDestroy()方法之間。和activity一樣,在onCreate()方法裡初始化,在onDestroy()方法裡釋放資源。例如,一個背景音樂播放服務可以在onCreate()方法裡播放,在onDestroy()方法裡停止。

 

@活動的生命週期

service的活動生命週期是在onStart()之後,這個發法會處理通過startServices()方法傳遞來的Intent物件。音樂service可以通過開打intent物件來找到要播放的音樂,然後開始後臺播放。

service停止時沒有相應的回撥方法,即沒有onStop()方法。

 

onCreate()方法和onDestroy()方法是針對所有的services,無論他們是否啟動。通過Context.startService()和Context.bindService()方法。然而,只有通過startService()方法啟動的service才會被呼叫onStart()方法。如果一個service允許別人繫結,那麼需要實現以下額外的方法:

 

IBinder onBind(Intent intent) 

boolean onUnbind(Intent intent) 

void onRebind(Intent intent)

 

onBind()回撥方法會繼續傳遞通過bindService()傳遞來的intent對像。onUnbind()會處理傳遞給unbindService()的intent物件。如果service允許繫結,onBind()會返回客戶端與服務互相聯絡的通訊頻道。如果建立了一個新的客戶端與服務的連結,onUnbind()方法可以請求呼叫onRebind()方法。

 

下面的圖表介紹了service的回撥方法,然而,他把通過startService()方法建立的服務從通過bindService()方法建立的服務分離開。

記住任何服務,無果它怎樣建立,都預設客戶端可以連結,所以任何的service能夠接收onBind()和onUnbind()方法。

 

 

Broadcast生命週期

 

Broadcast的生命週期只有一個回撥方法:

void onReceive(Context curContext,Intent broadcastMsg)

 

當broadcast訊息到達接收者時,Android會呼叫他的onReceive()方法,並且傳遞包含這個資訊的intent物件。broadcast接收者在執行這個方法時,被認為是活動的。當onReceive()方法返回時,它停止的活動狀態。

 

一個活動的廣播接受者程序是不能被殺死的,但是當他所消耗的記憶體被別的程序需要時,一個非活動狀態的程序可以被系統隨時殺死。

 

這帶來一個問題,相應一個廣播訊息是非常耗時的,因此,很多事情需要在一個獨立的執行緒中執行,而不是在主執行緒裡。如果onReceive()方法啟動一個執行緒,那麼整個程序包括剛啟動的新執行緒,是非活動狀態的,(除非程序裡其他應用程式元件有活動的),所以有被系統銷燬的危險。這個問題的解決方法是在onReceive()方法裡啟動一個服務然後處理一些事情,所以系統會知道在這個程序裡仍然有處於活動狀態的任務需要被處理。

 

下一節會有更多的弱程序將會被銷燬。

 

 程序和宣告週期

android作業系統嘗試儘可能長時間的保持應用的程序,但當可用記憶體很低時最終要移走一部分程序。怎樣確定那些程式可以執行,那些要被銷燬,Android讓每一個程序在一個重要級的基礎上執行,重要級低的程序最有可能被淘汰,一共有5級,下面這個列表就是按照重要性排列的:

1

前臺程序顯示的是使用者此時需要處理和顯示的。下列的條件有任何一個成立,這個程序都被認為是在前臺執行的。

@ 與使用者正發生互動的。

@ 它控制一個與使用者互動的必須的基本的服務。

@ 有一個正在呼叫生命週期的回撥函式的service(如onCreate()、onStar()、onDestroy())

@ 它有一個正在執行onReceive()方法的廣播接收物件。

只有少數的前臺程序可以在任何給定的時間內執行,銷燬他們是系統萬不得已的、最後的選擇——當記憶體不夠系統繼續執行下去時。通常,在這一點上,裝置已經達到了記憶體分頁狀態,所以殺掉一些前臺程序來保證能夠響應使用者的需求。

2

一個可用程序沒有任何前臺元件,但它仍然可以影響到使用者的介面。下面兩種情況發生時,可以稱該程序為可用程序。

@ 它是一個非前臺的activity,但對使用者仍然可用,(onPause()方法已經被呼叫)。這是可能發生的,例如:前臺的activity是一個允許上一個activity可見的對話方塊,即當前activity半透明,能看到前一個activity的介面。

@ 它是一個服務於可用activity的服務。

3

一個服務程序是一個通過呼叫startService()方法啟動的服務,並且不屬於前兩種情況。儘管服務程序沒有直接被使用者看到,但他們確實是使用者所關心的,比如後臺播放音樂或網路下載資料。所以系統保證他們的執行,直到不能保證所有的前臺可見程式都正常執行時才會終止他們。

4

一個後臺程序就是一個非當前正在執行的activity(activity的onStop()方法已經被呼叫),他們不會對使用者體驗造成直接的影響,當沒有足夠記憶體來執行前臺可見程式時,他們將會被終止。通常,後臺程序會有很多個在執行,所以他們維護一個LRU最近使用程式列表來保證經常執行的activity能最後一個被終止。如果一個activity正確的實現了生命週期的方法,並且儲存它當前狀態,殺死這些程序將不會影響到使用者體驗。

5

一個空執行緒沒有執行任何可用應用程式組,保留他們的唯一原因是為了設立一個快取機制,來加快元件啟動的時間。系統經常殺死這些記憶體來平衡系統的整個系統的資源,程序快取和基本核心快取之間的資源。

Android把程序裡優先順序最高的activity或服務,作為這個程序的優先順序。例如,一個程序擁有一個服務和一個可見的activity,那麼這個程序將會被定義為可見程序,而不是服務程序。

此外,如果別的程序依賴某一個程序的話,那麼被依賴的程序會提高優先順序。一個程序服務於另一個程序,那麼提供服務的程序不會低於獲得服務的程序。例如,如果程序A的一個內容提供商服務於程序B的一個客戶端,或者程序A的一個service被程序B的一個元件繫結,那麼程序A至少擁有和程序B一樣的優先順序,或者更高。

因為一個執行服務的程序的優先順序高於執行後臺activity的程序,一個activity會準備一個長時間執行的操作來啟動一個服務,而不是啟動一個執行緒--尤其是這個操作可能會拖垮這個activity。例如後臺播放音樂的同時,通過照相機向伺服器傳送一張照片。啟動一個服務會保證這個操作至少執行在service 程序的優先順序下,無論這個activity發生了什麼。就想前面章節提到的那樣,廣播接收者應該作為一個空服務而不是簡單的把耗時的操作單獨放在一個執行緒裡。