Activity的启动模式

来源:互联网 发布:三星s8打不开淘宝 编辑:程序博客网 时间:2024/05/20 07:14

一、任务栈
为了记录用户开启了那些activity,记录这些activity开启的先后顺序,google引入任务栈(task stack)概念,帮助维护好的用户体验。

1.一个应用程序一般都是由多个activity组成的。
2.任务栈(task stack)(别名back stack后退栈) 记录存放用户开启的activity的。
3.一个应用程序一被开启系统就给他分配一个任务栈,当所有的activity都退出的时候,任务栈就清空了。
4.任务栈的id是一个integer的数据类型 自增长的。
5.在android操作系统里面会存在多个任务栈,一个应用程序一个任务栈。
6.桌面应用和一般的应用程序是一样的,任务栈的行为也是一样。
7.默认情况下, 关闭掉一个应用程序,清空了这个应用程序的任务栈。应用程序的进程还会保留。

获取任务栈:

ActivityManager mActivityManager=(ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);List<RunningTaskInfo> l=mActivityManager.getRunningTasks(9999);

Activity启动模式设置:

<activity android:name=".MainActivity" android:launchMode="standard" />

二、使用manifest文件

1、standard(默认启动模式)

默认启动模式,每次激活Activity时都会创建Activity,并放入任务栈中。

写一个应用,创建3个Activity,分别为MainActivity、MainActivity2、MainActivity3,它们的启动模式为standard。

实验:每次都会创建一个新的Activity,将它放入当前的任务栈中。

在MainActivity中启动MainActivity2,在MainActivity2启动MainActivity3,在MainActivity3中再次启动MainActivity3。

03-14 14:32:23.042 5724-5724/? I/MainActivity: MainActivity:onCreate03-14 14:32:25.842 5724-5724/? I/MainActivity: MainActivity2:onCreate03-14 14:32:27.022 5724-5724/? I/MainActivity: MainActivity3:onCreate03-14 14:32:28.142 5724-5724/? I/MainActivity: MainActivity3:onCreate

很明显,MainActivity3被创建了两次。

2、singleTop

如果在任务的栈顶正好存在该Activity的实例, 就重用该实例(会调用实例的onNewIntent()),否者就会创建新的实例并放入栈顶(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例)。

写一个应用,创建3个Activity,分别为MainActivity、MainActivity2、MainActivity3,它们的启动模式为singleTop。

实验1:当启动的Activity在任务栈中存在,并且还位于任务栈的栈顶,会直接重用栈顶的那个Activity。

在MainActivity中启动MainActivity2,在MainActivity2启动MainActivity3,在MainActivity3中再次启动MainActivity3。

03-14 14:19:46.512 3511-3511/? I/MainActivity: MainActivity:onCreate03-14 14:19:49.732 3511-3511/? I/MainActivity: MainActivity2:onCreate03-14 14:19:51.362 3511-3511/? I/MainActivity: MainActivity3:onCreate03-14 14:19:52.742 3511-3511/? I/MainActivity: MainActivity3:onNewIntent

可以看到当在MainActivity3中再次启动Activity3的时候,没有执行onCreate,即没有创建一个新的Activity3,而是直接执行了原来栈顶那个MainActivity3的onNewIntent方法。当我们连续点击back按钮的时候:

03-14 14:24:38.902 4121-4121/? I/MainActivity: MainActivity3:onDestroy03-14 14:24:58.292 4121-4121/? I/MainActivity: MainActivity2:onDestroy03-14 14:24:59.382 4121-4121/? I/MainActivity: MainActivity:onDestroy

从这里也可以看出,MainActivity3只创建了一次。

实验2:当启动一个Activity在任务栈中存在,但是并不在任务栈的栈顶,它会再次创建这个Activity,并且把它放入当前的任务栈。

在MainActivity中启动MainActivity2,在MainActivity2启动MainActivity3,在MainActivity3中再次启动MainActivity2。

03-14 14:29:29.992 5002-5002/? I/MainActivity: MainActivity:onCreate03-14 14:29:35.192 5002-5002/? I/MainActivity: MainActivity2:onCreate03-14 14:29:38.382 5002-5002/? I/MainActivity: MainActivity3:onCreate03-14 14:29:40.752 5002-5002/? I/MainActivity: MainActivity2:onCreate

很明显就可以看到,MainActivity2被创建了两次。

3、singleTask

如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中。

实验:如果启动的Activity在栈中存在,但是不在栈顶,它也会重用这个Activity,并且将它上面的Activity全部移除。

在MainActivity中启动MainActivity2,在MainActivity2启动MainActivity3,在MainActivity3中再次启动MainActivity2。

