Activity四種啟動模式
這部分應該是最最基礎的了,但是還是有很多細節需要把握,不只是表面的知識點。
- 1 Activity的管理是采用任務棧的形式
- 2 任務棧采用“后進先出”的棧結構
- 3 每按一次Back鍵,就有一個Activity出棧
image.png
- 標準模式(standard)
每啟動一次Activity,就會創建一個新的Activity實例并置于棧頂誰啟動了這個Activity,那么這個Activity就運行在啟動它的那個Activity所在的棧中。也就是說在ActivityA中啟動了ActivityB那么ActivityB就在ActivityA的棧中
image.png
- 單例模式(singleInstance)
- 作為棧內復用模式(singleTask)的加強版
- 打開該Activity時,直接創建一個新的任務棧,并創建該Activity實例放入新棧中
- 一旦該模式的Activity實例已經存在于某個棧中,任何應用再激活該Activity時都會重用該棧中的實例
- 使用場景:多個應用共享一個應用,不管誰激活該 Activity 都會進入同一個應用中。使用場景如鬧鈴提醒,將鬧鈴提醒與鬧鈴設置分離。
四種啟動模式圖解
image.png
四種啟動模式的區別
- 決定打開的任務棧
standard、singleTop啟動模式的Activity的目標任務棧,和收到Intent的發送者在同一個任務棧內。
singleTask啟動模式打開的任務棧由參數TaskAffinity決定。
singleInstance啟動模式總是新建任務棧,不會被啟動到一個其他任務棧里。 - 是否允許多個相同的Activity實例
standard、singleTop啟動模式中,同一個Activity可以被實例化多次,并且存在于不同的任務棧中,且一個任務棧可以包括同一個Activity的多個實例;
singleTask、singleInstance啟動模式則限制只生成一個實例。 - 是否允許不同的Activity實例存在于同一個任務棧內
singleInstance啟動模式獨占一個任務棧,其它Activity實例不能存在于該任務棧里。
另外三種模式,則可以和其它Activity實例共存于一個任務棧。 - 是否每次都生成新實例
standard模式:每次都生成新實例。
singleTop模式:若啟動的Activity不在棧頂,則生成新實例;
singleInstance模式:所在棧的唯一Activity實例,只會實例化一次,以后每次都被重用。
singleTask模式:若啟動的Activity不在棧內,則生成新實例;
啟動模式的設置
啟動模式有兩種設置方式: - 在AndroidMainifest設置
- 通過Intent設置標志位
1.在AndroidMainifest中設置
image.png
2.通過Intent設置標志位
image.png
image.png
二者設置的區別
- Intent設置方式比Manifest設置方式的優先級要高,即以前者為準
- 限定范圍不同
Manifest設置方式無法設定FLAG_ACTIVITY_CLEAR_TOP標識;Intent設置方式無法設置單例模式(singleInstance)
介紹一下任務棧:
(1)程序打開時就創建了一個任務棧, 用于存儲當前程序的activity,所有的activity屬于一個任務棧。
(2)一個任務棧包含了一個activity的集合,去有序的選擇哪一個activity和用戶進行交互:只有在任務棧棧頂的activity才可以跟用戶進行交互。
(3)任務??梢砸苿拥胶笈_,并且保留了每一個activity的狀態. 并且有序的給用戶列出它們的任務,而且還不丟失它們狀態信息。
(4)退出應用程序時:當把所有的任務棧中所有的activity清除出棧時,任務棧會被銷毀,程序退出。
任務棧的缺點:
(1)每開啟一次頁面都會在任務棧中添加一個Activity,而只有任務棧中的Activity全部清除出棧時,任務棧被銷毀,程序才會退出,這樣就造成了用戶體驗差,需要點擊多次返回才可以把程序退出了。
(2)每開啟一次頁面都會在任務棧中添加一個Activity還會造成數據冗余,重復數據太多,會導致內存溢出的問題(OOM)。
為了解決任務棧的缺點,我們引入了啟動模式。
Standard
???默認模式 v,可以不用寫配置。在這個模式下,都會默認創建一個新的實例。因此,在這種模式下,可以有多個相同的實例,也允許多個相同Activity疊加。
??若我有一個Activity名為A1, 上面有一個按鈕可跳轉到A1。那么如果我點擊按鈕,便會新啟一個Activity A1疊在剛才的A1之上,再點擊,又會再新啟一個在它之上…….
??點back鍵會依照棧順序依次退出。
singleTop
??可以有多個實例,但是不允許多個相同Activity疊加。即,如果Activity在棧頂的時候,啟動相同的Activity,不會創建新的實例,而會調用其onNewIntent方法。
例如:
??若我有兩個Activity名為B1,B2,兩個Activity內容功能完全相同,都有兩個按鈕可以跳到B1或者B2,唯一不同的是B1為standard,B2為singleTop。
??若我意圖打開的順序為B1->B2->B2,則實際打開的順序為B1->B2(后一次意圖打開B2,實際只調用了前一個的onNewIntent方法)
??若我意圖打開的順序為B1->B2->B1->B2,則實際打開的順序與意圖的一致,為B1->B2->B1->B2。
singleTask
???只有一個實例。在同一個應用程序中啟動的它時候,若Activity不存在,則會在當前task創建一個新的實例,若存在,則會把task中在其之上的其它Activity destory掉并調用它的onNewIntent方法。
???如果是在別的應用程序中啟動它,則會新建一個task,并在該task中啟動這個Activity,singleTask允許別的Activity與其在一個task中共存,也就是說,如果我在這個singleTask的實例中再打開新的Activity,這個新的Activity還是會在singleTask的實例的task中。
例如:
???若我的應用程序中有三個Activity,C1,C2,C3,三個Activity可互相啟動,其中C2為singleTask模式,那么,無論我在這個程序中如何點擊啟動,如:C1->C2->C3->C2->C3->C1-C2,C1,C3可能存在多個實例,但是C2只會存在一個,并且這三個Activity都在同一個task里面。但是C1->C2->C3->C2->C3->C1-C2,這樣的操作過程實際應該是如下這樣因為singleTask會把task中在其之上的其它Activity destory掉。
操作:C1->C2 C1->C2->C3 C1->C2->C3->C2 C1->C2->C3->C2->C3->C1 C1->C2->C3->C2->C3->C1-C2
實際:C1->C2 C1->C2->C3 C1->C2 C1->C2->C3->C1 C1->C2
??若是別的應用程序打開C2,則會新啟一個task。
??如別的應用Other中有一個activity,taskId為200,從它打開C2,則C2的taskIdI不會為200,例如C2的taskId為201,那么再從C2打開C1、C3,則C1、C3的taskId仍為201。
注意:如果此時你點擊home,然后再打開Other,發現這時顯示的肯定會是Other應用中的內容,而不會是我們應用中的C1 C2 C3中的其中一個。
singleInstance
??只有一個實例,并且這個實例獨立運行在一個task中,這個task只有這個實例,不允許有別的Activity存在。
例如:
??加載該Activity時如果沒有實例化,他會創建新的Task后,實例化入棧,如果已經存在,直接調用 onNewIntent,該Activity的Task中不允許啟動其它的Activity,任何從該Activity啟動的其他Activity都將被放到其他task中,先檢查是否有本應用的task,沒有的話就創建。
??程序有三個ActivityD1,D2,D3,三個Activity可互相啟動,其中D2為singleInstance模式。那么程序從D1開始運行,假設D1的taskId為200,那么從D1啟動D2時,D2會新啟動一個task,即D2與D1不在一個task中運行。假設D2的taskId為201,再從D2啟動D3時,D3的taskId為200,也就是說它被壓到了D1啟動的任務棧中。
singleInstance附加解釋:
???這種啟動模式比較特殊,因為它會啟用一個新的棧結構,將Activity放置于這個新的棧結構中,并保證不再有其他Activity實例進入。
???我們修改MainActivity的launchMode=”standard”,SecondActivity的launchMode=”singleInstance”,由于涉及到了多個棧結構,我們需要在每個Activity中顯示當前棧結構的id,所以我們為每個Activity添加如下代碼:
TextView textview=(TextView)findViewById(R.id.tv); textview.setText("current tesk id"+this.getTaskId());
image.png
image.png
??我們發現這兩個Activity實例分別被放置在不同的棧結構中,關于singleInstance的原理圖如下
image.png
???上半部分圖我們看到從MainActivity跳轉到SecondActivity時,重新啟用了一個新的棧結構,來放置SecondActivity實例,然后按下后退鍵,再次回到原始棧結構;圖中下半部分顯示的在SecondActivity中再次跳轉到MainActivity,這個時候系統會在原始棧結構中生成一個MainActivity實例,然后回退兩次,注意,并沒有退出,而是回到了SecondActivity,為什么呢?是因為從SecondActivity跳轉到MainActivity的時候,我們的起點變成了SecondActivity實例所在的棧結構,這樣一來,我們需要“回歸”到這個棧結構。