图解Activity启动模式-参考官方文档

launchMode:

1.standard

如果启动该Activity的context是Activity,则新建一个Activity实例,该target Activity在source Activity的Task中。如果启动改Activity的context不是Activity,则新建一个Activity实例,并创建一个新的TaskRecord。

2.singleTop

如果启动该Activity的是Activity,那么看target Activity所在的Task的Top Activity是否与targetActivity同一类型,如果是同一类型,则调用Top Activity的onNewIntent(Intent),如果是不同类型,则创建一个target Activity实例放到Task顶部,并调用器onCreate()方法。这个模式下,Activity实例不是进程唯一,也不是Task唯一,而是指定Task的Top Activity类型唯一。当然Top Activity如果是pause状态,则在调用onNewIntent()前,将会调用onResume();

3.singleTask

在进程中只有一个实例。如果启动该Activity的是Activity,且两个Activity是同一应用,且target Activity没有声明taskAffinity属性,则target Activity与sourceActivity在同一task。sourceActivity 所在Task没有Target Activity类型的实例,则创建一个。source Activity所在Task存在一个target Activity类型的实例,则弹出其上的Activity,如下图:

如果ActivityB和Activity A不是在同一个应用定义的,那么ActivityB将在新的Task中。如果Activity B和Activity A是同一应用的,但是ActivityB声明了taskAffinity,那么ActivityB将在声明的task中,如果声明的task已存在,那么就去到那个task,如果不存在,则创建一个。如下图:

4.singleInstance

同singleTask类似,在进程中只有一个实例,但singleInstance更严格,即singleInstance=true的Activity,只能自己单独在一个Task。如果启动该Activity的是Activity,则会新创建一个TaskRecord给这个singleInstance实例,如果这个singleInstance需要启动另一个Activity,则会创建一个TaskRecord给这个Activity。如下图:

虽然singleInstance是会在一个独立的Task中,如果source Activity和target Activity属于同一进程的话,这个singleInstance和source Activity只能有一个在recents overview中出现,那么进入的source Activity可以用户从launcher那里进入,但用户可能找不到singleInstance的入口,除非在你的应用中提供一个入口。除以上说明的,其余的和singleTask是一样的。

flags:

1.FLAG_ACTIVITY_NEW_TASK

如果启动Activity的context是Activity,那么这个flag单独使用时,只对启动别的应用的Activity时有用。否则,如果sourceActivity和Target Activity是属于同一个apk的,需要结合android:taskAffinity属性使用(taskAffinity的值需要以a.b的形式)。

该Activity实例不存在时,则在指定的Task中创建一个。如果已存在,则将该实例所在Task调到前台,即显示该Task的Top Activity,注意,该Top Activity不一定是targetActivity,而且只会调用Top Activity的onResume(),而不会调用任何实例的onNewIntent()。当然在某些时候需要结合taskAffinity属性才能生效。

上图的状态2只适用于ActivityA和ActivityB属于同一应用。如果AcivityB和ActivityC跟ActivityA不是同一个进程的话,状态2则如下图所示:

如果AcivityB和ActivityC跟ActivityA不是同一个进程,但是想要上上图的效果,则需要Activity B声明如下,且在启动ActivityB是intent加上Activity B声明的action和category,同时带上FLAG_ACTIVITY_NEW_TASK

<intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

所以该flag和singleTask还是有很大区别的。singleTask是 FLAG_ACTIVITY_SINGLE_TOP +FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TOP的三者结合。

关于Context#startActivity(Intent,Bundle)注释说的,非Activity的Context,启动Activity都需要加上FLAG_ACTIVITY_NEW_TASK,因为不是从Activity启动的Activity,没有Task,但是实际运行7.0上不加该flag也是可以的。如果receiver是在ActivityA中注册的,那就该receiver启动的Activity就放到ActivityA所在的task。

2.FLAG_ACTIVITY_SINGLE_TOP

同launchMdoe中的singleTop

3.FLAG_ACTIVITY_CLEAR_TOP

如果是单独使用,且target Activity的launchMode是mutiple(默认的),则如下图:

如果是ActivityB的launchMode为其他值,又或者flag包含了FLAG_ACTIVITY_SINGLE_TOP,那么代替recreate一个实例的是,会去传递intent给onNewIntent()方法,如果这个实例之前是处于paused状态的,调用onNewIntent前会去调用onResume。

和FLAG_ACTIVITY_NEW_TASK结合使用,如果该实例已存在,那么会将实例所在的task带到前台,并实例本身及其上的activity实例,即recreate,而不是调用onNewIntent。

其他属性:

1.allowTaskReparenting

