Android基础之Intent Flag案例分析

在Android开发中,启动Activity时执行startActivity时,常常会在Intent对象中加入一些Flag来修改Activity与Task的关联方式,常见的有以下几种:

  • FLAG_ACTIVITY_NEW_TASK
  • FLAG_ACTIVITY_CLEAR_TASK
  • FLAG_ACTIVITY_BROUGHT_TO_FRONT
  • FLAG_ACTIVITY_CLEAR_TOP
  • FLAG_ACTIVITY_SINGLE_TOP
  • FLAG_ACTIVITY_NO_HISTORY
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

为了清楚地弄懂这些标志,写了一个Demo来加深理解,先依次看官方解释。

FLAG_ACTIVITY_NEW_TASK

FLAG_ACTIVITY_NEW_TASK
If set, this activity will become the start of a new task on this
history stack. A task (from the activity that started it to the
next task activity) defines an atomic group of activities that the
user can move to. Tasks can be moved to the foreground and background;
all of the activities inside of a particular task always remain in
the same order. See
Tasks and Back Stack for more information about tasks.

This flag is generally used by activities that want
to present a “launcher” style behavior: they give the user a list of
separate things that can be done, which otherwise run completely
independently of the activity launching them.

When using this flag, if a task is already running for the activity
you are now starting, then a new activity will not be started; instead,
the current task will simply be brought to the front of the screen with
the state it was last in. See {@link #FLAG_ACTIVITY_MULTIPLE_TASK} for a flag
to disable this behavior.

This flag can not be used when the caller is requesting a result from
the activity being launched.

官方这段话的意思就是当存在一个task与你将要启动的目标Activity的task的taskAffinity相同时,就将目标Activity压入该task中,否则就创建一个新的task;当一个task中已经在运行目标Activity,那么再以这个Flag启动目标Activity时,不会创建新的实例,而是将该task转到前台,并恢复其最后的状态。常见的用法就是在Service中启动Activity时,如果不加这个Flag则会报错,因为task只是针对Activity而言的,而Service不会存在于task中,返回栈也是如此。
先来看Demo,在Demo中我新建了3个Activity,分别为MainActivity, Main2Activity, Main3Activity.它们的launchMode都是默认的standard。在每个Activity中有一个TextView来显示该Activity的信息和taskid,一个Button来跳转,首先在MainActivity点击Button启动Main2Activity,在Main2Activity点击Button启动Main3Activity,在Main3Activity点击Button启动MainActivity,在启动时都加上FLAG_ACTIVITY_NEW_TASK标志,看看效果:

I/secray: MainActivity: com.sye.launchmode1.MainActivity@9f6a467
                        task id = 1271
I/secray: Main2Activity: com.sye.launchmode1.Main2Activity@d8e6b37
                        task id = 1271
I/secray: Main3Activity: com.sye.launchmode1.Main3Activity@a04e122
                        task id = 1271
I/secray: MainActivity: com.sye.launchmode1.MainActivity@227d7d0
                        task id = 1271

看Log会发现taskid没有变化,这说明了在一个应用内部没有指定task时,加这个标志是任何意义的,当然除了Service中启动Activity。
接下来验证下当一个task中存在目标Activity时,以该Flag再次启动目标Activity的情况,首先再定义一个Activity,为Main4Activity,然后设置Main2ActivityMain3ActivitytaskAffinitycom.android.test:

<activity
    android:name=".Main2Activity"
    android:taskAffinity="com.android.test" />
<activity
    android:name=".Main3Activity"
    android:taskAffinity="com.android.test"/>

MainActivity以及Main4Activity保持默认不变,并且Intent都加了FLAG_ACTIVITY_NEW_TASK,具体启动流程为:
这里写图片描述

我们看运行结果:

I/secray: MainActivity: com.sye.launchmode1.MainActivity@a7a4475
                        task id = 1275
I/secray: Main2Activity: com.sye.launchmode1.Main2Activity@7409c5
                         task id = 1276
I/secray: Main3Activity: com.sye.launchmode1.Main3Activity@271b021
                         task id = 1276
I/secray: Main4Activity: com.sye.launchmode1.Main4Activity@e9b9e3d
                         task id = 1275

当我们指定了不同taskAffinity时,再使用FLAG_ACTIVITY_NEW_TASK时就会创建一个新的task,所以Main2ActivityMain3Activitytaskid才会不同;再看启动流程,在Main4Activity启动Main2Activity时,没有Log输出,这就刚好验证了官方的解释,当存在含有目标Activity的task存在时,不会重新创建对象,而是将该task转到前台,并保持该task最后的状态,所以在这个实例中你会看到的是Main3Activity的界面。有的人可能会问,跨应用会怎么样,其实只要弄懂了Task和返回栈,跨应用也是一个道理。
接下来看看返回栈的情况,一直按返回键,你会发现返回顺序是这样的:
img
具体原因暂不分析,有兴趣可以去参考一下官方文档
BTW,值得注意的是在设置了taskAffinity的同时必须要使用FLAG_ACTIVITY_NEW_TASK启动目标Activity,否则还是同一个task。

FLAG_ACTIVITY_CLEAR_TASK

FLAG_ACTIVITY_CLEAR_TASK
If set in an Intent passed to Context.startActivity(), this flag will cause any existing task that would be associated with the activity to be cleared before the activity is started. That is, the activity becomes the new root of an otherwise empty task, and any old activities are finished. This can only be used in conjunction with FLAG_ACTIVITY_NEW_TASK.

翻译过来就是当以该Flag启动Activity时,会将与目标Activity关联的task清空,目标Activity会成为task的根Activity,这个标志只能与FLAG_ACTIVITY_NEW_TASK结合使用。
我们还是用Demo来说话,首先将4个Activity启动方式全恢复为默认,启动流程还是上面那样逐个启动,在Main3Activity启动Main4Activity时,设置该标志:

Intent intent = new Intent(Main3Activity.this, Main4Activity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);

运行程序,用dump命令adb shell dumpsys activity activitys查看task信息:

Running activities (most recent first):
TaskRecord{ddff686 #1357 A=com.sye.launchmode1 U=0 StackId=1 sz=4}
Run #3: ActivityRecord{53c9538 u0 com.sye.launchmode1/.Main4Activity t1357}
Run #2: ActivityRecord{47a652 u0 com.sye.launchmode1/.Main3Activity t1357}
Run #1: ActivityRecord{646181c u0 com.sye.launchmode1/.Main2Activity t1357}
Run #0: ActivityRecord{a31c6f2 u0 com.sye.launchmode1/.MainActivity t1357}

会发现没有任何变化,并没有清空掉task,修改一下:

Intent intent = new Intent(Main3Activity.this, Main4Activity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
        | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);

再次查看task信息:

Running activities (most recent first):
TaskRecord{8ec3eec #1358 A=com.sye.launchmode1 U=0 StackId=1 sz=1}
Run #0: ActivityRecord{6258990 u0 com.sye.launchmode1/.Main4Activity t1358}

这样才清空了task,所以FLAG_ACTIVITY_CLEAR_TASKFLAG_ACTIVITY_NEW_TASK结合使用才有效果,否则没有任何作用。

FLAG_ACTIVITY_BROUGHT_TO_FRONT

This flag is not normally set by application code, but set for you by the system as described in the launchMode documentation for the singleTask mode.

这个标志一般不需要我们去设置,在launchModesingleTask时,默认设置该标志。
一般情况下是不会设置该标志,但是我这里还是验证一下结果,在Main4Activity中启动Main2Activity,并加上该标志,运行Demo,看看结果:

Running activities (most recent first):
TaskRecord{8df2851 #1359 A=com.sye.launchmode1 U=0 StackId=1 sz=5}
Run #4: ActivityRecord{72df7cc u0 com.sye.launchmode1/.Main2Activity t1359}
Run #3: ActivityRecord{3e2af46 u0 com.sye.launchmode1/.Main4Activity t1359}
Run #2: ActivityRecord{910fc70 u0 com.sye.launchmode1/.Main3Activity t1359}
Run #1: ActivityRecord{55145ca u0 com.sye.launchmode1/.Main2Activity t1359}
Run #0: ActivityRecord{7cd83a4 u0 com.sye.launchmode1/.MainActivity t1359}

结果发现,单独使用该标志没有任何效果,还是会创建一个Activity实例,所以一般都不会设置该标志。

FLAG_ACTIVITY_CLEAR_TOP

If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
For example, consider a task consisting of the activities: A, B, C, D. If D calls startActivity() with an Intent that resolves to the component of activity B, then C and D will be finished and B receive the given Intent, resulting in the stack now being: A, B.
The currently running instance of activity B in the above example will either receive the new intent you are starting here in its onNewIntent() method, or be itself finished and restarted with the new intent. If it has declared its launch mode to be “multiple” (the default) and you have not set FLAG_ACTIVITY_SINGLE_TOP in the same intent, then it will be finished and re-created; for all other launch modes or if FLAG_ACTIVITY_SINGLE_TOP is set then this Intent will be delivered to the current instance’s onNewIntent().
This launch mode can also be used to good effect in conjunction with FLAG_ACTIVITY_NEW_TASK: if used to start the root activity of a task, it will bring any currently running instance of that task to the foreground, and then clear it to its root state. This is especially useful, for example, when launching an activity from the notification manager.

当设置了该标志,并且当前任务中已经运行了正在启动的目标Activity,那么不会创建一个新的实例,而是将任务中目标Activity上的Activity全部销毁,并且将Intent传给位于任务顶部的目标ActivityonNewIntent方法处理。值得注意的是如果是设置launchModestandard时,目标Activity会销毁重建,而设置了launchModesingleTop或者设置标志位为FLAG_ACTIVITY_SINGLE_TOP时,就不会销毁重建目标Activity,我们用Demo来验证下:
Main4Activity中启动Main2Activity,并设置该标志:

Intent intent = new Intent(Main4Activity.this, Main2Activity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

运行Demo,查看结果:

I/secray: MainActivity: com.sye.launchmode1.MainActivity@e566b1f
                        task id = 1360
I/secray: Main2Activity: com.sye.launchmode1.Main2Activity@c4416fc
                         task id = 1360
I/secray: Main3Activity: com.sye.launchmode1.Main3Activity@7f2b948
                         task id = 1360
I/secray: Main4Activity: com.sye.launchmode1.Main4Activity@2d9aa54
                         task id = 1360
I/secray: Main2Activity: com.sye.launchmode1.Main2Activity@8173bd9
                         task id = 1360

task结构信息:

Running activities (most recent first):
TaskRecord{ad5cc97 #1360 A=com.sye.launchmode1 U=0 StackId=1 sz=2}
Run #1: ActivityRecord{ec8b818 u0 com.sye.launchmode1/.Main2Activity t1360}
Run #0: ActivityRecord{5b9427 u0 com.sye.launchmode1/.MainActivity t1360}

从Log可以看出来的确是销毁重建了一个Main2Activity实例压入current task中,dump信息则可以看出销毁了Main2Activity之上的Activity
换一种方式来验证,上面是一个task中验证的,下面从不同的task来验证下该标志,我们设置Main2ActivityMain3Activity为不同的task,与FLAG_ACTIVITY_NEW_TASK中实例一样taskcom.android.test,启动顺序还是相同,Main4Activity中启动Main2Activity,看看结果:

I/secray: MainActivity: com.sye.launchmode1.MainActivity@44c5ebe
                        task id = 1365
I/secray: Main2Activity: com.sye.launchmode1.Main2Activity@599c0ce
                         task id = 1366
I/secray: Main3Activity: com.sye.launchmode1.Main3Activity@9278f3a
                         task id = 1366
I/secray: Main4Activity: com.sye.launchmode1.Main4Activity@245de66
                         task id = 1365
I/secray: Main2Activity: com.sye.launchmode1.Main2Activity@7eb8edd
                         task id = 1365

有的人可能觉得疑惑,明明Main2Activity设置了taskAffinity,为什么还是和MainActivity一个task,如果仔细看了官方文档就明白了,当前task不存在目标Activity时,会重新创建一个Activity实例压入当前task中,所以这里不管Main2Activity是否设置了taskAffinity,目标Activity一定会属于当前task的。

FLAG_ACTIVITY_SINGLE_TOP

If set, the activity will not be launched if it is already running at the top of the history stack.

很简单的一个标志,与launchMode之一singleTop效果一样。就是说在当前栈栈顶已经是目标Activity,那么不会再启动目标Activity。例如有三个Activity,A,B,C,依次启动,那么在C中以该标志启动C时,不会再启动C了,栈中只有A,B,C三个Activity,如果在C中以此标志启动B,那么会重新启动B,栈中Activity顺序为A,B,C,B。
比如说Demo中存在四个Activity,将启动方式和Intent标志都恢复成默认,在Main4Activity再次启动Main4Activity,并且Intent设置Flag为FLAG_ACTIVITY_SINGLE_TOP,用dump命令看看task信息:

Running activities (most recent first):
TaskRecord{a55d02a #7574 A=com.sye.launchmode1 U=0 StackId=1 sz=4}
Run #3: ActivityRecord{ffd663b u0 com.sye.launchmode1/.Main4Activity t7574}
Run #2: ActivityRecord{aa1167d u0 com.sye.launchmode1/.Main3Activity t7574}
Run #1: ActivityRecord{296242f u0 com.sye.launchmode1/.Main2Activity t7574}
Run #0: ActivityRecord{2b82211 u0 com.sye.launchmode1/.MainActivity t7574}

修改一下代码,在Main4Activity中以相同的方式启动Main2Activity,再看dump信息:

Running activities (most recent first):
TaskRecord{b2f2aa8 #7575 A=com.sye.launchmode1 U=0 StackId=1 sz=5}
Run #4: ActivityRecord{b2cb442 u0 com.sye.launchmode1/.Main2Activity t7575}
Run #3: ActivityRecord{967ba8c u0 com.sye.launchmode1/.Main4Activity t7575}
Run #2: ActivityRecord{ba7ac06 u0 com.sye.launchmode1/.Main3Activity t7575}
Run #1: ActivityRecord{668e330 u0 com.sye.launchmode1/.Main2Activity t7575}
Run #0: ActivityRecord{6ae830b u0 com.sye.launchmode1/.MainActivity t7575}

很明显,在Main4Activity之上还启动了一个Main2Activity。结合两个dump信息可以很好地验证上面所述。

FLAG_ACTIVITY_NO_HISTORY

If set, the new activity is not kept in the history stack. As soon as the user navigates away from it, the activity is finished. This may also be set with the noHistory attribute.
If set, onActivityResult() is never invoked when the current activity starts a new activity which sets a result and finishes.

当设置该标志启动目标Activity,只要目标Activity再启动其他Activity,目标Activity就会finish掉,这个标志还可以通过AndroidMainifest.xml文件Activity的属性noHistory来设置。只要设置了该属性,onActivityResult()将不会被触发。

回到Demo中,我们将MainActivity启动Main2Activity的Intent标志设置为FLAG_ACTIVITY_NO_HISTORY

Intent intent = new Intent(MainActivity.this, Main2Activity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);

其余Activity为默认,依次启动至Main4Activity,查看dump信息:

Running activities (most recent first):
TaskRecord{1aeb0bc #7578 A=com.sye.launchmode1 U=0 StackId=1 sz=3}
Run #2: ActivityRecord{4ffe4b6 u0 com.sye.launchmode1/.Main4Activity t7578}
Run #1: ActivityRecord{623aa60 u0 com.sye.launchmode1/.Main3Activity t7578}
Run #0: ActivityRecord{304ec39 u0 com.sye.launchmode1/.MainActivity t7578}

Main2Activity启动Main3Activity之后,就会finish掉,所以task中不包含Main2Activity了。

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

If set, the new activity is not kept in the list of recently launched activities.

这个标志在AndroidMainifest.xml文件中也有一个属性对应——android:excludeFromRecents。设置该标志后,目标Activity不会存在在最近任务列表中。
该标志适用于task的root Activity,为什么这么说呢,比如说在Main2Activity设置android:excludeFromRecents属性,那么在同一个task中,最近任务列表中还是会存在Main2Activity,如果我们设置Main2Activity为一个task的根Activity,不加该属性,效果是这样的:
这里写图片描述
加了该属性:

<activity
    android:name=".Main2Activity"
    android:excludeFromRecents="true"
    android:taskAffinity="com.android.test"/>

后,效果是这样的:
这里写图片描述

所以该属性一般设置在一个task的根Activity上,不然没什么意义。
上面几种FLAG是开发中比较常用的,还有很多FLAG,可以参考官方文档
dump命令可以去看gityuan大神的blog

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Android 12 Intent有以下Flag:FLAG_ACTIVITY_NEW_TASK、FLAG_ACTIVITY_CLEAR_TASK、FLAG_ACTIVITY_CLEAR_TOP、FLAG_ACTIVITY_SINGLE_TOP、FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS和FLAG_ACTIVITY_NO_HISTORY。 ### 回答2: Android 12引入了一些新的intent标记(flag),以便开发者可以在应用程序之间进行更好的通信和交互。以下是Android 12中的一些intent标记(flag): 1. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS( 0x00800000):当启动一个Activity时,可以使用此标记将其排除在最近使用应用程序列表之外。这意味着即使用户最近使用了该应用,也不会在最近使用应用程序列表中显示该Activity。 2. FLAG_ACTIVITY_NEW_TASK( 0x10000000):使用此标记启动一个新的任务(Task)。如果当前没有活动的任务正在运行,它将创建一个新的任务;否则将在已有任务中启动Activity。 3. FLAG_ACTIVITY_CLEAR_TASK(0x00008000):使用此标记启动一个新的Activity时,会清除任务(Task)中所有已存在的Activity,只保留新启动的Activity。 4. FLAG_ACTIVITY_TASK_ON_HOME(0x00004000):使用此标记启动一个新的Activity时,如果它已经是该任务的根Activity,则将该任务移动到后台并显示Home屏幕。 5. FLAG_ACTIVITY_FORWARD_RESULT(0x02000000):使用此标记启动一个新的Activity,并将结果返回给启动它的Activity。 6. FLAG_ACTIVITY_NO_ANIMATION(0x00010000):使用此标记启动一个新的Activity时,将禁用转场动画效果。 需要注意的是,这只是Android 12中的一些intent标记(flag),还有其他标记(flag)可以根据开发者的需求来使用。这些标记(flag)的灵活使用可以提供更好的用户体验和应用程序之间的交互功能。 ### 回答3: Android 12中的Intent有很多不同的flag,每个flag都有特定的作用。以下是一些常用的Intent flag: 1. FLAG_ACTIVITY_NEW_TASK: 这个flag用于指定新的Activity位于一个新的任务栈中,而不是当前任务栈。 2. FLAG_ACTIVITY_CLEAR_TOP: 这个flag用于将目标Activity之上的所有Activity都移除栈顶,从而保证目标Activity位于栈顶。 3. FLAG_ACTIVITY_SINGLE_TOP: 这个flag用于指定如果目标Activity已经处于栈顶,则不会创建新的实例,而是调用其onNewIntent()方法。 4. FLAG_ACTIVITY_REORDER_TO_FRONT: 这个flag用于重新调整Activity栈,将目标Activity移到前台。 5. FLAG_ACTIVITY_CLEAR_TASK: 这个flag用于在启动新的Activity时清除所有该任务栈中的其他Activity。 6. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS: 这个flag用于指定某个Activity不会出现在最近使用的应用列表中。 7. FLAG_ACTIVITY_NO_ANIMATION: 这个flag用于指定启动Activity时不使用任何转场动画效果。 8. FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET: 这个flag用于在任务重置时清除目标Activity之上的所有Activity。 以上是Android 12中一些常见的Intent flag,这些flag可以帮助开发者在启动Activity时指定其行为和特性。根据具体的需求,可以选择适当的flag来达到预期的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值