Android每個Application都是由若干個四大組件組成的。每個頁面都是一個Activity,當需要打開相應頁面(Activity)時系統會創建他們的實例并把他們一一放入棧中進行管理。任務棧是一種“后進先出”的棧結構,通過back鍵,我們可以發現這些Activity會一一出棧(PS:不斷返回上一頁)。如果每次啟動Activity都創建一個實例,會不會很浪費資源。能不能進行Activity的復用呢?Android系統在設計就考慮到這個問題,所以提供了同步的Activity啟動模式,在不同條件下進行Activity的復用。其中都包括:Standard、SingleTop、SingleTask、SingleInstance。
(PS:本篇文章的實驗數據都基于Android7.0)
在講述Activity啟動模式之前我們先了解一些基礎概念:
Application 是組件的集合。
Process 操作系統調度的單位。
Task是指在執行特定作業時與用戶交互的一系列 Activity。Task以棧的形式管理Activity集合。
- 一個應用中可以有多個Task
- 不同應用的Activity可以放在同一個Task中進行管理
- 一個應用中可以有多個Process
- Task可以運行在不同進程
standard
標準啟動模式,也是activity的默認啟動模式。在這種模式下啟動的activity可以被多次實例化,即在同一個任務中可以存在多個activity的實例,每個實例都會處理一個Intent對象。
- AndroidManifest.xml
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".AActivity"
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=".BActivity"
android:launchMode="standard"/>
</application>
- Logcat輸出
3459-3459 D/$$$AActivity: onCreate: currentActivityName:AActivity currentTaskID:6384
3459-3459 D/$$$AActivity: onClickBtn: AActivity start BActivity
3459-3459 D/$$$BActivity: onCreate: currentActivityName:BActivity currentTaskID:6384
3459-3459 D/$$$BActivity: onClickBtn: BActivity start AActivity
3459-3459 D/$$$AActivity: onCreate: currentActivityName:AActivity currentTaskID:6384
3459-3459 D/$$$AActivity: onClickBtn: AActivity start BActivity
3459-3459 D/$$$BActivity: onCreate: currentActivityName:BActivity currentTaskID:6384
- 當前任務棧
Running activities (most recent first):
TaskRecord{3efeab #6384 A=com.tzx.launchmodel U=0 StackId=1 sz=4}
Run #4: ActivityRecord{18878b0 u0 com.tzx.launchmodel/.BActivity t6384}
Run #3: ActivityRecord{5a7f957 u0 com.tzx.launchmodel/.AActivity t6384}
Run #2: ActivityRecord{559bd5f u0 com.tzx.launchmodel/.BActivity t6384}
Run #1: ActivityRecord{facb908 u0 com.tzx.launchmodel/.AActivity t6384}
singleTop
啟動的activity的實例已經存在于任務桟的桟頂,那么再啟動這個Activity時,不會創建新的實例,而是重用位于棧頂的那個實例,并且會調用該實例的onNewIntent()方法將Intent對象傳遞到這個實例中。
- AndroidManifest.xml
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".AActivity"
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=".BActivity"
android:launchMode="singleTop"/>
</application>
- Logcat輸出
14450-14450 D/$$$AActivity: onCreate: currentActivityName:AActivity currentTaskID:6386
14450-14450 D/$$$AActivity: onClickBtn: AActivity start BActivity
14450-14450 D/$$$BActivity: onCreate: currentActivityName:BActivity currentTaskID:6386
14450-14450 D/$$$BActivity: onClickBtn: BActivity start AActivity
14450-14450 D/$$$AActivity: onCreate: currentActivityName:AActivity currentTaskID:6386
14450-14450 D/$$$AActivity: onClickBtn: AActivity start BActivity
14450-14450 D/$$$BActivity: onCreate: currentActivityName:BActivity currentTaskID:6386
14450-14450 D/$$$BActivity: onClickBtn: BActivity start BActivity
14450-14450 D/$$$BActivity: onNewIntent()
14450-14450 D/$$$BActivity: onClickBtn: BActivity start BActivity
14450-14450 D/$$$BActivity: onNewIntent()
- 當前任務棧
Running activities (most recent first):
TaskRecord{fba1a37 #6386 A=com.tzx.launchmodel U=0 StackId=1 sz=4}
Run #5: ActivityRecord{9609e73 u0 com.tzx.launchmodel/.BActivity t6386}
Run #4: ActivityRecord{50fff56 u0 com.tzx.launchmodel/.AActivity t6386}
Run #3: ActivityRecord{1c403e9 u0 com.tzx.launchmodel/.BActivity t6386}
Run #2: ActivityRecord{3c41ba4 u0 com.tzx.launchmodel/.AActivity t6386}
singleTask
啟動模式為singleTask,那么系統總會在一個新任務的最底部(root)啟動這個activity,并且被這個activity啟動的其他activity會和該activity同時存在于這個新任務中。如果系統中已經存在這樣的一個activity則會重用這個實例,并且調用他的onNewIntent()方法。即,這樣的一個activity在系統中只會存在一個實例。
- AndroidManifest.xml
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".AActivity"
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=".BActivity"
android:launchMode="singleTask"/>
<activity android:name=".CActivity"
android:process=":remote"/>
</application>
- Logcat輸出
19684-19684 D/$$$AActivity: onCreate: currentActivityName:AActivity currentTaskID:6394
19684-19684 D/$$$AActivity: onClickBtn: AActivity start BActivity
19684-19684 D/$$$BActivity: onCreate: currentActivityName:BActivity currentTaskID:6394
19684-19684 D/$$$BActivity: onClickBtn: BActivity start AActivity
19684-19684 D/$$$AActivity: onCreate: currentActivityName:AActivity currentTaskID:6394
19684-19684 D/$$$AActivity: onClickBtn: AActivity start CActivity
19921-19921 D/$$$CActivity: onCreate: currentActivityName:CActivity currentTaskID:6394
19921-19921 D/$$$CActivity: onClickBtn: CActivity start AActivity
19684-19684 D/$$$AActivity: onCreate: currentActivityName:AActivity currentTaskID:6394
19684-19684 D/$$$AActivity: onClickBtn: AActivity start BActivity
19684-19684 D/$$$BActivity: onNewIntent()
19684-19684 D/$$$BActivity: onClickBtn: BActivity start BActivity
19684-19684 D/$$$BActivity: onNewIntent()
- 當前任務棧
Running activities (most recent first):
TaskRecord{8e8fb09 #6394 A=com.tzx.launchmodel U=0 StackId=1 sz=2}
Run #7: ActivityRecord{7489fc u0 com.tzx.launchmodel/.BActivity t6394}
Run #6: ActivityRecord{9a5d10e u0 com.tzx.launchmodel/.AActivity t6394}
singleInstance
總是在新的任務中開啟,并且這個新的任務中有且只有這一個實例。
- AndroidManifest.xml
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".AActivity"
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=".BActivity"
android:launchMode="singleInstance"/>
<activity android:name=".CActivity"
android:process=":remote"/>
</application>
- Logcat輸出
25016-25016 D/$$$AActivity: onCreate: currentActivityName:AActivity currentTaskID:6396
25016-25016 D/$$$AActivity: onClickBtn: AActivity start BActivity
25016-25016 D/$$$BActivity: onCreate: currentActivityName:BActivity currentTaskID:6397
25016-25016 D/$$$BActivity: onClickBtn: BActivity start AActivity
25016-25016 D/$$$AActivity: onCreate: currentActivityName:AActivity currentTaskID:6396
25016-25016 D/$$$AActivity: onClickBtn: AActivity start CActivity
26003-26003 D/$$$CActivity: onCreate: currentActivityName:CActivity currentTaskID:6396
26003-26003 D/$$$CActivity: onClickBtn: CActivity start BActivity
25016-25016 D/$$$BActivity: onNewIntent()
- 當前任務棧
Running activities (most recent first):
TaskRecord{d5934c9 #6397 A=com.tzx.launchmodel U=0 StackId=1 sz=1}
Run #9: ActivityRecord{986e7ce u0 com.tzx.launchmodel/.BActivity t6397}
TaskRecord{f282078 #6396 A=com.tzx.launchmodel U=0 StackId=1 sz=3}
Run #8: ActivityRecord{d2c75de u0 com.tzx.launchmodel/.CActivity t6396}
Run #7: ActivityRecord{2d3a2eb u0 com.tzx.launchmodel/.AActivity t6396}
Run #6: ActivityRecord{2ca9351 u0 com.tzx.launchmodel/.AActivity t6396}
本文敘述性的文字非常少,主要通過其代碼和其運行結果然后得出我們需要的結論。每一種設計模式我都畫了一副圖,可以使大家理解記憶深刻。
Activity啟動模式到這里就結束了么,然而并沒有。之前看過其他類似文章或者書籍的同學都知道還有Activity的Flags和 android:taskAffinity
標簽對Activity的啟動有影響。這些內容我們放在下一張深入理解Activity啟動模式之大結局中講述,有興趣的同學可以點擊閱讀\~!
文章到這里就全部講述完啦,若有其他需要交流的可以留言哦~!~!