03-14 14:36:29.882 6587-6587/? I/MainActivity: MainActivity:onCreate03-14 14:36:33.052 6587-6587/? I/MainActivity: MainActivity2:onCreate03-14 14:36:37.032 6587-6587/? I/MainActivity: MainActivity3:onCreate03-14 14:36:38.942 6587-6587/? I/MainActivity: MainActivity2:onNewIntent03-14 14:36:39.002 6587-6587/? I/MainActivity: MainActivity3:onDestroy

可以看到,当再次启动MainActivity2的时候,栈中已经存在这个实例,并且会将它上面的MainActivity3移除,使其位于栈顶。

singleTask的实质其实是为了让系统创建一个新的任务,并将启动的Activity放入这个新任务的栈底位置。但是从上面我们看到,它并没有创建新的任务栈,而是使用了当前的任务栈,并且如果栈中存在这个Activity,它会直接复用。原因是因为设置了singleTask启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity与它的属性值taskAffinity相同的任务栈是否存在;如果存在这样的任务栈,它就会在这个任务栈中启动,否则就会在新任务栈中启动。 由于同一个程序中所有Activity的affinity默认都是相同的,都是包名,所以当没有指定affinity的时候,当前任务栈的affinity跟它的affinity相同,它就没有重新创建一个任务栈,而是使用当前的任务栈。

实验:

写一个应用,创建3个Activity,分别为MainActivity、MainActivity2、MainActivity3,它们的启动模式为singleTask,另外将MainActivity2的taskAffinity值重新指定为”com.hupianpian.test2”,它是另一个应用的包名。

在MainActivity中启动MainActivity2,在MainActivity2启动MainActivity3,在MainActivity3中再次启动MainActivity2。

03-14 15:37:46.232 14071-14071/ I/MainActivity: MainActivity:onCreate03-14 15:37:49.882 14071-14071/ I/MainActivity: MainActivity2:onCreate03-14 15:37:53.702 14071-14071/ I/MainActivity: MainActivity3:onCreate03-14 15:37:59.682 14071-14071/ I/MainActivity: MainActivity2:onNewIntent

下面进入设备来查看任务栈,可以看到有两个任务栈,很显然,在启动Activity2的时候,创建了一个新的任务栈,并将它放在里面,一个任务栈里面放的是Activity和Activity3,另一个Activity2。当我再次启动Activity2的时候,它会重用另一个任务栈中的Activity2。

点击第一个任务栈,将Activity3置入前台,点击back按钮。

03-14 15:51:16.012 1800-1800/I/MainActivity: MainActivity3:onDestroy03-14 15:51:17.622 1800-1800/I/MainActivity: MainActivity:onDestroy

很明显,这个栈中只有两个Activity,一个是MainActivity3,一个是MainActivity。

点击另一个任务栈,将Activity2置入前台,点击back按钮。

03-14 15:53:24.792 8369-8369/I/MainActivity: MainActivity2:onDestroy

很明显,这个栈中只有Activity2。

再次查看手机的任务栈,发现两个任务栈仍然存在,一个栈顶是MainActivity,另一个栈顶是MainActivity2,很明显,它们都是之前栈底的那个Activity。当应用退出之后,并不代表任务栈也随着销毁,它的任务栈仍然是存在的,并且最底层的那个Activity存在于任务栈中。

4、singleInstance

每个activity实例都是单独放入一个栈中,该Activity所在的栈不能容纳除该Activity之外的其他Activity实例。启动一个Activity,如果这个Activity是第一次被创建,就在一个新栈中创建该Activity实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity的实例存在于某个栈中,任何应用再激活改Activity时都会重用该栈中的实例,其效果相当于多个应用程序共享一个应用,不管谁激活该Activity都会进入同一个应用中。

实验:

在MainActivity中启动MainActivity2,在MainActivity2启动MainActivity3,在MainActivity3中再次启动MainActivity,接着在MainActivity中又MainActivity2,在MainActivity2启动MainActivity3。

03-14 22:22:11.832 17669-17669/ I/MainActivity: MainActivity:onCreate03-14 22:22:13.702 17669-17669/ I/MainActivity: MainActivity2:onCreate03-14 22:22:15.102 17669-17669/ I/MainActivity: MainActivity3:onCreate03-14 22:22:17.502 17669-17669/ I/MainActivity: MainActivity:onNewIntent03-14 22:22:20.512 17669-17669/ I/MainActivity: MainActivity2:onNewIntent03-14 22:22:21.852 17669-17669/ I/MainActivity: MainActivity3:onNewIntent

可以看到第一次启动的时候会创建,下一次启动就直接重用了。

三、使用Intent flags

1、FLAG_ACTIVITY_NEW_TASK

