最近想寫篇關於Activity啟動過程源碼分析的博客,在此之前先總結下Android中Activity必須要知道的一些基礎知識,以方便後面能看懂Activity的源碼。
一,Activity生命周期和啟動模式
activity最經典的啟動模式圖如下:
它分為onCreate--onStart--onResume--onPause--onStop--onDestory.這幾個階段,這個是個android開發者肯定都很熟悉,這裡不詳細說,只是說下一些注意事項:
1.onStart和onStop的區別:onStart表示應用己經可見,但只運行在後台,沒到前台。onStop表示acitvity運行在後台。當用戶使用透明主題,不會調用onstop.
2.onResume和onpause的區別:這兩個是從activity是否位於前台來回調的,是一組。
3.當新Activity啟動之前,棧頂acitivity需要先onPause新的再啟動。所以不能在onpause中做耗時操作。
4.當activity異常停止時,會調用onSaveInstanceState,並把所保存的Bundle傳遞給onRestoreInstanceState,onRestoreInstanceState是在onStart之後被調用。過程是onSaveInstanceState先保存數據,Activity會委托Window保存數據,接著Window再委托上面的頂級容器去保存,一直往上委托直到DecorView,最後它再一一通知它的子元素來保存數據。典型的委托思想。
如果onRestoreInstanceState被調用 ,那它的onSaveInstanceState參數一定有值。
5.在資源不足情況下導致的activity被殺死也會調用onSaveInstanceState。activity有三個優先級:
* 前台activity。
* 可見但非前台activity(如Dialog)
* 後台activity(onstop的情況)。
二,啟動模式
1.啟動模式介紹:
android有四種模式,分別是standard,singleTop,singleTask,singleInstance。
standard:一個任務棧可以有多個實例,每個實例可以屬於不同任務棧。每新建一個activity就新建一個實例。一個實例被哪個實例創建,就存在哪個實例所在的棧中,如A啟動了B,那麼B就位於A的棧中。不能在appliactionContext中啟動它,因為非activity的context沒有任務棧,解決方法是加上FLAG_ACTIVITY_NEW_TASK標識,會新建一個任務棧。
singleTop:如果activity存在棧頂,此時activity不會被重建,它的oncreate等方法不會被重調用 。如棧中有ABC,再啟動C,就不會重新創建C。
singleTask:棧內復用模式,首先判斷所需要的棧是否在否存在,若存在,那麼只要在棧中存在,就不新建實例,並cleanTop,如果不存在,新建實例。如果所要的棧都不存在,新建棧。如棧中有ABCD,啟動C,C指定了所需的棧且棧不存在,那麼就會創建一個新棧,並把C存入,此時就存在兩個棧,一個是ABC,一個是C。如棧中有ABCD,啟動的C所需的棧就是ABCD所在的棧,那就會把C置於棧項,C上的所有實例出棧,此時棧就變成了ABC。那麼如何指定所需任務棧。一般使用TaskAffinity來指定,下面會說明。
singleInstance:具有singleTask的所有特性。不同的是,具有此模式的acitivity只能單獨位於一個棧中。如創建了A,A在一個棧中,後續再創建A就不會再創建實例了。
指定啟動模式有兩種設置方法:
在xml中設置:andorid:launchMode="singleTop"
在代碼中設置:intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);這種方法的優點是優先級比第一種高,比如同時用兩種方法設置,那以第二種為主,缺點是它不能設置singleInstance。
2.所需任務棧:
TaskAffinity:標識了一個activity所需要的任務棧名稱。默認為應用的包名。主要和singleTask配對使用。
任務棧分為前台和後台任務棧。後台 任務棧是指位於暫停的狀態。用戶可以切換將後台再次調到前台。
A啟動B,則B會位於A的任務棧中。(沒有TaskAffinity情況下)
比如A啟動B,B的TaskAffinity與A的不同,那就會創建新任務棧並把B放入。
AB是前台棧,CD是後台棧,B啟動D,則變成ABCD,啟動C則變成ABC.
3.標志位:
我們經常會在代碼中指定標志位,主要的標志位有以下幾種:
FLAG_ACTIVITY_NEW_TASK:類似singleTask
FLAG_ACTIVITY_SINGLE_TOP:類似singleTop
FLAG_ACTIVITY_CLEAN_TOP:清當前activity棧中它本身以上的activity
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有這個標記的activity不會出現在歷史activity列表中。只需設置
android:excludeFromRecents="true"
三,IntentFilter匹配規則
啟動activity有顯式和隱式兩種,如果是隱式,就要滿足IntentFilter匹配規則。
intent 有action,category,data.三個屬性。只有一個intent同時匹配了action,category和data才算完全匹配。有多個filter只要有一個匹配就可以。
action只要有一個匹配就可以。
category:如果intent有這個屬性,那它所有的category都必須匹配上。可以沒有。沒有默認有DEFAULT這個屬性。為了我們的activity能接受隱式調用,就必須加上android.intent.category.DEFAULT這個屬性。
data:與action類似。它為分為兩部分。mimeType,URL.mineType指媒體類型,如image/jpeg等,URL如下
http://www.baidu.com:80/search/info
URL默認是content和file,在不指定data 情況下就是匹配它。調用的方法如下
intent.setDataAndType(Uri.parse("file://abc"),"image/png")
完整的代碼如下:
Intent intent = new Intent("com.lxj.a");
intent.addCategory("com.lxj.b");
intent.setDataAndType(Uri.parse("file://abc"),"image/png")
startActivity(intent);
匹配的是如下的activity
就先寫這麼多吧,下一篇我會介紹下我對activity啟動源碼的理解。