1. 程式人生 > >Android 四大元件之---Activity 詳解

Android 四大元件之---Activity 詳解

Android Activity生命週期詳解

1. 什麼是Activity?

  1. Activity作為Android四大元件之一,它有著舉足輕重的地位,每一個Activity都會獲得一個用於繪製其使用者介面的視窗,Activity是一個view物件的容器,通過Window類的setContentView()方法新增到Activity上,最終提供與使用者互動的介面;
  2. Activity是上下文物件 Context的子類, 並且實現了Window.callback,KeyEvent.callback 這兩個介面,因此 Activity 可以響應和處理使用者與視窗的互動事件,以及鍵盤相關的輸入事件;
  3. 一個Android應用通常由一個或者多個Activity 組成;如果是多個Activity,一般會指定應用中的某個 Activity 為“主” Activity,即首次啟動應用時呈現給使用者的那個 Activity。 而且每個Activity 通過使用Intent(意圖)均可啟動另一個Activity,這裡使用的是IPC機制。 每次啟動一個新的Activity 啟動時,前一 Activity 便會停止,但系統會在回退桟中保留該 Activity,而新啟動的Activity可以放如該棧頂也可以設定其啟動方式放入新的回退桟,這就和Activity四種啟動方式有關了。

附上一張圖,對Activity有一個更直觀和全面的認識:
這裡寫圖片描述

對Activity有了一個比較直觀的認識後,我們自然想到的是怎麼使用它,其實對於Activity google對其封裝的還是挺厲害,開發者使用時主要就是繼承Activity,通過setContentView()方法設定佈局介面,然後重寫它的幾個生命週期函式;而跳轉新的Acitivty更簡單,通過一個Intent然後呼叫startActivity方法即可;

2. Activity生命週期

其實對於Activity最重要的就是搞清楚它的各個生命週期函式,只有這樣我們才能知道Activity在各個生命週期階段需要做什麼事,那些事不適合做,這對於編寫高質量的App是至關重要的;

Activity是通過回退桟來管理的,此時Activity可呈現出四種狀態:
(1) 當Activity位於回退棧桟頂時,此時將顯示在螢幕上,使用者可與之互動,此時Activity處於執行狀態


(2) 當Activity失去了焦點但依然可見(如棧頂Activity尺寸小沒有完全覆蓋螢幕,或者棧頂Activity是透明的),此時Activity處於暫停狀態
(3) 當Activity被新的Activity或者應用完全遮住(新Activity不透明),因此Activity已經對使用者不可見,此時Activity處於停止狀態
(4) 當Activity被完全退出或者App程序完全退出時,Activity將會回撥onDestory方法,之後Activity將被銷燬,Activity將處於銷燬狀態

下面我們主要闡述Activity的生命週期:
同樣我們先附上圖(來自Android官方文件):
這裡寫圖片描述

1. 首先對Activity主要生命週期函式做介紹:

(1) onCreate

Activity生命週期的第一個方法,表示Activity正在被建立,在該方法中通過setContentView 方法載入xml編寫的佈局檔案,然後通過findByViewId方法獲取控制元件;
onCreate()方法在Activity整個生命週期中只會呼叫一次,所以該方法中就可以做一些大致只需要做一次的工作,如:一些變數的初始化,資源的載入,初始化控制元件以及事件的繫結等;
由於此時view還沒有加載出來,因此該方法中不能開啟動畫的;

注:onCreate()的官方文件註釋,建議 setContentView()、findViewById() 在 onCreate() 中呼叫,但在onStart()中呼叫 setContentView()、findViewById() 功能也是正常的,只是不建議,並且很少會這樣做;

(2) onStart

Activity正在啟動,此時Activity已經看見,但是沒有展現在前臺,沒有獲取到焦點,當然也就不能與使用者互動;
因為該方法是Activity重新回到前臺時第一個回撥的方法,因此在該方法裡我們可以去檢查某些必須的系統特性是否可用,比如網路是否在連線, GPS是否開啟等類似的功能;
該方法中我們通常初始化一些變數,當然這些變數必須是在Activity處於前臺的時候才能夠被響應;

(3) onResume

Activity可見可互動;
如果Activity是重新開啟,此時就需要在該方法中重新例項化在onPause()中釋放的資源;
初始化在前臺顯示時需要的資源,如:動畫、播放視訊,此外建議在onResume()中開啟獨佔裝置,比如相機,之所以在該方法中開啟是因為當開啟新的Activity時,首先會onPause掉舊Activity,然後在onCreate, onStart, onResume新Activity,如果之前舊Activity已經打開了獨佔裝置(相機), 那此時onPause舊Activity時就可以釋放掉獨佔裝置(相機),那麼開啟的新Activity就能夠使用獨佔裝置(相機)了;

(4) onPause

Activity已經暫停,可見但不在前臺,因此也不可互動;
該方法中需要持久化使用者資料、停止動畫,暫停正在播放的視訊等不太耗時的操作;
釋放部分佔用的系統資源(尤其是獨佔裝置),如:相機, GPS等,設定有時會讓該Activity斷開網路連線,因為這些工作會大幅度佔用系統資源,增加電耗或者流量消耗;
因為開啟新的Activity前回去回撥舊Activity的onPause方法,因此onPause方法中不能做太耗時的操作(如,資料庫讀寫,IO操作),否則調新的 Activity 在切換時可能會出現卡頓現象,這是使用者不想看到的;
耗時的清理工作應該放在onStop方法中;

