《Android藝術開發探索》學習筆記之Activity的生命週期

鋸齒流沙發表於2017-12-26

《Android開發藝術探索》這本書真心不錯,是非常不錯的Android開發的進階書籍,內容深入淺出,推薦大家看一下。

Android藝術開發探索.png

上圖就是Activity生命週期切換過程圖。

正常情況下,Activity會經歷以下的生命週期:

1)onCreate:Activity正在被建立,在這方法中做一些初始化的工作。

2)onRestart:Activity正在重新啟動,呼叫情況:噹噹前的Activity從不可見重新變為可見狀態時被呼叫,如使用者按下home鍵,接著又回到該Activity。

3)onStart:Acitivity正在被啟動,即將開始,這是Activity可見,但還沒有出現在前臺,無法與使用者互動,使用者看不到。

4)onResume:Activity已經可見並且出現在前臺,可以與使用者互動。注意和OnStart的區別,onStart和onResume都可見,但onStart在後臺,onResume在前臺。

5)onPause:Activity正在停止,在此方法中可以做一些資料儲存、停止動畫等工作,但是注意不能太耗時,因為會影響到新Activity的顯示,先執行完onPause,才執行新Activity的onResume方法。

6)onStop:Activity即將停止,可做一些稍微重量級的回收工作,但不能太耗時。

7)onDestroy:Activity生命週期最後一個方法,Activity即將被銷燬,可做一些回收工作和最終的資源釋放。

Activity生命週期的附加說明

1)針對一個特定的Activity,第一次啟動,回撥:onCreate—>onStart—>onResume

Android開發藝術探索筆記.png

2)當使用者開啟新的Activity或者切換到桌面時,回撥:onPause—>onStop。特殊情況:新Acitivity採用透明主題,則當前Activity不會回撥onStop;

Android開發藝術探索筆記.png

3)當使用者再次回到原Activity時,回撥:onRestart—>onStart—>onResume;

Android開發藝術探索筆記.png

4)當使用者按back鍵回退時,回撥:onPause—>onStop—>onDestroy;

Android開發藝術探索筆記.png

5)當Activity被系統回收後再次開啟,生命週期方法回撥過程跟(1)的一樣,這是生命週期方法一樣,不代表所有過程一樣。

6)從整個生命週期來說,onCreate和onDestroy時配對的,即Activity的建立和銷燬,並且只有可能一次呼叫,從Activity是否可見來說,onStart和onStop是配對的,從Activity是否在前臺來說,onResume和onPause是配對的,隨著使用者操作或者裝置螢幕的點亮和熄滅,onStart、onStop、onResume和onPause可能被多次呼叫。

異常情況下,Activity的生命週期

1、資源相關的系統配置發生改變導致Activity被殺死並重新建立,比如橫屏手機和豎屏手機切換。

預設情況下,Activity不做特殊處理,那麼當系統配置發生改變後,Activity就會被銷燬並重新建立,其生命週期如下:

Android開發藝術探索筆記.png

可以看到被銷燬時,系統會呼叫onSaveInstanceState方法儲存當前的Activity狀態,這個方法在onStop之前呼叫,但是和onPause沒有既定的時序關係。 當被重新建立時,系統會呼叫onRestoreInstanceState,並且把銷燬時在onSaveInstanceState方法所儲存的bundle物件作為引數同時傳遞給onRestoreInstanceState和onCreate方法,我們通過這兩個方法判斷Activity是否被重新建立,如果重建了,就利用取出並資料並且恢復,onRestoreInstanceState在onStart之後被呼叫。

在onSaveInstanceState和onRestoreInstanceState方法中,系統會自動幫我們做一些恢復的工作,如當前Activity的檢視結構:例如文字框中使用者輸入的資料,listview滾動的位置等等。

系統儲存和恢復的工作流程:activity被意外終止時,呼叫onSaveInstanceState儲存資料,然後activity會委託window去儲存資料,接著window再委託它上面的頂級容器去儲存資料。頂級容器是一個ViewGroup,很有可能是DecorView。最後頂級容器再一一通知子元素來儲存資料,這樣子整個資料儲存過程就完成了。這是一種典型的委託思想,上層委託下層,父容器委託子元素去處理一件事情。

2、資源記憶體不足導致低優先順序的Activity被殺死。

Activity按照優先順序分為三種: 1)前臺Activity——正在和使用者互動的Activity,優先順序別最高。

2)可見但非前臺Activity——比如Activity彈出一個對話方塊,導致Activity可見但是位於後臺無法和使用者互動。

3)後臺Activity——已經被暫停的Activity,比如執行了onStop,優先順序最低。

當記憶體不足時,系統會按照上述優先順序殺死目標的Activity所在的程式。並且通過onSaveInstanceState和onRestoreInstanceState來儲存和恢復資料。如果一個程式沒有四大元件在執行就容易被系統殺死,因此,一些後臺工作不適合脫離四大元件而獨自執行在後臺,比較好的方法就是後臺工作放入Service中從而保證程式有一定的優先順序,這樣不容易被系統殺死。

防止Activity因系統配置發生改變而重新建立:

android:configChanges="orientation"
複製程式碼

具體可以參考表格

Android開發藝術探索筆記.png

Activity的啟動模式

1)standard:標準模式,即預設模式,每次啟動一個Activity都會建立一個Activity例項,不管這個例項是否存在。這是一種多例項實現,一個任務棧可以建立多個例項,每個例項也可以屬於不同的任務棧,誰啟動了這個Activity,那麼這個Activity就會執行在啟動它的那個Activity所在的任務棧。

2)singleTop:棧頂複用模式,即如果新的Activity已經位於任務棧的棧頂,那麼此Activity不會被重新建立,同時它的onNewIntent方法被回撥,通過此方法的引數我們可以取出當前請求的資訊,但此Activity的onCreate、onStart不會被系統呼叫,因為他們並沒有發生改變。

