Android四大元件之Activity-啟動模式
阿新 • • 發佈:2018-12-14
1.Activity的啟動模式
當我們多次呼叫同一個Activity時,系統會重複建立多個例項並把它們一一放入任務棧中,這種方式顯然不符合我們的設計要求。所以Android在設計時就提供了四種啟動模式來解決此問題。
四種啟動模式分別如下:
- standard-標準模式也是預設模式 每次啟動一個Activity都會建立新的例項並壓入任務棧,onCreate,onStart,onResume都會被呼叫。每個任務棧可以有多個例項,每個例項也可屬於不同的任務棧。例如: A->B,B為standard模式,B即屬於A的任務棧。 A B C D 再次啟動A(standard模式)
當前任務棧存在的元素 | 啟動後的任務棧存在的元素 |
---|---|
A B C D | A B C D A |
- singleTop-棧頂複用模式 此模式下,比如新的Activity已經位於棧頂,那麼此Activity不會被重新建立,會回撥它的onNewIntent方法,它的onCreate,onStart不會被系統呼叫。如果新的Activity不是位於棧頂,那麼它還是會被重新建立。例: A B C D 再次啟動D(singleTop模式) A B D C 再次啟動D(singleTop模式)
當前任務棧存在的元素 | 啟動後的任務棧存在的元素 |
---|---|
A B C D | A B C D |
A B D D | A B D C D |
- singleTask-棧內複用模式 單例項模式,只要Activity在一個棧中存在,多次啟動都不會重新建立例項,系統會回撥onNewIntent方法。 如果要啟動一個啟動模式為singleTask的Activity A,先判斷是否存在A所需的任務棧,不存在->新建立任務棧並把例項A壓入。如果存在,判斷A是否在棧中存在例項,存在移到棧頂,並將之前的例項出棧,如果不存在例項,建立並壓入棧。
任務棧S1存在A B C,啟動D(singleTask模式)(所需任務棧S2),因為S2與D例項均不存在,所以系統會新建任務棧S2並建立D壓入S2。 任務棧S1存在A B C,啟動D(singleTask模式)(所需任務棧S1),啟動D後的S1為A B C D。 任務棧S1存在A D B C,啟動D(singleTask模式)(所需任務棧S1),啟動D後的S1為A D。
使用:
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
Log.d(TAG, "--onNewIntent--")
}
可以看出MainActivity始終沒有被重新建立
- singleInstance-單例項模式 加強的singleTask模式,擁有singleTask的所有特點且只能單獨的位於一個任務棧中。
特殊情況
?:現在有S1-前臺任務棧,S2-後臺任務棧(singleTask模式)。S1有A B,S2有C D。
現在啟動D,S2整個任務棧會切換至S1中,即S1存在 A B C D,依此按下返回鍵例項一一出棧。
現在啟動C,S2整個任務棧會切換至S1中,即S1存在 A B C,依此按下返回鍵例項一一出棧。
2.任務棧
前面所說的Activity所需任務棧是什麼?即TaskAffinity引數:這個引數標識了一個Activity所需任務棧的包名。此屬性主要與singleTask啟動模式或者allowReparenting屬性配對使用。
1.當與singleTask配對使用時,啟動的Activity會執行在名字與TaskAffinity相同的任務棧中。
2.當與allowReparenting配對使用時,情況比較特殊。
現有應用A與B(存在Activity C),現在A啟動B的C,點選Home鍵。點選B 會啟動C。--C從A的任務棧轉移到了B的任務棧。
簡單使用: A為standrad B為singleTask TaskAffinity值為”com.wdl.test“。模擬過程A->B->A
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:launchMode="standard">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Main2Activity"
android:taskAffinity="com.wdl.test"
android:launchMode="singleTask"/>
控制檯輸入adb shell dumpsys activity
發現此時存在兩個任務棧 一個為包含B A的S1(com.wdl.test),另一個為只有A的S2 (com.wdl.kt1)
分為2類:
- 前臺任務棧
- 後臺任務棧,位於暫停狀態
3.如何給Activity指定啟動模式
- 通過AndroidMenifest.xml為Activity指定啟動模式
<activity android:name=".Main2Activity"
android:launchMode="singleTask"/>
- 在Intent中設定標誌位為Activity指定啟動模式
val intent = Intent(this,MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
常用的標誌位有:
值 | 作用 |
---|---|
FLAG_ACTIVITY_NEW_TASK | 指定singleTask啟動模式 |
FLAG_ACTIVITY_SINGLE_TOP | 指定singleTop啟動模式 |
FLAG_ACTIVITY_CLEAR_TOP | 此Activity(singleTask)之前的例項全部要出棧; Activity(standard)之前與本身的例項全部要出棧,重新建立例項併入棧 |
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | 具有此標記的Activity不會出現在歷史Activity中 |
二者的區別: 1.優先順序上第二種方式高於第一種方式。 2.限定範圍上有所不同 例:第一種方式無法直接為Activity設定FLAG_ACTIVITY_CLEAR_TOP標識;第二種方式無法為Activity指定singleInstance模式