(5) onStop

Activity即將停止,此時當然不可見;
耗時的清理工作應該放在onStop方法中;
Activity 在此狀態時仍然存在於記憶體中,如果在系統記憶體不夠時,系統接下來很快會銷燬掉該Activity,在極端情況下,直接 kill Activity 且不執行onDestroy()函式。所以務必在onStop()函式中就清理掉可能引起記憶體洩露的資源,當然更極端的時系統記憶體已嚴重不足,導致系統無法保留該程序的情況下,onStop() 可能都不會被執行;

(6) onDestory

Activity即將被銷燬,
很多情況下 Activity 是不需要定義這個函式,因為在onPause()和onStop()中,大多數的清理工作都已經完成了。但是,如果在onCreate()中定義了後臺執行緒,或者可能引起記憶體洩露的程式碼,那就需要在onDestroy()中清理,如,靜態物件持有其他Activity的引用,廣播登出等操作;

(7) onRestart

Activity正在被重新啟動
在原Activity沒有銷燬時重新要回到該Activity時會回撥該方法,緊接著會回撥onStart方法,一般在該方法中恢復使用者資料;

其實Activity生命週期函式可以看成是成對的,onCreate和onDestory成對,onStart和onStop成對,onResume和onPause成對,這在上述每個回撥函式的介紹中也可以看出來
這裡寫圖片描述

2. 下面闡述幾種比較常見的情況:

(1) 單個A Activity啟動回撥流程

 onCreate
 onStart
 onResume

(2) 當用戶按下home鍵時

 onPause
 onStop

(3) 當用戶再次回到原Activity時

 onRestart
 onStart
 onResume

(4) 在A Activity的基礎上,開啟新的B Activity,此時需要注意的問題是B Activity的大小和透明度

 a. B Activity完全覆蓋A Activity,並且B Activity是不透明的:
  A Activity: onPause
  B Activity: onCreate –> on Start –> onResume
  A Activity : onStop

 b. B Activity因為尺寸小沒有完全覆蓋A Activity,或者B Activity是透明的, 此時A Activity的onStop方法是不會被執行的
  A Activity: onPause
  B Activity: onCreate –> on Start –> onResume

(5) 當用戶按back鍵時

 onPause
 onStop
 onDestory

(6). 橫豎屏切換時 Activity 的生命週期

此時的生命週期跟清單檔案裡的配置有關係。
1.不設定 Activity 的 android:configChanges 時,切屏會重新呼叫各個生命週期預設首先銷燬當前 activity,然後重新載入。

2.設定 Activity android:configChanges=”orientation|keyboardHidden|screenSize”時,切屏不會重新呼叫各個生命週期,只會執行 onConfigurationChanged 方法。

3. 儲存 Activity 的狀態

Activity 的狀態通常情況下系統會自動儲存,只有當我們需要儲存額外的資料時才需要使用到這樣的功能。
通常呼叫了 onPause()onStop()方法後的 Activity 例項仍然存在於記憶體中, 此時Activity 的資訊和狀態資料不會丟失, 當activity 重新回到前臺之後, 會重新恢復到之前的裝填; 但是當系統記憶體不足時, 呼叫 onPause()onStop()方法後的 Activity很可能會被系統銷燬, 此時記憶體中就不會存有該Activity的例項了, 如果此時再讓這個 Activity 回到前臺, 它只能重新啟動, 執行onCreate(0,onStart()onResume()`方法, 之前Activity的改變
全部丟失 。

這種情況是我們不想看到的, 怎麼樣避免發生呢 , 我們可以覆寫 onSaveInstanceState() 方法;
onSaveInstanceState()方法接受一個 Bundle 型別的引數, 開發者可以將狀態資料儲存到這個Bundle物件中, 這樣即使Activity被系統摧毀, 當用戶重新啟動這個Activity會呼叫它的onCreate()方法時, 我們可以在onCreate()方法中拿到這個 Bundle 物件, 從而取出之前儲存的Activity資料, 然後利用這些資料將 activity 恢復到被摧毀之前的狀態。

需要注意的是, onSaveInstanceState()方法並不是一定會被呼叫的, 因為有些場景是不需要儲存狀態資料的. 比如使用者按下 BACK 鍵退出 activity 時, 使用者顯然想要關閉這個 activity, 此時是沒有必要儲存資料 以供下次恢復的, 也就是 onSaveInstanceState()方法不會被呼叫. 如果 呼叫onSaveInstanceState()方法, 呼叫將發生在 onPause()或 onStop()方法之前。

4. 如何在APP退出的時候結束所有的Activity

大致有以下方法可以參考使用:

1. 傳送特定廣播
1. 在需要結束應用時,傳送一個特定的廣播,每個 Activity 收到廣播後,關閉;

2. 遞迴退出
在開啟新的 Activity 時使用 startActivityForResult,然後自己加標誌,在 onActivityResult 中處理,遞迴關閉。

3. 其實也可以通過 intent 的 flag 來實現 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
啟用一個新的 Activity。此時如果該任務棧中已經有該 Activity,那麼系統會把這個 Activity 上面的所有 Activity 幹掉。其實相當於給 Activity 配置的啟動模式為 SingleTop
 
 
如有錯誤,歡迎指正,謝謝!