今天對於Activity的生命周期又有了一點深入的理解。做個總結吧。
一、正常情況下的生命周期
什么叫正常情況下的生命周期呢?也就是我們經常了解的一個活動的正常的生命流程。不用過度解釋,
總結如下:
(1)onCreate()方法
活動第一次創建時被調用。
(2)onStart()
活動由不可見變為可見的時候調用
(3)onResume()
當活動准備開始與用戶交互時會觸發該方法,一般只會在需要執行以下的操作時才重寫該事件:
l 開始動畫
l 開始監聽GPS更新
l 顯示一些相關的提示和對話框
l 注冊廣播監聽
(4)onPause()
系統准備去啟動或者恢復另外一個活動的時候調用。或者當活動被切換到后台時將觸發該方法,一般我們需要在該事件做如下的事情:
l 保存用戶未提交的數據
l 關閉或清除引用的資源
l 注銷廣播
l 如果存在正在顯示的提示或者對話框,則必須利用.Dismiss()進行清除。
(5)onStop()
當該活動完全不可見的時候被調用。一般會由以下原因觸發:
l 當一個新的活動打開,並覆蓋該活動時
l 一個已存在的活動切換到前台時
l 活動被銷毀時
OnStop不是每次都會被執行,如果內存低下時,系統將不會執行該事件,而是直接關閉該應用,所以大家在OnPause事件中就要保存好所以的參數等等。而不能依賴該事件。
(6)onDestroy()
活動銷毀之前被調用
(7)onRestart()
當活動由停止狀態變為運行狀態時被調用。即當用戶通過Home按鈕將該用戶切換到后台,並在之后又打開該應用則會觸發該事件。一般也很少重寫該方法。
貼一張大家都知道的流程圖吧,如下:


需要極其注意的是:在onPause中執行的操作不能太耗時!
二、異常情況下活動的生命周期
這個是重點要說的!什么是異常情況呢?不好說,比如因為資源相關的配置發生改變或者系統內存不足時,活動就
會被殺死。這就屬於異常情況,總之一句話:活動被異常終止!最常見的就是下面的兩種情況:
(1)橫屏或者豎屏切換時。此時因為切換之間系統要對活動中的布局里面的圖片進行更換(比如你可能會准備同樣的兩張
圖片,不同像素寬高,分別對應於橫屏或者豎屏的情況),此時就會導致在切換時,活動被瞬間殺死又被瞬間重建!
(2)因為系統內存不足,活動被回收時。
發生意外終止,系統做出的對策就是會將活動中的數據進行自動保存,然后再需要的時候再將活動創建出來恢復數據。
因此,對應的生命周期如下圖:

也就是說在發生意外時,系統會自動調用onSaveInstanceState方法來保存數據,在需要的時候再會重新創建出這個活動,
然后自動調用onRestoreInstanceState方法來恢復數據。你可能會有疑問,一個活動中可能有一個TextView,還有一個按鈕,
可能還有其他的,那么當活動意外終止,怎么來控制保存這些控件的數據呢?其實任何一個view都重寫了onSaveInstanceState
和onRestoreInstanceState方法,你可以翻看源碼,看看發生意外時,每一個view都會自動保存什么。這里不再多說。
上面列出的兩種意外情況下的活動的生命周期是一樣的,都是如上圖所示。系統內存不足,不好模擬。但是橫屏和豎屏
比較好模擬。下面我們通過一個實際例子,來看看是不是真的如上面所述的那樣。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
新建一個項目。修改其Manifest文件,加入橫豎和豎屏切換的感應,如下:
<activity android:name=".MainActivity" android:label="@string/app_name" android:screenOrientation="sensor" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
上面只貼出了修改的那段代碼,黃色部分就是加入的自動切換橫屏和豎屏的功能。
下面再修改其MainActivity代碼,如下:
1 public class MainActivity extends ActionBarActivity { 2 3 private static final String Tag = "MainActivity"; 4 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.activity_main); 9 10 if(savedInstanceState != null) 11 { 12 String t = savedInstanceState.getString("save_test"); 13 Log.e(Tag,t+" "+"onCreate"); 14 } 15 16 } 17 18 @Override 19 protected void onSaveInstanceState(Bundle outState) { 20 super.onSaveInstanceState(outState); 21 22 String t = "save me "; 23 Log.e(Tag,t+"onSaveInstanceState"); 24 outState.putString("save_test",t); 25 } 26 27 @Override 28 protected void onRestoreInstanceState(Bundle savedInstanceState) { 29 super.onRestoreInstanceState(savedInstanceState); 30 31 String t = savedInstanceState.getString("save_test"); 32 Log.e(Tag,t+" "+"onRestoreInstanceState"); 33 } 34 35 36 }
代碼中重寫了onSaveInstanceState和onResoreInstanceState方法,然后就在各個方法中打印標簽。
下面運行一下程序,做如下的操作:

