经常混淆,转载的以备今后查看(原链接:https://www.jianshu.com/p/7f1c9fac2af2)
LaunchMode
在声明Activity的xml中指定 android:launchMode="xxx"
1.standard
标准模式。这是系统默认的模式,每次启动Activity都会重新创建一个新的Activity实例,也就是onCreate,onStart,onResume流程走一遍,并且一个任务栈里允许存在多个实例。
当我们使用ApplicationContext去启动Activity的时候,因为默认是standard模式会报错:Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
因为standard 模式默认启动的Activity会和启动它的Activity在同一任务栈,而由于ApplicationContext非Activity的Context,并没有所谓的任务栈,所以提示我们需要使用FLAG_ACTIVITY_NEW_TASK来新建一个任务栈并把启动的Activity放进去。
2.singleTop
栈顶复用模式。在同一个任务栈中栈顶如果有此Activity的实例,那么不会重新创建一个新实例,而是调用此Activity的onNewIntent,此时onCreate、onStart不会被调用。但如果此Activity在同一个任务栈但不在栈顶或之前用standard模式启动的,就会重新创建。
如ADBCD(第一个D不在栈顶则重新创建),ABCDD(第一个D为standard模式启动也会重新创建)。
3.singleTask
栈内复用模式。在同一个任务栈(注意:不一定是栈顶了)中如果有此Activity的实例,那么不会重新创建一个新实例,而是调用此Activity的onNewIntent,此时onCreate、onStart不会被调用。并且自带FLAG_ACTIVITY_CLEAR_TOP效果。
同一个栈内。如ADBC(要启动D,则把D挪到栈顶,BC由于clearTop而被移除栈,剩下AD)。
如果D指定栈为S2,android:taskAffinity="S2",而启动它的Activity栈为S1,则先创建S2栈然后再new D放到S2中。
注意和FLAG_ACTIVITY_CLEAR_TOP
的区别!!!
4.singleInstance
单例模式。这是一种加强的singleTask模式。除了singleTask模式所有特性外,它只能单独在一个任务栈中,跟其他Activity不能同时存在一个任务栈,整个Application也只有一个实例。
Intent的Flag
我们在代码里面通过Intent启动Activity的时候可以添加flag来设置启动的方式,如 : intent.addFlags(Intent.FLAG_ACTIVITY_XXX);
1.FLAG_ACTIVITY_CLEAR_TASK
此Activity将变成一个新Task中新的最底端的Activity,所有的之前此Activity实例和包含该实例的Task都会被关闭,这个标识仅仅和FLAG_ACTIVITY_NEW_TASK联合起来才能使用。
2.FLAG_ACTIVITY_NEW_TASK
与launchMode="singleTask"一样的效果。
FLAG_ACTIVITY_NEW_TASK标签必须配合taskAffinity属性使用,如果不设置taskAffinity属性值,将不会生成新task(新的栈)。
当从启动模式为singleInstance的Acitivity中启动新的Acitivity时,新的Activity自带FLAG_ACTIVITY_NEW_TASK标签。
3.FLAG_ACTIVITY_CLEAR_TOP
清除包含此Activity的Task中位于该Activity实例之上的其他Activity实例。这种行为的 launchMode 属性没有对应的值,只能通过代码设置。
单独使用的情况:ABCD 启动 B ,会销毁B和B以上的实例 变成 AB ,B 重新执行onCreate -> onStart
配合FLAG_ACTIVITY_SINGLE_TOP使用,则 B 不会销毁只销毁B以上实例,然后B 执行onNewIntent -> onRestart。(效果同singleTask一样)
配合FLAG_ACTIVITY_NEW_TASK则是singleTask效果
4.FLAG_ACTIVITY_SINGLE_TOP
与launchMode="singleTop"一样的效果。
5.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
设置了的话该Activity则不出现在最近使用的列表中。
6.FLAG_ACTIVITY_FORWARD_RESULT
如果A需要onActivityResult中获取返回结果,startActivityForResult B,而B只是过渡页,启动C之后就finish掉了,需要在 C 中setResult返回给A就可以用到这个标志。
A -> B -> XXXXX(无论多少个过渡页) 设置 FLAG_ACTIVITY_FORWARD_RESULT 来启动 C ,之后该XXX过渡页finish - > A ,那么C的结果返回给A
7.FLAG_ACTIVITY_NO_HISTORY
如果设置,新的Activity将不再历史stack中保留。用户一离开它,这个Activity就关闭了。
例如A启动B的时候,给B设置了FLAG_ACTIVITY_LAUNCHED_NO_HISTORY,那么:A -> B -> C ,启动C 就算 B没有自行finish ,也会变为 AC
8.FLAG_ACTIVITY_NO_ANIMATION
启动的时候不执行动画。
9.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
当用户点击Home,从历史中选择该Activity,系统会自动加上这个Flag。
10.FLAG_ACTIVITY_NO_USER_ACTION
在onPause()之前会调用onUserLeaving( )方法,如果使用了该标识,说明目标Activity不和用户交互,所以也就不需要回调onUserLeaving( )方法。
11A*.FLAG_ACTIVITY_BROUGHT_TO_FRONT
比方说我现在有A,在A中启动B,此时在A中Intent中加上这个标记。此时B就是以 FLAG_ACTIVITY_BROUGHT_TO_FRONT 这个启动的,此时在B中再启动C,D(正常启动C,D),如果这个时候在D中再启动B,这个时候最后的栈的情况是 A,C,D,B
具体应用:判断闪屏页的启动模式不为FLAG_ACTIVITY_BROUGHT_TO_FRONT
public class SplashActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
finish();
return;
}
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
startActivity(new Intent(SplashActivity.this, MainActivity.class));
finish();
}
}, 2000);
}
}
PS: 如果闪屏页的启动模式为FLAG_ACTIVITY_BROUGHT_TO_FRONT
,那么如果。。。某一刻跳转回闪屏页,那么task中间的页面将不会销毁!突然想到了FLAG_ACTIVITY_CLEAR_TASK
,你有没有相同的感受?哈哈哈
11B*.FLAG_ACTIVITY_REORDER_TO_FRONT
如果设置这个标记,新启动的Activity将会被放到它所属task的最前面
例如,假如有一个Task包含4个Activity:A,B,C,D.如果D通过调用startActivity( )来启动B,如果使用了这个标记,B将会排在这个task的最上面,也即现在的顺序变成了A,C,D,B。
如果使用了FLAG_ACTIVITY_CLEAR_TOP,这个标记将会被忽略。
12.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
如果设置该属性,并且这个Activity在一个新的Task中正在被启动或者被带到一个已经存在的Task的顶部,这时这个Task会被重置(即该Task中之前的Activity会被关闭),该Activity成为栈底第一个Activity。
13.FLAG_ACTIVITY_TASK_ON_HOME
把当前新启动的任务置于Home任务之上,也就是按back键从这个任务返回的时候会回到Home,即使这个不是他们最后看见的Activity。
注意这个标记必须和FLAG_ACTIVITY_NEW_TASK加上android:taskAffinity一起使用。
14.FLAG_DEBUG_LOG_RESOLUTION
用来调试,当设置这个标志的时候,在解析这个intent的时候,将会打出打印信息(queryIntent函数)。
15.FLAG_INCLUDE_STOPPED_PACKAGES 和 FLAG_DEBUG_LOG_RESOLUTION
从Android 3.1开始,给Intent定义了两个新的Flag,分别为FLAG_INCLUDE_STOPPED_PACKAGES和FLAG_EXCLUDE_STOPPED_PACKAGES,用来控制Intent是否要对处于停止状态的App起作用,顾名思义:
- FLAG_INCLUDE_STOPPED_PACKAGES:表示包含未启动的App
- FLAG_EXCLUDE_STOPPED_PACKAGES:表示不包含未启动的App
值得注意的是,Android 3.1开始,系统向所有Intent的广播添加了FLAG_EXCLUDE_STOPPED_PACKAGES标志。这样做是为了防止广播无意或不必要地开启未启动App的后台服务。如果要强制调起未启动的App,后台服务或应用程序可以通过向广播Intent添加FLAG_INCLUDE_STOPPED_PACKAGES标志来唤醒。
16.FLAG_FROM_BACKGROUND
Intent不光可以在Acitivity里面start,还可以从service里面启动,这个参数就表示这个Intent是从后台服务发起的。
17.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
区别于 FLAG_GRANT_READ_URI_PERMISSION 跟 FLAG_GRANT_WRITE_URI_PERMISSION, URI权限会持久存在即使重启,直到明确的用 revokeUriPermission(Uri, int) 撤销。 这个flag只提供可能持久授权。但是接收的应用必须调用ContentResolver的takePersistableUriPermission(Uri, int)方法实现 。
18.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
Uri 权限授予任何原始授权URI前缀匹配的URI。
19.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
结合FLAG_GRANT_READ_URI_PERMISSION 和 FLAG_GRANT_WRITE_URI_PERMISSION 使用。
Uri 权限授予任何原始授权URI前缀匹配的URI。如果没有这个标志则必须精确匹配Uri了。
20.FLAG_GRANT_READ_URI_PERMISSION 和 FLAG_GRANT_WRITE_URI_PERMISSION
临时访问读权限和写权限 。Intent的接受者将被授予 INTENT 数据 uri 或者 在ClipData 上的读/写权限。
21.FLAG_RECEIVER_FOREGROUND
当发送广播时,允许其接受者 在前台运行的拥有更高的优先级,更短的超时间隔。
22.FLAG_RECEIVER_NO_ABORT
如果是有序广播,不要允许接收者中断广播播。
23.FLAG_RECEIVER_REGISTERED_ONLY
设置之后就不能通过xml来注册监听这个广播了,必须动态注册。
很多毒病程序为了证保自己被止终后可以再次行运,都会在xml中册注一些系统广播,妄图利用这些系统高频广播来实现自动启。
比如在老版本的android系统中,毒病程序可以通过监听TIME_TICK来动启自己的service后台行运,做一些秘隐的作工,而且就算自己被kill失落了,也能很快重新动启。
而一旦这些系统广播加了flag FLAG_RECEIVER_REGISTERED_ONLY,这些毒病程序就没辙了。
例如系统的TIME_TICK广播,由AlarmManagerService发送,我们看源码可以看到
mTimeTickSender = PendingIntent.getBroadcast(context, 0,
new Intent(Intent.ACTION_TIME_TICK).addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY), 0);
这样就不能监听ACTION_TIME_TICK来自启动了。
24.FLAG_RECEIVER_REPLACE_PENDING
这个Flag 将会将之前的Intent 替代掉。加了这个Flag,在发送一系列的这样的Intent 之后,中间有些Intent 有可能在你还没有来得及处理的时候,就被替代掉了。
25.FLAG_ACTIVITY_NEW_DOCUMENT(原FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
可以跟FLAG_ACTIVITY_MULTIPLE_TASK结合使用,当只用自己的时候相当于Manifast中 android.R.attr.documentLaunchMode="intoExisting",当跟FLAG_ACTIVITY_MULTIPLE_TASK 结合使用相当于 Manifast中android.R.attr.documentLaunchMode="always"。
26.FLAG_ACTIVITY_RETAIN_IN_RECENTS
默认情况下通过FLAG_ACTIVITY_NEW_DOCUMENT启动的Activity在关闭之后,Task中的记录会相对应的删除。如果为了能够重新启动这个Activity你想保留它,就可以使用者个flag,最近的记录将会保留在接口中以便用户去重新启动。接受该Flag的Activity可以使用autoRemoveFromRecents去复写这个request或者调用Activity.finishAndRemoveTask( )方法。
27.FLAG_ACTIVITY_MULTIPLE_TASK
这个标识用来创建一个新的task栈,并且在里面启动新的activity(所有情况,不管系统中存在不存在该activity实例),经常和FLAG_ACTIVITY_NEW_DOCUMENT或者FLAG_ACTIVITY_NEW_TASK一起使用。这上面两种使用场景下,如果没有带上FLAG_ACTIVITY_MULTIPLE_TASK标识,他们都会使系统搜索存在的task栈,去寻找匹配intent的一个activity,如果没有找到就会去新建一个task栈;但是当和FLAG_ACTIVITY_MULTIPLE_TASK一起使用的时候,这两种场景都会跳过搜索这步操作无条件的创建一个新的task。和FLAG_ACTIVITY_NEW_TASK一起使用需要注意,尽量不要使用该组合除非你完成了自己的顶部应用启动器,他们的组合使用会禁用已经存在的task栈回到前台的功能。
taskAffinity 和 allowTaskReparenting
taskAffinity用于指定当前Activity所关联的Task,allowTaskReparenting用于配置是否允许该Activity可以更换从属Task,通常情况二者连在一起使用,用于实现把一个应用程序的Activity移到另一个应用程序的Task中。
allowTaskReparenting用来标记Activity能否从启动的Task移动到taskAffinity指定的Task,默认是继承至application中的allowTaskReparenting=false,如果为true,则表示可以更换;false表示不可以。
例如在A应用中启动了B应用的Activity,如果设置allowTaskReparenting=true,则Activity允许从A的Task移动到B的Task。但如果A被启动之后,Activity就会回到A的Task中。
关于onNewIntent
- singleInstance:
第一次进入:onCreate onStart
在栈顶再次进入: onNewIntent
不在栈顶再次进入:onNewIntent onRestart onStart
按home键再次进入:onRestart onStart
按返回键:onRestart onStart
- standard:
第一次进入:onCreate onStart
在栈顶再次进入: onCreate onStart
不在栈顶再次进入:onCreate onStart
按home键再次进入:onRestart onStart
按返回键:onRestart onStart
- singleTop:
第一次进入:onCreate onStart
在栈顶再次进入:onNewIntent
不在栈顶再次进入:onCreate onStart
按home键再次进入:onRestart onStart
按返回键:onRestart onStart
- singleTask:
第一次进入:onCreate onStart
在栈顶再次进入:onNewIntent
不在栈顶再次进入:onNewIntent onRestart onStart
按home键再次进入:onRestart onStart
按返回键:onRestart onStart
其实很好理解!!!