新启动Activity,如果这个Activity是其他应用的Activity,并且其他应用的任务栈存在就会直接是这个任务栈,否则就会创建一个任务栈并放置到一个这个任务栈当中,如果这个Activity是当前应用的Activity,就会放入当前任务栈中,默认是standard,跟没有设置效果一样,所以它针对的是启动其他应用的Activity。

实验:
在当前应用中,把MainActivity,MainActivity2,MainActivity3都设置为FLAG_ACTIVITY_NEW_TASK,在MainActivity中启动MainActivity2,在MainActivity2启动MainActivity3,在MainActivity3中再次启动MainActivity,接着在MainActivity中又MainActivity2,在MainActivity2启动MainActivity3。

03-14 22:45:39.882 29473-29473/? I/MainActivity: MainActivity:onCreate03-14 22:45:58.522 29473-29473/? I/MainActivity: MainActivity2:onCreate03-14 22:46:01.652 29473-29473/? I/MainActivity: MainActivity3:onCreate03-14 22:46:06.042 29473-29473/? I/MainActivity: MainActivity:onCreate03-14 22:46:08.282 29473-29473/? I/MainActivity: MainActivity2:onCreate03-14 22:46:10.762 29473-29473/? I/MainActivity: MainActivity3:onCreate

可以看到只有一个任务栈,并且Activity每次启动都会重复创建,这个跟没有设置FLAG_ACTIVITY_NEW_TASK效果是一样的。

实验1:在一个应用中启动另一个应用的Activity,不设置flag为FLAG_ACTIVITY_NEW_TASK

Intent intent = new Intent();ComponentName cn = new ComponentName("com.test2", "com.test2.MainActivity2");intent.setComponent(cn);intent.addCategory(Intent.CATEGORY_DEFAULT);startActivity(intent);

可以看到新启动的Activity放入了当前的任务栈中。

实验2:在一个应用中启动另一个应用的Activity,设置flag为FLAG_ACTIVITY_NEW_TASK

Intent intent = new Intent();ComponentName cn = new ComponentName("com.test2", "com.test2.MainActivity2");intent.setComponent(cn);intent.addCategory(Intent.CATEGORY_DEFAULT);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);

可以看到,新启动的Activity放入一个新的任务栈中。

另外,如果一个Activity设置了FLAG_ACTIVITY_NEW_TASK,还可以指定它的affinity,让它根据affinity重新为Activity选择合适的宿主Task;

综上所述,可以这样总结,如果设置了FLAG_ACTIVITY_NEW_TASK,它代表的是在新任务栈中启动,但是它必须满足一些条件,它在启动的时候,会先在系统中查找属性值affinity与它的属性值taskAffinity相同的任务栈是否存在;如果存在这样的任务栈,它就会在这个任务栈中启动,否则就会在新任务栈中启动。 由于同一个程序中所有Activity的affinity默认都是相同的,都是包名,所以在同一个应用中启动Activity,它不会创建新的任务栈,而是使用当前任务栈,如果启动另一个应用的Activity,它会查看另一个应用的任务栈是否存在,如果存在就直接使用,不存在才会创建一个新的任务栈。这个跟singleTask有些像。

2、FLAG_ACTIVITY_SINGLE_TOP

这种flag和在launchMode中指定”singleTop”模式所实现的效果是一样的。

3、FLAG_ACTIVITY_CLEAR_TOP

一个Activity设置了这个标签,如果这个Activity没有在manifest中指定任何启动模式(为默认模式),并且Intent中也没有加入一个FLAG_ACTIVITY_SINGLE_TOP,那么此时启动这个Activity,如果栈中存在这个Activity实例,那么栈中包括这个Activity实例在内的之上的所以Activity都会被销毁,然后在重新创建该Activity并且放入任务栈。

实验:

在MainActivity中启动MainActivity2,在MainActivity2启动MainActivity3,在MainActivity3中再次启动MainActivity4,接着在MainActivity4中启动MainActivity2,并且设置flag为FLAG_ACTIVITY_CLEAR_TOP。

Intent intent = new Intent(this, MainActivity2.class);intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);startActivity(intent);
03-15 11:20:05.278 20598-20598/I/MainActivity: MainActivity:onCreate03-15 11:20:07.038 20598-20598/I/MainActivity: MainActivity2:onCreate03-15 11:20:08.478 20598-20598/I/MainActivity: MainActivity3:onCreate03-15 11:20:09.668 20598-20598/I/MainActivity: MainActivity4:onCreate03-15 11:20:10.938 20598-20598/I/MainActivity: MainActivity3:onDestroy03-15 11:20:10.958 20598-20598/I/MainActivity: MainActivity2:onDestroy03-15 11:20:10.978 20598-20598/I/MainActivity: MainActivity2:onCreate03-15 11:20:11.038 20598-20598/I/MainActivity: MainActivity4:onDestroy