也就是控制手機,做了一個橫豎和豎屏的切換。我們來看一下打印結果,如下:

通過打印結果,就會發現在橫屏和豎屏切換時,確實是調用了保存數據和恢復數據的那些方法。而從再一次
調用了onCreate方法,就知道活動被重建了。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
接着上面的分析,有沒有方法讓在橫豎和豎屏切換時,不要重新創建活動呢??當然是肯定的。
其實很簡單,只要在Manifest文件中加入configChanges屬性即可。也就是當檢測到confiChanges指定
的屬性發生改變時,也不會再去重新創建活動了。
下面我們就修改代碼,來測試一下。首先修改Manifest中的代碼,如下:
<activity android:name=".MainActivity" android:label="@string/app_name" android:screenOrientation="sensor" android:configChanges="orientation|screenSize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
可以看到,添加了一句(即黃色部分),即檢測到方向發生改變或者屏幕的size改變,也不去重新創建活動。
這針對的就是橫屏和豎屏的切換。
然后修改MainActivity中的代碼,如下:
1 public class MainActivity extends ActionBarActivity { 2 3 private static final String Tag = "MainActivity"; 4 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.activity_main); 9 10 if(savedInstanceState != null) 11 { 12 String t = savedInstanceState.getString("save_test"); 13 Log.e(Tag,t+" "+"onCreate"); 14 } 15 16 } 17 18 @Override 19 protected void onSaveInstanceState(Bundle outState) { 20 super.onSaveInstanceState(outState); 21 22 String t = "save me "; 23 Log.e(Tag,t+"onSaveInstanceState"); 24 outState.putString("save_test",t); 25 } 26 27 @Override 28 protected void onRestoreInstanceState(Bundle savedInstanceState) { 29 super.onRestoreInstanceState(savedInstanceState); 30 31 String t = savedInstanceState.getString("save_test"); 32 Log.e(Tag,t+" "+"onRestoreInstanceState"); 33 } 34 35 @Override 36 public void onConfigurationChanged(Configuration newConfig) { 37 super.onConfigurationChanged(newConfig); 38 Log.e(Tag,"onConfigurationChanged"); 39 } 40 }
黃色部分是我們新增加的代碼。然后運行程序,依然做一個橫屏豎屏的切換操作,打印結果如下:

我們這次只有onConfiguration這一個方法被調用。onSaveInstanceState方法和onRestoreInstanceState方法
都沒有被調用,onCreate方法也沒有,即沒有再重新創建活動了。這提示我們,如果在橫豎屏切換過程中,還想做一些
邏輯操作的話,可以放在onConfiguration方法中。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
總結:(1)系統只在異常終止了Activity時,才會調用onSaveInstanceState和onRestoreInstanceState方法
來恢復數據。因此我們可以重寫這兩個方法來防止活動被出現意外終止時,數據發生丟失。
(2)如果使用了在Manifest文件中加入configChanges屬性來監測發生變化時不再重新創建活動,那么
onConfiguration方法會被自動回調,我們可以在這里實現相關邏輯。
(3)就是上面的兩張圖,一個正常活動生命周期的圖,一個異常下活動生命周期的圖。