如果一个Activity B设置这个属性为true,且声明了taskAffinity="a.b"。此时别的应用从Launcher启动了(Activity A必须声明了android.intent.action.MAIN和android.intent.category.LAUNCHER),启动的这个ActivityB也声明了taskAffinity="a.b",注意这两个Activity必须是不同应用的。那么ActivityA启动后,Activity将从原来的task转移到Activity A所在的Task。只有create Activity A的时Activity B才可以转移。在Activity A非create,只是resume时是不可以转移的如下图:

官方文档举例的用途如下: 例如,如果电子邮件包含网页链接,则点击链接会调出可显示网页的 Activity。 该 Activity 由浏览器应用定义,但作为电子邮件任务的一部分启动。 如果将其父项更改为浏览器任务,它会在浏览器下一次转至前台时显示,当电子邮件任务再次转至前台时则会消失。

2.clearTaskOnLaunch

这个属性只对声明了android.intent.action.MAIN和android.intent.category.LAUNCHER的Activity有效。从Launcher启动时,将清除root Activity之上的所有Activity实例,如下图:

如果ActivityB的taskAffinity有值,且allowTaskReparenting="true",那么Activity B会被移到另外一个Task中,ActivityC依然调用onResume,但是在overviews中没有ActivityB的入口。文档是这样描述的:“如果该属性和allowTaskReparenting的值均为“true”,则如上所述,任何可以更改父项的 Activity 都将转移到与其有亲和关系的任务;其余 Activity 随即被移除。”

3.finishOnTaskLaunch

每当用户再次启动其任务(在主屏幕上选择任务)时,是否应关闭(完成)现有 Activity 实例 —“true”表示应关闭,“false”表示不应关闭。 默认值为“false”。

如果该属性和allowTaskReparenting均为“true”,则优先使用该属性。 Activity 的亲和关系会被忽略。 系统不是更改 Activity 的父项,而是将其销毁。

注意:该属性对非root Activity有效,即对声明android.intent.action.MAIN和android.intent.category.LAUNCHER的Activity无效。

示意图:

4.allowRemainTaskState

系统是否始终保持 Activity 所在任务的状态 —“true”表示保持,“false”表示允许系统在特定情况下将任务重置到其初始状态。 默认值为“false”。该属性只对任务的根 Activity 有意义;对于所有其他 Activity,均忽略该属性。

正常情况下,当用户从主屏幕重新选择某个任务时,系统会在特定情况下清除该任务(从根 Activity 之上的堆栈中移除所有 Activity)。 系统通常会在用户一段时间(如 30 分钟)内未访问任务时执行此操作。

不过,如果该属性的值是“true”,则无论用户如何到达任务,将始终返回到最后状态的任务。 例如,在网络浏览器这类存在大量用户不愿失去的状态(如多个打开的标签)的应用中,该属性会很有用。

flag launch conjunction

1.从Launcher点击应用使用的启动方式:

如果该在桌面的快捷图标对应的是一个应用,那么启动的Activity是该应用的manifest中声明了android.intent.action.MAIN和android.intent.category.LAUNCHER的Activity,启动的intent包含android.intent.action.MAIN和android.intent.category.LAUNCHER,还必须包含FLAG_ACTIVITY_NEW_TASK,否则该Activity就会在Launcher的Task中。使用Launcher的这种方式,可以把对应Activity所在的Task带到前台,显示Task中的Top Activity。如果不加上android.intent.action.MAIN和android.intent.category.LAUNCHER,则会在对应Task的顶部create一个Activity。如果只加android.intent.action.MAIN和android.intent.category.LAUNCHER而不加上FLAG_ACTIVITY_NEW_TASK,则target Activity会在source Activity所在Task中。

2.在声明了android.intent.action.MAIN和android.intent.category.LAUNCHER,且使用了singleTask

Launcher在启动这个Activity时,就完全按照singleTask前面所说的方式了。Android系统自带的设置应用,就是这种情况,所以每次从Launcher进入Settings,都是去到主界面,而不会回到之前的Top Activity。只能从overview中才能去到Top,因为RecentsActivity和Launcher的启动方式不一样,估计使用的是FLAG_ACTIVITY_NEW_TASK和FLAG_ACTVITY_SINGLE_TOP,而且启动的Activity不是声明了MAIN和LAUNCHER的那个,而是启动Top Activity。

3.注意setFlags和addFlags的区别

setFlags会把之前的覆盖了,而addFlags是追加。

官方文档:

https://developer.android.google.cn/guide/components/activities/tasks-and-back-stack#TaskLaunchModes

猜你喜欢

转载自blog.csdn.net/b1480521874/article/details/82698789