登錄
小豬快跑22
關注
一個實例讓你徹底明白Activity的4種啟動模式
原創(chuàng) 2017年08月03日 14:46:54 閱讀 792
首先,我們得有一個概念雀鹃,就是啟動的Activity都是放在相應的任務棧中久又。按Back鍵的時候Activity會從任務棧中返回巫延,當任務棧為空時系統(tǒng)就會回收這個任務棧。
那么我們?yōu)槭裁葱枰@4中啟動模式呢地消?我們新建Activity的并在Androidmanifest.xml文件中注冊的時候炉峰,默認的就是standard模式,如果你在這個Activity中一直通過startActivity來啟動這個Activity脉执,那么任務棧中就會有許多該Activity疼阔,你要多次按返回鍵才能返回到launcher頁面。這樣的體驗簡直糟糕啊半夷。
模式1:standard
標準模式婆廊,也是Activity默認的啟動方式。這個在Androidmanifest.xml中的Activity里聲明巫橄,如下:
<activity
? ? ? ? ? ? android:name="luanchmode.ActivityB"
? ? ? ? ? ? android:launchMode="standard" />
1
2
3
以這種方式啟動的Activity每次都會創(chuàng)建一個新的實例淘邻,不管這個實例是否已經(jīng)存在。
比如在 Activity A 中啟動 A湘换,那么任務棧中會有2個A宾舅。
例子1:ActivityA 中以standard啟動 ActivityA敬尺,代碼如下:
manefest.xml:
<activity android:name="luanchmode.ActivityA"
? ? ? ? ? ? android:launchMode="standard">
? ? ? ? ? ? <intent-filter>
? ? ? ? ? ? ? ? <action android:name="android.intent.action.MAIN" />
? ? ? ? ? ? ? ? <category android:name="android.intent.category.LAUNCHER" />
? ? ? ? ? ? </intent-filter>
? ? ? ? </activity>
1
2
3
4
5
6
7
8
ActivityA.java:
public class ActivityA extends Activity {
? ? @Override
? ? protected void onCreate(@Nullable Bundle savedInstanceState) {
? ? ? ? Log.e("xxx", "ActivityA, onCreate");
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? TextView tv = new TextView(this);
? ? ? ? tv.setTextSize(20);
? ? ? ? tv.setText("This is activityA");
? ? ? ? tv.setGravity(Gravity.CENTER);
? ? ? ? tv.setBackgroundColor(Color.parseColor("#999999"));
? ? ? ? setContentView(tv, new ViewGroup.LayoutParams(200, 100));
? ? ? ? tv.setFocusable(true);
? ? ? ? tv.requestFocus();
? ? ? ? tv.setOnClickListener(new View.OnClickListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onClick(View v) {
? ? ? ? ? ? ? ? Log.e("xxx","onclick A");
? ? ? ? ? ? ? ? Intent intent = new Intent(ActivityA.this, ActivityA.class);
? ? ? ? ? ? ? ? startActivity(intent);
? ? ? ? ? ? }
? ? ? ? });
? ? }
? ? @Override
? ? protected void onNewIntent(Intent intent) {
? ? ? ? Log.e("xxx", "ActivityA, onNewIntent");
? ? ? ? super.onNewIntent(intent);
? ? }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
log如下:
08-02 19:33:45.720 11791-11791/com.example.aidlclient E/xxx: ActivityA, onCreate
08-02 19:33:59.192 11791-11791/com.example.aidlclient E/xxx: onclick A
08-02 19:33:59.207 11791-11791/com.example.aidlclient E/xxx: ActivityA, onCreate
1
2
3
可以看到 點擊跳轉(zhuǎn)到 ActivityA 的時候,任然會執(zhí)行 onCreate方法贴浙。
通過指令:adb shell dumpsys activity 查看任務棧:
? Running activities (most recent first):
? ? TaskRecord{2470eca6 #1587 A=com.example.aidlclient U=0 sz=2}
? ? ? Run #1: ActivityRecord{3456102c u0 com.example.aidlclient/luanchmode.ActivityA t1587}
? ? ? Run #0: ActivityRecord{352831f7 u0 com.example.aidlclient/luanchmode.ActivityA t1587}
1
2
3
4
可以看出任務棧中有2個ActivityA 砂吞。
模式2:singleTop 棧頂復用模式
在這種模式下啟動的Activity,如果該Activity已經(jīng)位于棧頂崎溃,那么就不會去創(chuàng)建新的實例蜻直,調(diào)用該Activity的onNewIntent方法。如果不在棧頂還是會新建一個Activity實例袁串。
例子: A 啟動B概而,B的啟動模式為singleTop ,然后 B 再啟動 B囱修;
AndroidManifest.xml如下:
<activity android:name="luanchmode.ActivityA"
? ? ? ? ? ? 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="luanchmode.ActivityB"
? ? ? ? ? ? android:launchMode="singleTop" />
? ? ? ? <activity
1
2
3
4
5
6
7
8
9
10
11
12
AcitivityA 和 ActivityB 中的部分代碼如下:
tv.setOnClickListener(new View.OnClickListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onClick(View v) {
? ? ? ? ? ? ? ? Intent intent = new Intent(ActivityA.this, ActivityB.class);
? ? ? ? ? ? ? ? startActivity(intent);
? ? ? ? ? ? }
? ? ? ? });
1
2
3
4
5
6
7
tv.setOnClickListener(new View.OnClickListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onClick(View v) {
? ? ? ? ? ? ? ? Intent intent = new Intent(ActivityB.this, ActivityB.class);
//? ? ? ? ? ? ? ? intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
? ? ? ? ? ? ? ? startActivity(intent);
? ? ? ? ? ? }
? ? ? ? });
1
2
3
4
5
6
7
8
log如下:
08-03 09:13:01.841 26939-26939/com.example.aidlclient E/xxx: ActivityA, onCreate
08-03 09:18:08.513 26939-26939/com.example.aidlclient E/xxx: ActivityB, onCreate
08-03 09:18:09.983 26939-26939/com.example.aidlclient E/xxx: ActivityB, onNewIntent
1
2
3
可以看出從A跳轉(zhuǎn)到B時赎瑰,由于棧中沒有B,所以會新建B的實例并放入棧中破镰;從B跳到B中餐曼,由于棧頂以經(jīng)是B了,所以不會新建實例鲜漩,而是會調(diào)用B的onNewIntent方法源譬。
我們看看任務棧中是不是只有A和B ?
Running activities (most recent first):
? ? TaskRecord{351e6f43 #1596 A=com.example.aidlclient U=0 sz=2}
? ? Run #1: ActivityRecord{2925d326 u0 com.example.aidlclient/luanchmode.ActivityB t1596}
? ? Run #0: ActivityRecord{1e64c90 u0 com.example.aidlclient/luanchmode.ActivityA t1596}
1
2
3
4
可以看到任務棧中只有A和B孕似,也可以看出如果如果B在棧頂就不會創(chuàng)建新的實例踩娘。接下來我們看看如果B不是棧頂,那又會如何喉祭?
接下來的例子是這樣的 A 啟動 B养渴, B 啟動 C, C 再啟動 B:
代碼很簡單就不貼A和B的了,貼下C的泛烙。
tv.setOnClickListener(new View.OnClickListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onClick(View v) {
? ? ? ? ? ? ? ? Intent intent = new Intent(ActivityC.this, ActivityB.class);
//? ? ? ? ? ? ? ? intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
? ? ? ? ? ? ? ? startActivity(intent);
? ? ? ? ? ? }
? ? ? ? });
1
2
3
4
5
6
7
8
log如下:
08-03 09:36:35.259 17108-17108/com.example.aidlclient E/xxx: ActivityA, onCreate
08-03 09:36:39.482 17108-17108/com.example.aidlclient E/xxx: ActivityB, onCreate
08-03 09:36:40.979 17108-17108/com.example.aidlclient E/xxx: ActivityC onCreate
08-03 09:36:42.171 17108-17108/com.example.aidlclient E/xxx: ActivityB, onCreate
1
2
3
4
可以看出理卑,C再次啟動B的時候B會創(chuàng)建新的實例。我們查看下任務椊憾瑁看看是什么樣的傻工,任務棧中應該是 A->B->C->B.
Running activities (most recent first):
? ? ? TaskRecord{1d40b112 #1602 A=com.example.aidlclient U=0 sz=4}
? ? ? ? Run #3: ActivityRecord{3482a81a u0 com.example.aidlclient/luanchmode.ActivityB t1602}
? ? ? ? Run #2: ActivityRecord{a101309 u0 com.example.aidlclient/luanchmode.ActivityC t1602}
? ? ? ? Run #1: ActivityRecord{3575d5f8 u0 com.example.aidlclient/luanchmode.ActivityB t1602}
? ? ? ? Run #0: ActivityRecord{31f704f3 u0 com.example.aidlclient/luanchmode.ActivityA t1602}
1
2
3
4
5
6
以上2個例子驗證了,以singleTop啟動的Activity孵滞,如果棧頂是該Activity中捆,那么不會創(chuàng)建新的實例,如果該Activity不在棧頂坊饶,要啟動這個Activity還是會創(chuàng)建新的實例泄伪。
模式3:singleTask 站內(nèi)復用模式
在這種模式下,如果Activity存在于棧中匿级,那么啟動這個Activity不會創(chuàng)建新的實例蟋滴,而是會調(diào)用onNewIntent()染厅,并且將該Activity上面的所有Activity移出棧;當以singleTask 啟動一個Activity的時候津函,首先去判斷是否要為該Activity去創(chuàng)建一個任務棧肖粮?怎么判斷的我們下面再講,如果需要的話尔苦,那么就會創(chuàng)建一個任務棧涩馆,并且將該Activity放入棧中;如果不需要的話允坚,直接將該Activity放入當前的任務棧中魂那。
現(xiàn)在我們來講怎么判斷是否需要創(chuàng)建任務棧?任務棧的創(chuàng)建跟taskAffinity的屬性相關稠项,每個Activity都有taskAffinity屬性涯雅,這個屬性指出了它希望進入的Task。如果一個Activity沒有顯式的指明該Activity的taskAffinity展运,那么它的這個屬性就等于Application指明的taskAffinity活逆,如果Application也沒有指明,那么該taskAffinity的值就等于包名乐疆。
在singleTask 模式下划乖,如果你在要啟動的Activity中設置taskAffinity屬性,且該屬性的值不等于包名挤土,那么就需要創(chuàng)建任務棧,否則不需要創(chuàng)建误算。taskAffinity的屬性設置如下:
<activity
? ? ? ? ? ? android:name="luanchmode.ActivityB"
? ? ? ? ? ? android:launchMode="singleTask"
? ? ? ? ? ? android:taskAffinity="com.example.aidlclient.test" />
1
2
3
4
而我的應用的包名是:package=”com.example.aidlclient”>
例子1:A中啟動B仰美,B中啟動C,然后C啟動D儿礼,D再啟動B咖杂,其中A和C、D是standard模式蚊夫,B是singleTask模式诉字。
manifest.xml如下:
<activity
? ? ? ? ? ? android:name="luanchmode.ActivityA"
? ? ? ? ? ? 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="luanchmode.ActivityB"
? ? ? ? ? ? android:launchMode="singleTask" />
? ? ? ? <activity android:name="luanchmode.ActivityC" />
? ? ? ? <activity android:name="luanchmode.ActivityD" />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
還是先看log:
08-03 10:40:33.896 14823-14823/? E/xxx: ActivityA, onCreate
08-03 10:40:42.777 14823-14823/? E/xxx: ActivityB, onCreate
08-03 10:40:44.169 14823-14823/? E/xxx: ActivityC onCreate
08-03 10:40:45.218 14823-14823/? E/xxx: ActivityD onCreate
08-03 10:40:46.696 14823-14823/? E/xxx: ActivityB, onNewIntent
1
2
3
4
5
6
7
A->B : 由于棧中沒有B且未對B設置android:taskAffinity屬性,所以直接創(chuàng)建B的實例并放在該棧中知纷;
B->C->D:創(chuàng)建C和D的實例并放到棧中
D->B : 由于B已經(jīng)存在棧中壤圃,所以直接將B移到棧頂,調(diào)用onNewIntent()琅轧,并且B上面的Activity全部出棧伍绳。
任務棧如下:
Running activities (most recent first):
? ? ? TaskRecord{33b61cae #1611 A=com.example.aidlclient U=0 sz=2}
? ? ? ? Run #1: ActivityRecord{2291853f u0 com.example.aidlclient/luanchmode.ActivityB t1611}
? ? ? ? Run #0: ActivityRecord{390ec8d6 u0 com.example.aidlclient/luanchmode.ActivityA t1611}
1
2
3
4
可以看到A和B都在同一個棧中,且從D跳轉(zhuǎn)到B的時候乍桂,B上面的Activity全部出棧冲杀。
例子2:為B設置android:taskAffinity=”com.example.aidlclient.test”和包名不一樣
manifest.xml如下:
<activity
? ? ? ? ? ? android:name="luanchmode.ActivityB"
? ? ? ? ? ? android:launchMode="singleTask"
? ? ? ? ? ? android:taskAffinity="com.example.aidlclient.test"/>
1
2
3
4
log如下:
08-03 10:45:24.335 15566-15566/com.example.aidlclient E/xxx: ActivityA, onCreate
08-03 10:45:38.858 15566-15566/com.example.aidlclient E/xxx: ActivityB, onCreate
08-03 10:45:40.912 15566-15566/com.example.aidlclient E/xxx: ActivityC onCreate
08-03 10:45:42.694 15566-15566/com.example.aidlclient E/xxx: ActivityD onCreate
08-03 10:45:44.406 15566-15566/com.example.aidlclient E/xxx: ActivityB, onNewIntent
1
2
3
4
5
A->B:由于B不存在與任務棧中效床,所以會新建B的實例,至于有沒有創(chuàng)建對應的棧权谁,log中看不出剩檀,等下通過adb來查看。
B->C->D:正常啟動旺芽,創(chuàng)建C和D的實例并放入任務棧
D->B:由于B存在于任務棧中沪猴,所以直接將B移到棧頂,調(diào)用onNewIntent()甥绿,并且B上面的Activity全部出棧字币。
利用 adb shell dumpsys activity查看任務棧情況:
先看 A->B->C->D:的任務棧詳情:
Running activities (most recent first):
? ? ? TaskRecord{3874c557 #1618 A=com.example.aidlclient.test U=0 sz=3}
? ? ? ? Run #3: ActivityRecord{84f09e0 u0 com.example.aidlclient/luanchmode.ActivityD t1618}
? ? ? ? Run #2: ActivityRecord{255bda6b u0 com.example.aidlclient/luanchmode.ActivityC t1618}
? ? ? ? Run #1: ActivityRecord{2ac8c0a u0 com.example.aidlclient/luanchmode.ActivityB t1618}
? ? ? TaskRecord{1d0e98b2 #1617 A=com.example.aidlclient U=0 sz=1}
? ? ? ? Run #0: ActivityRecord{3863a8b u0 com.example.aidlclient/luanchmode.ActivityA t1617}
1
2
3
4
5
6
7
可以看出 B、C共缕、D在一個任務棧洗出,A在另外一個任務棧。
先看 A->B->C->D->B:的任務棧詳情
? Running activities (most recent first):
? ? ? TaskRecord{3874c557 #1618 A=com.example.aidlclient.test U=0 sz=1}
? ? ? ? Run #1: ActivityRecord{2ac8c0a u0 com.example.aidlclient/luanchmode.ActivityB t1618}
? ? ? TaskRecord{1d0e98b2 #1617 A=com.example.aidlclient U=0 sz=1}
? ? ? ? Run #0: ActivityRecord{3863a8b u0 com.example.aidlclient/luanchmode.ActivityA t1617}
1
2
3
4
5
可以看出图谷,從B->D后翩活,會將B上面的Activity全部移除出棧。
模式4:singleInstance
這種模式下便贵,Activity只能單獨的存在一個任務棧中菠镇,舉個例子,就是說A以singleInstance 啟動了B承璃,那么會創(chuàng)建一個任務棧利耍,并把B放到創(chuàng)建的任務棧中,該棧只能有B的存在盔粹。
例子1:A啟動B隘梨,B啟動C,其中A舷嗡、C的啟動模式為standard轴猎,D的啟動模式為singleInstance 。
manifest.xml如下:
<activity
? ? ? ? ? ? android:name="luanchmode.ActivityA"
? ? ? ? ? ? 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="luanchmode.ActivityB"
? ? ? ? ? ? android:launchMode="singleInstance" />
? ? ? ? <activity android:name="luanchmode.ActivityC" />
1
2
3
4
5
6
7
8
9
10
11
12
13
log如下:
08-03 11:07:29.810 5490-5490/com.example.aidlclient E/xxx: ActivityA, onCreate
08-03 11:07:37.698 5490-5490/com.example.aidlclient E/xxx: ActivityB, onCreate
08-03 11:07:41.398 5490-5490/com.example.aidlclient E/xxx: ActivityC onCreate
08-03 11:08:37.934 5490-5490/com.example.aidlclient E/xxx: ActivityB, onNewIntent
1
2
3
4
A->B:由于不存在B需要的任務棧进萄,所以先創(chuàng)建任務棧捻脖,然后將B壓入棧
B->C:正常啟動,創(chuàng)建C的實例并入棧中鼠。
C->B:不會創(chuàng)建B新的實例可婶,而是調(diào)用onNewIntent()。
先看 A->B->C的任務棧詳情:
Running activities (most recent first):
? ? ? TaskRecord{2d63becf #1621 A=com.example.aidlclient U=0 sz=2}
? ? ? ? Run #2: ActivityRecord{340fa242 u0 com.example.aidlclient/luanchmode.ActivityC t1621}
? ? ? TaskRecord{323683de #1622 A=com.example.aidlclient U=0 sz=1}
? ? ? ? Run #1: ActivityRecord{2aef961d u0 com.example.aidlclient/luanchmode.ActivityB t1622}
? ? ? TaskRecord{2d63becf #1621 A=com.example.aidlclient U=0 sz=2}
? ? ? ? Run #0: ActivityRecord{3486b42c u0 com.example.aidlclient/luanchmode.ActivityA t1621}
1
2
3
4
5
6
7
A->B 會新建一個任務棧然后創(chuàng)建B的實例并壓入該棧兜蠕;B->C 直接創(chuàng)建C的實例并壓入之前A所在的棧扰肌。
Activity的4種啟動模式就寫到這里,下面會寫Intent中設置flag熊杨,以及taskAffinity曙旭。
閱讀全文
舉報
小豬快跑22訪問量 6萬+ 原創(chuàng) 54 博主更多文章>
Android中Activity的使用盗舰,簡單實例講解
qq_32175491 10449次閱讀 2016-12-27 16:09:12
activity例子
shiyanming1223 8317次閱讀 2015-02-28 22:11:30
通過官網(wǎng)的一個例子來看Activity的分組管理
chuyouyinghe 302次閱讀 2016-05-20 10:51:25
如何獲取Activity的實例
u011663865 1394次閱讀 2016-04-02 22:21:38
徹底弄懂Activity四大啟動模式
mynameishuangshuai 70645次閱讀 2016-05-24 16:04:24
Activity的四種啟動模式和應用場景
wangxueming 5020次閱讀 2017-06-15 17:56:44
activity的四種啟動模式區(qū)別_launchmode圖文詳解
androidstar_cn 1409次閱讀 2016-10-03 23:55:06
[Android開發(fā)]Activity的四種啟動模式及其應用場景
CodeEmperor 26320次閱讀 2016-01-08 11:39:41
Activity的4種啟動模式
wl1fy 74次閱讀 2017-03-28 18:08:42
更多相關文章
CSDN
CSDN精彩內(nèi)容推薦
查看熊掌號