大家都知道,安卓有四種啟動模式,使用的時候在清單文件配置一下就好了。但是如果你對四種啟動模式認識不深,後面是要吃大虧的!有些需求場景本來是可以簡單實現的,但是卻被各自需求邏輯搞複雜。我之前遇到一個問題是,點擊手機桌面圖標,打開的Activity總是啟動頁,當時以為是因為我們把啟動頁這個Activity設置成了LauchActivity導致的,所以我把MainActivity設置成了LauchActivity,導致每次點擊桌面圖標首先打開MainActivity,然後去啟動SplashActivity,這樣做是非常消耗內存的,所以我們的項目上線之後在啟動頁加載廣告圖的時候造成內存溢出了!後來想想原來是自己對Activity的啟動模式和Android任務棧認識不深導致的。
首先,我們點擊桌面應用圖標,一定打開的是我們設置為LauchActivity的那個Activity,然後在根據業務邏輯進行調轉到相應的Activity。當你的SplashActivity的啟動模式設置成SingleTask或者SingleInstance啟動模式,並且這個Activity還是LauchActivity,那麼當你程序退出到後臺,再次點擊桌面圖標,程序打開的還是SplashActivity,而你之前在任務棧還沒有調用finish()的Activity,已經因為你設置的啟動模式,而強行清棧了!這就是我說的很坑的地方,改動一處,已經影響了之前的業務邏輯。
那麼現在我們就要來聊一聊安卓的啟動模式了。
這裡有比較好的博客可以參考一下:
http://blog.csdn.net/shinay/article/details/7898492/
但是為了加深自己的理解,所以我決定自己做一下實驗:
準備材料:安卓開發工具、一個新的項目工程、三個功能相同並列印各種生命周期的Activity.
首先我們看Standard啟動模式:它允許Activity重複添加,如果你想讓跳轉之前的Activity出棧,需要手動的調用跳轉之前的Activity的finish()方法。
我們會發現FristActivity的onPause()方法會在SecondActivity調用onCreate()方法之前調用,而onSaveInstanceState()和onStop()會在FristActivity創建之後調用。
SingleTop啟動模式
實驗場景:1)三個功能相同的Activity,並列印各自的生命周期方法,把SecondActivity設置為SingleTop啟動模式。2)我們首先從FristAcitity跳轉到SecondActivity,接著跳轉到ThirdActivity,然後再從ThirdActivity跳轉到FristActivity,再跳SecondActivity來觀察SecondActivity的生命周期方法。
實驗現象:1)我們會發現每次跳轉SecondActivity的生命周期調用和Sandard啟動模式是一致的。
2)當我把SecondActivity設置成跳轉到當前的顯示界面的時候,如下圖:
點擊當前SecondAtivity的跳轉按鈕,發現調用了SecondActivity的如下生命周期方法:
我們發現當SecondActivity設置成SingleTop啟動模式的時候,重複跳轉到自己,如果自己在棧頂的話,它就不會重新創建自己,而是復用了當前處在棧頂的Activity,並調用onPause()、onNewIntent()、onResume()、onPostResume()四個方法。
為了進行對比,我們現在讓FristActivity重複的跳轉到自己,列印的生命周期如下:
我們會發現Standard啟動模式的Activity並沒有復用自己,而是重新走了一遍生命周期方法,也說明它是允許Activity疊加的!
3)SingleTop 可以有多個實例,但是不允許多個相同Activity疊加。如果該Activity不在棧頂,則創建新的實例,在棧頂則復用,並調用onNewIntent()方法。這種啟動模式通常適用於接受到消息後顯示的界面,例如QQ接受到消息後彈出Activity,如果一次來10條消息,總不能一次彈10個Activity。
SingleTask模式
實驗場景:1)材料和上面一樣,現在我們把SecondActivity設置成SingleTask啟動模式,並從1–>2–>3—>1—>2這樣進行Activity調轉。
實驗現象:1)發現正常的從1–>2—>3生命周期方法和Standard啟動模式一模一樣。
2)當從3–>1–>2Activity進行跳轉的時候,SecondActivity調用了如下生命周期方法。
我們發現,SingleTask啟動的Activity在發現自己在任務棧有實例時,會復用之前的實例,並調用onNewIntent()、onRestart()、onStart()、onResume()、onPostResume()五個生命周期方法。
3)設置SingleTask啟動模式的Activity會調用在任務棧上面activity的onDestroy方法,把前面的Activity清出任務棧,直到自己處在棧頂,後面的Activity的位置保持不變。
4)設置SingleTask啟動模式的Activity一個任務棧只存在一份實例,這就是它和SingleTop的區別.
5)SingleTask只有一個實例。在同一個應用程式中啟動他的時候,若Activity不存在,則會在當前task創建一個新的實例,若存在,則會把task中在其之上的其它Activity destory掉並調用它的onNewIntent方法。
SingleInstance模式
實驗場景:1)實驗材料和上面相同,我們把SecondActivity的啟動模式設置成singleInstance啟動模式。
2)在每個Activity的onCreate()方法中加如下代碼:
Log.e(">>>>>>>>>>>>>>>>>"+TAG,"onCreate()"+"TaskId"+getTaskId());
實驗現象:1)首先從FristActivity跳轉到SecondActivity時我們發現除了onCreate()方法列印的日誌不一樣外,其他的生命周期方法和Sandard啟動模式一模一樣,日誌列印如下:
2)我們再從SecondActivity跳轉到ThridActivity,再從ThridActivity跳轉到FristActivity,都沒有發現什麼異常,因為除了SecondActivity,其他Activity都是Sandard啟動模式。
3)當我們再從FristActivity跳轉到SecondActivity,我們發現設置SingleInstance啟動模式的Activity也會復用實例,並調用onNewIntent()、onRestart()、onStart()、onResume()、onPostResume()方法。
4)當我回退棧的時候,發現之前創建的Activity都還在任務棧內,我們從1–>2–>3–>1–>2,回退棧的時候順序是2–>1–>3–>1,發現之前的實例在第一次退棧的時候銷毀了,所以,任務棧沒有SecondActivity的實例。
5)SingleInstance和SingleTask的區別就是它實例存在於獨立的一個任務棧中,並跳轉復用實例的時候不會清之前存在於任務棧的Activity實例。
6)SingleInstance啟動的Activity允許不同的應用進程訪問,否則調用將無效。比如:第三方推送跳轉時,跳轉的Activity必須設置成SingleInstance啟動模式,否則無法打開。
最後,我們總結一下:
1)Standard模式允許Activity重複疊加。
2)SingleTop 可以有多個實例,但是不允許多個相同Activity疊加。如果該Activity不在棧頂,則創建新的實例,在棧頂則復用,並調用onNewIntent()方法。這種啟動模式通常適用於接受到消息後顯示的界面,例如QQ接受到消息後彈出Activity,如果一次來10條消息,總不能一次彈10個Activity。
3)SingleTask只有一個實例。在同一個應用程式中啟動他的時候,若Activity不存在,則會在當前task創建一個新的實例,若存在,則會把task中在其之上的其它Activity destory掉並調用它的onNewIntent方法。
4)SingleInstance只有一個實例,並獨立使用一個任務棧,不會把task中在其之上的其它Activity destory掉並調用它的onNewIntent方法。使用場景,A應用需要啟動B應用的Activity,則需要把該Activity設置成SingleInstance,比如第三方推送。