Activity的4种启动模式

登录

小猪快跑22

关注

一个实例让你彻底明白Activity的4种启动模式

原创 2017年08月03日 14:46:54 阅读 792

首先,我们得有一个概念,就是启动的Activity都是放在相应的任务栈中。按Back键的时候Activity会从任务栈中返回,当任务栈为空时系统就会回收这个任务栈。

那么我们为什么需要这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每次都会创建一个新的实例,不管这个实例是否已经存在。

比如在 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

可以看到 点击跳转到 ActivityA 的时候,任然会执行 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已经位于栈顶,那么就不会去创建新的实例,调用该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跳转到B时,由于栈中没有B,所以会新建B的实例并放入栈中;从B跳到B中,由于栈顶以经是B了,所以不会新建实例,而是会调用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在栈顶就不会创建新的实例。接下来我们看看如果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会创建新的实例。我们查看下任务栈看看是什么样的,任务栈中应该是 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,那么不会创建新的实例,如果该Activity不在栈顶,要启动这个Activity还是会创建新的实例。

模式3:singleTask 站内复用模式

在这种模式下,如果Activity存在于栈中,那么启动这个Activity不会创建新的实例,而是会调用onNewIntent(),并且将该Activity上面的所有Activity移出栈;当以singleTask 启动一个Activity的时候,首先去判断是否要为该Activity去创建一个任务栈?怎么判断的我们下面再讲,如果需要的话,那么就会创建一个任务栈,并且将该Activity放入栈中;如果不需要的话,直接将该Activity放入当前的任务栈中。

现在我们来讲怎么判断是否需要创建任务栈?任务栈的创建跟taskAffinity的属性相关,每个Activity都有taskAffinity属性,这个属性指出了它希望进入的Task。如果一个Activity没有显式的指明该Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果Application也没有指明,那么该taskAffinity的值就等于包名。

在singleTask 模式下,如果你在要启动的Activity中设置taskAffinity属性,且该属性的值不等于包名,那么就需要创建任务栈,否则不需要创建。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属性,所以直接创建B的实例并放在该栈中;

B->C->D:创建C和D的实例并放到栈中

D->B : 由于B已经存在栈中,所以直接将B移到栈顶,调用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跳转到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的实例,至于有没有创建对应的栈,log中看不出,等下通过adb来查看。

B->C->D:正常启动,创建C和D的实例并放入任务栈

D->B:由于B存在于任务栈中,所以直接将B移到栈顶,调用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,那么会创建一个任务栈,并把B放到创建的任务栈中,该栈只能有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需要的任务栈,所以先创建任务栈,然后将B压入栈

B->C:正常启动,创建C的实例并入栈。

C->B:不会创建B新的实例,而是调用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 会新建一个任务栈然后创建B的实例并压入该栈;B->C 直接创建C的实例并压入之前A所在的栈。

Activity的4种启动模式就写到这里,下面会写Intent中设置flag,以及taskAffinity。

阅读全文

举报

小猪快跑22访问量 6万+ 原创 54 博主更多文章>

Android中Activity的使用,简单实例讲解

qq_32175491 10449次阅读 2016-12-27 16:09:12

activity例子

shiyanming1223 8317次阅读 2015-02-28 22:11:30

通过官网的一个例子来看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的四种启动模式区别_launchmode图文详解

androidstar_cn 1409次阅读 2016-10-03 23:55:06

[Android开发]Activity的四种启动模式及其应用场景

CodeEmperor 26320次阅读 2016-01-08 11:39:41

Activity的4种启动模式

wl1fy 74次阅读 2017-03-28 18:08:42

更多相关文章

CSDN

CSDN精彩内容推荐

查看熊掌号

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容