可以看到当再次启动Activity2的时候,因为它已经存在,接着就将它在内的MainActivity2、MainActivity3、MainActivity4全部销毁,然后再次创建了一个MainActivity2。

如果Activity在manifest中指定了任何一种启动模式,或者是在Intent中加入了一个FLAG_ACTIVITY_SINGLE_TOP flag,当启动的Activity实例在任务中中存在,它会将该实例之上的Activity实例移除,并且调用该Activity的onNewIntent()方法。

实验:
在MainActivity中启动MainActivity2,在MainActivity2启动MainActivity3,在MainActivity3中再次启动MainActivity4,接着在MainActivity4中启动MainActivity2,并且设置flag为FLAG_ACTIVITY_CLEAR_TOP、FLAG_ACTIVITY_SINGLE_TOP。

Intent intent = new Intent(this, MainActivity2.class);intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);startActivity(intent);
03-15 12:16:42.138 5462-5462/ I/MainActivity: MainActivity:onCreate03-15 12:16:48.608 5462-5462/ I/MainActivity: MainActivity2:onCreate03-15 12:16:49.978 5462-5462/ I/MainActivity: MainActivity3:onCreate03-15 12:16:50.788 5462-5462/ I/MainActivity: MainActivity4:onCreate03-15 12:16:51.528 5462-5462/ I/MainActivity: MainActivity3:onDestroy03-15 12:16:51.538 5462-5462/ I/MainActivity: MainActivity2:onNewIntent03-15 12:16:51.598 5462-5462/ I/MainActivity: MainActivity4:onDestroy

可以看到当再次启动MainActivity2的时候,它会移除MainActivity2之上的MainActivity3、MainActivity4,直接复用MainActivity2。

FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_NEW_TASK结合在一起使用也会有比较好的效果,比如可以将一个后台运行的任务切换到前台,并把目标Activity之上的其它Activity全部关闭掉。这个功能在某些情况下非常有用,比如说从通知栏启动Activity的时候。

affinity主要有以下两种应用场景:

1、当调用startActivity()方法来启动一个Activity时,默认是将它放入到当前的任务当中。但是,如果在Intent中加入了一个FLAG_ACTIVITY_NEW_TASK flag的话(或者该Activity在manifest文件中声明的启动模式是”singleTask”),系统就会尝试为这个Activity单独创建一个任务。但是规则并不是只有这么简单,系统会去检测要启动的这个Activity的affinity和当前任务的affinity是否相同,如果相同的话就会把它放入到现有任务当中,如果不同则会去创建一个新的任务。而同一个程序中所有Activity的affinity默认都是相同的,这个前面讲到过。

2、当把Activity的allowTaskReparenting属性设置成true时,Activity就拥有了一个转移所在任务的能力。具体点来说,就是一个Activity现在是处于某个任务当中的,但是它与另外一个任务具有相同的affinity值,那么当另外这个任务切换到前台的时候,该Activity就可以转移到现在的这个任务当中。

比如有一个天气预报程序,它有一个Activity是专门用于显示天气信息的,这个Activity和该天气预报程序的所有其它Activity具体相同的affinity值,并且还将allowTaskReparenting属性设置成true了。这个时候,你自己的应用程序通过Intent去启动了这个用于显示天气信息的Activity,那么此时这个Activity应该是和你的应用程序是在同一个任务当中的。但是当把天气预报程序切换到前台的时候,这个Activity又会被转移到天气预报程序的任务当中,并显示出来,因为它们拥有相同的affinity值,并且将allowTaskReparenting属性设置成了true。

如何用户将任务切换到后台之后过了很长一段时间,系统会将这个任务中除了最底层的那个Activity之外的其它所有Activity全部清除掉。当用户重新回到这个任务的时候,最底层的那个Activity将得到恢复。

在元素中设置以下几种属性就可以改变系统这一默认行为:

alwaysRetainTaskState:如果将最底层的那个Activity的这个属性设置为true,任务中所有的Activity即使过了很长一段时间之后仍然会被继续保留。

clearTaskOnLaunch:如果将最底层的那个Activity的这个属性设置为true,那么只要用户离开了当前任务,再次返回的时候就会将最底层Activity之上的所有其它Activity全部清除掉。

finishOnTaskLaunch:这个属性和clearTaskOnLaunch是比较类似的,不过它不是作用于整个任务上的,而是作用于单个Activity上。如果某个Activity将这个属性设置成true,那么用户一旦离开了当前任务,再次返回时这个Activity就会被清除掉。

参考文章:Android任务和返回栈完全解析,细数那些你所不知道的细节

0 0
原创粉丝点击