3)singleTask:棧內複用模式,這是一種單例項模式,在此模式下,只要Activity存在於任務棧中,啟動此Activity就不會重新被建立例項,和singleTop一樣,系統會回撥其onNewIntent方法。

例子:任務棧S1、S2 1、S1:ABC 啟動 D ,D屬於S2, 建立S2,D加入S2

2、S1:ABC 啟動D,D屬於S1 則S1:ABCD

3、S1:ADBC 啟動D, D屬於S1 則S1:AD

4)singleInstance:單例項模式,這是一種加強的singleTask模式,除了具有singleTask模式的特性外,還加強了一點:具有此模式的Activity只能單獨位於一個任務棧中。比如:Activity A是singleInstance模式,當A啟動後,系統為它建立新的任務棧,然後A獨自在新的任務棧中,由於棧內複用的特性,後續的請求均不會建立新的Activity,除非系統銷燬此任務棧。

Activity的Flags

Activity的Flags,即標誌位,作用很多,有的標誌位可以設定Activity的啟動模式。

常用的標誌位:

FLAG_ACTIVITY_NEW_TASK

指定Activity的啟動模式為:singleTask

FLAG_ACTIVITY_SINGLE_TOP

指定Activity的啟動模式為:singleTop

FLAG_ACTIVITY_CLEAR_TOP

具體此標誌位的Activity,當啟動它時,在同一個任務棧中所有位於上面的Activity都要出棧,這個模式一般需要和FLAG_ACTIVITY_NEW_TASK配合使用。

FLAG_ACTIVITY_EXCLUDE_FROM_ RECENTS

具有這個標記的Activity不會出現在歷史的Activity列表中,當某些情況下我們不希望使用者通過歷史列表回到我們的Activity的時候這個標記比較有用。它等同於在XML中指定Activity的屬性android:excludeFromRcents = "true"。

IntentFilter的匹配規則

啟動Activity方式:顯式和隱式。

顯式呼叫:明確指定被啟動物件的元件資訊,包括包名和類名。 隱式呼叫:不需要明確指定元件資訊,需要Intent能夠匹配目標元件的IntentFilter中所設定的過濾資訊,如果不匹配則無法啟動目標元件Activity。IntentFilter中過濾的資訊有action、category、data。

<activity android:name=".IntentFilterActivity">
            <intent-filter>
                <action android:name="com.uipro.action.c"/>
                <action android:name="com.uipro.action.d"/>
                <category android:name="com.uipro.category.a"/>
                <category android:name="com.uipro.category.b"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:mimeType="text/plain"/>
            </intent-filter>
        </activity>
複製程式碼

為了匹配過濾列表,同時需要過濾列表中的action、category、data資訊,否則匹配失敗。一個過濾列表中action、category、data可以有多個,所有的action、category、data分別構成不同的類別,同一類別的資訊共同約束當前類別的匹配過程。只有一個Intent同時匹配action類別,category類別,data類別才算完全匹配,只有完全匹配才能成功啟動目標Activity。另外,Activity可以有多個IntentFilter,一個Intent只有能匹配任何一組的IntentFilter即可成功啟動對應的Activity。

1、action匹配規則

action是一個字串,系統預定義了一些action,同時也可以在應用中定義自己的action。action的匹配規則是Intent中的action必須能夠和過濾規則中的action匹配,這裡說的匹配是指action的字串值完全一樣。一個過濾規則中可以有多個action,只要Intent中的action能夠和過濾規則中的任何一個action相同即可匹配成功。action區分大小寫。

2、category的匹配規則

category是一個字串,系統預定義了一些category,同時也可以定義自己的category。

匹配規則:category要求Intent中如果含有category,那麼所有的category都必須和過濾規則中的其中一個category相同,換句話說,Intent中如果出現了category,不過有幾個category,對於每個category來說,它必須是過濾規則中已經定義l的category。當然Intent中可以沒有category,如果沒有category,按照上面的描述,這個Intent仍然匹配成功。

和action區別:action要求Intent中必須有一個action且必須能夠和過濾規則中的某個action相同;category要求Intent中可以沒有category,但是如果一旦有category,不管幾個 ,每個都要能夠和過濾規則中的任何一個category相同。

不設定category也能匹配成功的原因:系統在呼叫startActivity或者startActivityForResult的時候預設為Intent加上android:intent.category.DEFAULT這個category,所以這個category就可以匹配前面的過濾規則中的第三個category。同時過濾規則中就必須指定android:intent.category.DEFAULT

3、data的匹配規則

data的匹配規則和action類似,如果過濾規則中定義了data,那麼Intent中也必須要定義可匹配的data。data的語法定義如下:

Android開發藝術探索筆記.png

mimeType:媒體型別,如:image/jpeg,video/*,可以表示圖片、文字、視訊等不同的媒體格式。

URI結構:

Android開發藝術探索筆記.png

Android開發藝術探索筆記.png

Scheme:URI模式,比如http、file、content等。如果URI沒有指定scheme,則URI無效。

Host:URI主機名,比如www.baidu.com。如果不指定Host,URI無效。

Port:URI的埠號,比如80,當且僅當URI指定了scheme和host之後才有意義。

Path、pathPattern和pathfix:都是指路徑資訊,path表示完整路徑資訊,pathPattern也是表示完整路徑,但可包含萬用字元,pathfix表示路徑的字首資訊。

注意:如果Intent指定完整的data,必須呼叫setDataAndType方法,不能先呼叫setData,然後呼叫setType,因為這兩個方法彼此會清楚對方的值。

原始碼可知:

Android開發藝術探索筆記.png

Android開發藝術探索筆記.png

相關文章