博客逐步遷移至 極客兔兔的小站html
接下來將介紹 Android Activity(四大組件之一) 的生命週期, 包含運行、暫停和中止三種狀態,onCreate、onStart、onResume、onPause、onStop、onDestroy六種系統調用方法。java
如圖所示,Activity實例能夠在生命週期狀態發生關鍵性轉換時完成某些工做。android
- onCreate()
建立
,該方法是最常被覆蓋的方法,第一次建立實例時調用, 通常用來完成實例建立的初始化操做,包括實例化組件,設置監聽器,訪問外部模型數據等。- onStart()
開始
,當Activity處於可見狀態的時候就會調用onStart方法,包括建立完實例顯示,或者從其餘活動切換到活動時調用。- onResume()
準備
,當Activity得到用戶焦點時調用。- onPause
暫停
,當Activity準備調用或者恢復另外一個活動時調用,失去焦點時,例如啓動一個Dialog調用。該方法能夠釋放一些消耗CPU的資源,保存一些關鍵數據,可是執行速度要快,不然影響新的棧頂活動使用。- onStop
中止
,徹底不可見時調用。例如成功啓動了另一個活動,該活動離開棧頂不可見。啓動Dialog不會執行該方法。- onDestroy
銷燬
,這個方法在活動銷燬時調用。
// 可使用如下方法進行測試。 public class MainActivity extends Activity { private String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(TAG,"Create"); } @Override protected void onStart() { super.onStart(); Log.d(TAG, "Start"); } @Override protected void onResume() { super.onResume(); Log.d(TAG, "Resume"); } @Override protected void onPause() { super.onPause(); Log.d(TAG, "Pause"); } @Override protected void onStop() { super.onStop(); Log.d(TAG, "Stop"); } @Override protected void onDestroy() { super.onDestroy(); Log.d(TAG, "Destroy"); } }
使用上面的日誌打印測試方法發現, 設備旋轉時生命週期如圖所示,即設備旋轉時,當前活動實例會被系統銷燬,而後建立一個新的實例。ide
由於旋轉設備會改變設備配置(device configuration),設備配置包括屏幕的方向、密度、尺寸、鍵盤類型、底座模式等,爲匹配不一樣的設備,可使用不一樣的佈局文件,這和Web開發中 針對不一樣寬度的屏幕選擇不一樣CSS樣式殊途同歸,如何建立不一樣佈局適配不一樣配置設備不在本文討論之列。佈局
設備旋轉時,臨時數據會丟失。例如你使用了一個變量記錄了用戶點擊了多少次按鈕,設備旋轉以後,Activity從新建立,這個變量就被初始化了,這裏可使用Bundle
對象來恢復。保存數據能夠覆蓋onSaveInstanceState()
方法。測試
例以下面的代碼,按3次按鈕,旋轉屏幕後,將打印出saved currentPage:3 init mCurrentPage:0,點擊次數存在了Bundle對象中,並在onCreate()中獲取到。3d
/* * onSaveInstanceState()一般在onPause、onStop、onDestroy前由系統調用 * onCreate()傳入的參數savedInstanceState可獲取保存的變量 */ public class MainActivity extends Activity { private static final String KEY = "currentPage"; private static final String TAG = "MainActivity"; private Integer mCurrentPage = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mCurrentPage += 1; } }); if(savedInstanceState != null){ // 打印使用Bundle保存的currentPage信息 Log.d(TAG,"saved currentPage: " + savedInstanceState.getInt(KEY,0)); // 打印新建活動mCurrentPage的值,總爲0 Log.d(TAG,"init mCurrentPage: " + mCurrentPage); // ... update code } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // 使用key-value對的方式存儲臨時變量 outState.putInt(KEY, mCurrentPage); } }
當系統回收內存時,處於Pause、Stop狀態的Activity可能被銷燬,此時系統會調用onSaveInstanceState(),用戶數據被存儲在Bundle對象中,系統將Bundle對象放入Activity記錄,能夠將這種狀態理解爲Activity的暫存狀態(無實例有記錄)。日誌
Activity暫存後,當前活動不復存在,Activity記錄可幫助用戶返回應用時活動的快速恢復,提供一個好的用戶體驗。可是當用戶按了後退鍵,系統會完全銷燬當前活動,Activity記錄同時被清除,系統重啓也會被清除該記錄。code
standard是活動默認的啓動模式,Android是使用返回棧來管理活動的,所謂棧就是先進後出,後進先出。該模式下,每啓動一個新的活動,就會在返回棧中入棧,並處於棧頂的位置(即用戶當前見到的活動)。系統不會 檢查該活動的實例已經在返回棧中存在,每次啓動都新建一個。當前返回棧爲A->B(B爲棧頂),新建活動B, 返回棧變爲A->B->B。xml
standard模式有時並不合理,好比活動實例已經在棧頂了,再次啓動時還需再建立一個實例, 這會形成資源的浪費。singleTop模式下,若是當前棧頂已是該活動實例,則認爲能夠直接使用,而再也不建立新的活動。當前返回棧爲A->B(B爲棧頂),新建活動B, 返回棧仍爲A->B。
<!--AndroidManifest.xml--> <!--設置方式,launchMode --> <activity android:name=".MainActivity" android:launchMode="singleTop" android:label="AndroidDialog"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity>
singleTop模式能夠避免重複建立棧頂活動的問題,可是若是啓動活動不在棧頂,而以前已經建立過,仍是會重複建立。例如A->B->C,當前已有三個活動A、B、C,C位於棧頂,再建立B,返回棧變爲A->B->C->B(另外一個實例)。singleTask模式可讓返回棧中每一個活動只存在一個實例,若是發現當前須要啓動活動已經在棧中,則直接使用,可是該活動之上的全部活動所有出棧;如沒有發現,則建立新的實例。例如A->B->C,如此時建立活動B,則返回棧變爲A->B(B存在,使用B,C出棧);若此時建立活動D,則返回棧變爲A->B->C->D
singleInstance模式是四種啓動模式中最複雜的,不一樣於上述三種模式,指定爲singleInstance模式的活動會啓動一個新的返回棧來管理這個活動。例如當前有活動A、B、C,活動A、C爲默認啓動模式,B指定爲singleInstance模式,首先新建A,A活動頁面啓動B,B啓動C,此時的返回棧並非A->B->C,而是存在2個返回棧,一個是A->C,另外一個是B。此時按下BACK鍵返回,將從C返回到A,再按一次,A返回到B,按第三次,程序退出。即返回時,先清空棧A->C,再清空棧B。 singleInstance模式有什麼應用場景呢?例如當前程序中某個活動容許其餘活動調用,若是想多個程序共享該活動的一個實例A,那麼每個程序都有一個返回棧,若使用前3種模式,該活動入棧時必然建立新的實例,沒法實現實例共享。singleInstance能很好地解決這個問題。