Activity的LaunchMode和taskAffinity
Thanks to:http://www.cnblogs.com/SteveMing/archive/2012/04/24/2459575.html
【原】Activity的LaunchMode和taskAffinity
做项目到现在都一直没有理解LaunchMode有什么用,或许根本就没真正花心思去看,所以今天把这部分整理下。
设置Activity的LaunchMode属性可以决定这个Activity是和当前Task保持关联,还是说每次运行这个Activity是新建一个实例,还是保持单例。
Task和Back Stack简介
task是一组Activities的集合,一组Activities被Stack(back stack)所管理。
在一个应用中,有3个activities,分别是activity1,activity2,activity3,首先activity1被start,此时,如果应用没有创建task则创建,并把activity1压入栈顶,activity1触发onCreate->onStart->onResume。
接着activity1转向到activity2时,activity1先触发onPause,activity2触发onCreate->onStart->onResume,然后activity1触发onPause->onStop,activity2压入栈顶。
以此类推,activity2转向activity3也是一样的步骤。那么当前栈顶是activity3。
当我们按下手机上的返回键时,栈顶的activity3触发onPause,activity2需要从状态stop到pause,所以触发了onPause->onStart->onResume,activity3触发onStop->onDestory,因为activity3从栈顶弹出,所以触发onDestory,此时,activity2在栈顶。
如果继续按返回键,当前栈顶的activity弹出并被destory,直到home界面。当所有的activity都弹出了,这个task也就消亡了。
当开始一个新的task时,前一个task被设置为后台,在后台,所有的activity都处理stop状态,但是back stack保留了所有后台activity的状态信息,只是丢失了焦点。
反复的在两个activity之间切换,activity会产生多个独立的实例。
查阅有关Activity生命周期更多说明。
两种方式设置LaunchMode属性
1. 在 manifest文件中设置
<activity android:name=".activity.ActivityA"android:launchMode="standard"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter> </activity>
2. 使用Intent flags设置
Intent intent = new Intent(); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setClass(ActivityA.this, ActivityB.class); startActivity(intent);
四种LaunchMode说明
standard
不做任何设置,默认模式就是standard,activity在每次start时,都会有一个新的实例被task管理。下面看下代码实例。
//ActivityA.java Intent intent = new Intent(); intent.setClass(ActivityA.this, ActivityB.class); startActivity(intent);//ActivityB.java Intent intent = new Intent(); intent.setClass(ActivityB.this, ActivityA.class); startActivity(intent);
操作1:在ActivityA(蓝)和ActivityB(绿)之间重复切换,按返回键推到home界面。
可以发现(蓝色86和绿色79的taskID)ActivityA和ActivityB都在同一个task,并且每次resume的实例都是不一样的。这说明在一个activity可以有多个实例在同一个task中。
在按返回按键时,将依次弹出stack。
singleTop
和standard一样,可以多次实例,但,如果处于当前栈顶并且接受到一个与当前activity一样类型的intent,那么不会创建一个新实例,而是触发onNewIntent()事件。
//ActivityA.java Intent intent = new Intent(); intent.setClass(ActivityA.this, ActivityA.class); startActivity(intent);@Override protected void onNewIntent(Intent intent) {logger.d("onNewIntent " + this.hashCode() + " taskID "+ this.getTaskId());super.onNewIntent(intent); }
<activity android:name=".activity.ActivityA" android:label="ActivityA"android:launchMode="singleTop"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter> </activity>
操作1:点击ActivityA上的按钮
发现当点击按钮是ActivityA->onPause->onNewIntent->onResume,没有新建新的实例(蓝62)。
这个模式在这个场景下比较有用,比如:如果有一个其他的应用想启动你的Activity(launch mode为singleTop),而你当前的Activity正好在栈顶,那么就会调用到onNewIntent方法。原文贴上:If an instance of the activity already exists at the top of the current task, the system routes the intent to that instance through a call to its onNewIntent()
method。
singleTask
系统会创建一个新task(如果没有启动应用)和一个activity新实例在新task根部,然后,如果activity实例已经存在单独的task中,系统会调用已经存在activity的 onNewIntent()
方法,而不是存在新实例,仅有一个activity实例同时存在。运用实例:浏览器主界面。不管跳转多少页面,主界面只启动一次,其余都走onNewIntent,并清空主界面上的其他页面。
<activity android:name=".activity.ActivityA" android:label="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=".activity.ActivityB" android:label="ActivityB" android:launchMode="singleTask"><intent-filter><action android:name="android.intent.action.MAIN" /></intent-filter> </activity> <activity android:name=".activity.ActivityC" android:label="ActivityC" android:launchMode="standard"><intent-filter><action android:name="android.intent.action.MAIN" /></intent-filter> </activity>
操作1:ActivityA->ActivityB->ActivityC->ActivityA->ActivityB->ActivityC
可以看到,当再次进入ActivityB时,没有onCreate,而是onNewIntent(绿55)。
这里我们也可以发现一个现象,当在调用到ActivityB的onNewIntent时,之前的ActivityA和ActivityC都调用了onDestory。也就是说,系统发现栈中存在ActivityB的实例时,ActivityA和ActivityB都弹栈了。
列出Log日志(这里设ActivityA的LaunchMode为singleTask),ActivityB和ActivityC都在onNewIntent前后调用了onDestory。
singleInstance
和singleTask相似,除了系统不会让其他的activities运行在所有持有的task实例中,这个activity是独立的,并且task中的成员只有它,任何其他activities运行这个activity都将打开一个独立的task。实例运用:适合与程序分离的页面,如闹铃提醒。
<activity android:name=".activity.ActivityA" android:launchMode="singleTask"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter> </activity> <activity android:name=".activity.ActivityB" android:launchMode="singleInstance"><intent-filter><action android:name="android.intent.action.MAIN" /></intent-filter> </activity> <activity android:name=".activity.ActivityC"><intent-filter><action android:name="android.intent.action.MAIN" /></intent-filter> </activity>
操作1:ActivityA->ActivityB->ActivityA
可以发现,两个Activity是在不同的Task中,其次,当调用到onNewIntent时,ActivityB没有被Destory,互不干涉。
操作2:ActivityA->ActivityB->ActivityC,按返回键
图解:
刚进入应用,创建TaskA,ActivityA为栈顶,从ActivityA到ActivityB,ActivityB进入TaskB(如果再次进入ActivityB,则不创建Task,调用onNewIntent),此时TaskB中的ActivityB为栈顶,从ActitivyB到ActivityC,ActivityC为栈顶。
一直按返回键,先从TaskA中依次将Activity弹出,然后再从TaskB中将ActiviyB弹出。ActiviyC->ActivityA->ActivityB。
这里分析一个问题,浏览器的LaunchMode为singleTask,所以如果当你点击一个连接下载文件时(由一个activity来处理下载,launchmode为standard),如果再次进入浏览器,那么下载页面就被Destory了,那么这里我们可以把下载页面LaunchMode设置为singleInstance可以解决这个问题。
Affinity定义
Affinity更像是表明了activity属于哪个task,默认情况下,应用所有的activities都有相同的affinity,所以都是在相同的task中。然后你可以编辑默认的affinity。Activities定义在不同的应用可以共享一个affinity,或者activities定义在相同的应用中可以被不同的affinities所关联。
你可以编辑在<activity>元素中
activity的taskAffinity属性。
先看看两种不同的情况下affinity的表现:
- 当运行一个activity包含了
FLAG_ACTIVITY_NEW_TASK标记
//ActivityA.java Intent intent = new Intent(); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setClass(ActivityA.this, ActivityB.class); startActivity(intent);
<activity android:name=".activity.ActivityA" android:taskAffinity="com.android.demo.affinity1"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter> </activity> <activity android:name=".activity.ActivityB" android:taskAffinity="com.android.demo.affinity2"><intent-filter><action android:name="android.intent.action.MAIN" /></intent-filter> </activity>
操作1:不同的affinity值,ActivityA->ActivityB
如果已经存在相同affinity,那么新activity运行在这个task中,否则,系统创建新task。
操作2:相同的affinity值,ActivityA->ActivityB
<activity android:name=".activity.ActivityA" android:taskAffinity="com.android.demo.affinity1"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter> </activity> <activity android:name=".activity.ActivityB" android:taskAffinity="com.android.demo.affinity2"><intent-filter><action android:name="android.intent.action.MAIN" /></intent-filter> </activity>
可以看出ActivityA和ActivityB都运行在同一个task中。
- 当Activity的
allowTaskReparenting的属性设为'true'
使用来表示是否允许activity重新附属其他Task,还是举例说明吧。
有两个应用,Demo1和Demo2,Demo1中有2个Activity(ActivityA,ActivityC),ActivityA可以转向到ActivityC,Demo2中有一个Activity(ActivityB),也可以转向到ActivityC。
操作1:设置ActivityC的allowTaskReparenting属性为true。
运行Demo2,转向到ActivityC,在ActivityC中打印信息,返回到HOME界面,运行Demo1。
//Demo1 //ActivityA.java Intent intent = new Intent(); intent.setClass(ActivityA.this, ActivityC.class); startActivity(intent);//ActivityC.java tv.setText(ActivityC.this.toString());//Demo2 //ActivityB.java Intent intent = new Intent(); intent.setClassName("com.android.demo","com.android.demo.activity.ActivityC"); ActivityB.this.startActivity(intent);
//Demo1 <activity android:name=".activity.ActivityA"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter> </activity> <activity android:name=".activity.ActivityC" android:allowTaskReparenting="true"><intent-filter><action android:name="android.intent.action.MAIN" /></intent-filter></activity> //Demo2 <activity android:name=".ActivityB"><intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter></activity>
运行结果:(黄色Demo1,绿色Demo2)
ActivityB转向到ActivityC,此时ActivityC就关联到Demo2的Task中,TaskID都为231。在运行Demo1时,看到是ActivityC而不是ActivityA。当再次进入Demo2时就看不到ActivityC了。
操作2:将ActivityC的taskAffinity设置为"com.android.demo.activityc"。
运行Demo2,转向到ActivityC,在ActivityC中打印信息,返回到HOME界面,运行Demo1。
//Demo1 <activity android:name=".activity.ActivityC"android:taskAffinity="com.android.demo.activityc"android:allowTaskReparenting="true"><intent-filter><action android:name="android.intent.action.MAIN" /></intent-filter></activity>
运行结果:
从结果中可以看出,Demo1和Demo2都拥有ActivityC,也就是说有2个Task里存在ActivityC,分别被Demo1和Demo2所使用。
操作3:将ActivityC和ActivityB的taskAffinity都设为"com.android.demo.activityc"。
运行Demo2,转向到ActivityC,在ActivityC中打印信息,返回到HOME界面,运行Demo1。
//Demo2 <activity android:name=".ActivityB" android:taskAffinity="com.android.demo.activityc"><intent-filter> <action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter> </activity>//Demo1 <activity android:name=".activity.ActivityC"android:taskAffinity="com.android.demo.activityc"android:allowTaskReparenting="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> </intent-filter> </activity>
运行结果:
和操作1相反,再进入Demo2时看到是ActivityC,进入Demo1都是看到ActivityA。
写到最后越来越崩溃了,如果有什么地方写的不对或不清楚请指明。
转帖请说明原文出处:http://www.cnblogs.com/SteveMing/archive/2012/04/24/2459575.html
另一篇 图文并茂 http://www.androidchina.net/3173.html
两种设置方式:
1) XML
<activity android:name=".ActivitySub"android:launchMode="singleInstance">
</activity>
2)在java代码中设置intent.setFlags()
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClass(this,ActivitySub.ckass);
startActivity(intent);
Activity的LaunchMode和taskAffinity相关推荐
- Android Activity的launchMode四种启动模式备忘
Android Activity的launchMode四种启动模式备忘 Android的Activity的启动模式有四种,在AndroidManifest.xml通过配置Activity的androi ...
- Activity的launchMode和任务栈小结
对Activity的launchMode的理解一直没有好好总结下,这两天系统总结下launchMode的使用方法: Activity的launchMode属性决定了Activity和应用程序当前任务栈 ...
- Activity之launchMode:singleTop,singleTask与singleInstance
相关内容,可以参见官方网址: http://developer.android.com/guide/components/tasks-and-back-stack.html 如图所示,如果ABC三个A ...
- Activity的launchMode启动模式 day7
2019独角兽企业重金招聘Python工程师标准>>> Activity的launchMode day7 在功能清单AndroidManifest.xml 里 设置 启动模式 如: ...
- Activity的LaunchMode情景思考
此链接:http://blog.csdn.net/xiaodongrush/article/details/28597855 1. 有哪几种类型?分别有什么用? http://developer.an ...
- activity 的属性android:taskAffinity和android:allowTaskReparenting
1.清单文件中,activity 的属性 android:allowTaskReparenting 这个属性用于设定Activity能够从启动它的任务中转移到另一个与启动它的任务有亲缘关系的任务中,转 ...
- Activity的LaunchMode
在Android中,启动一个Activity有时需要总是创建一个新的对象,有时需要重复使用以后的对象,可以通过在配置activity时通过LaunchMode属性指定. LaunchMode的属性值: ...
- Activity栈管理(三):Intent的Flag与taskAffinity
作者:anly_jun 链接:https://www.jianshu.com/p/c97688eb5056 引用上文生命周期和launchMode介绍, Activity的生命周期实际上比我们想象的复 ...
- android 当中taskAffinity属性与launchMode相关
一.本文尝试解释以下问题 1. Activity被启动之后放在哪个任务栈当中?与哪些因素有关? 2. Activity的四种启动模式对Activity的启动有哪些影响? 3. 在Activity ...
最新文章
- Java 并发专题 : Semaphore 实现 互斥 与 连接池
- 一套实用的数据中心设计方案
- 07- Firmware Update (FWU)
- mysql内存体系结构_Innodb存储引擎的体系架构之内存
- 内置的常用协议实现模版
- (一)uboot的移植与制作
- TCP 慢启动 拥塞控制
- 利用 QQWry.Dat 实现 IP 地址高效检索(PHP)
- 复工后,汉堡薯条、奶茶“续命”又开始了
- 52 - 算法- leetcode 14 最长公共前缀
- URAL-1998 The old Padawan 二分
- 【大话设计模式】模式二 :工厂模式
- ENVI5.3.1高分2号影像预处理流程
- git 上上下下左左右右AABB
- 设计logo原来这么简单
- python包和库的区别_python中模块、包、库的区别和使用
- 乐鑫Esp32学习之旅13 esp32 内置 dns 服务器,无需外网访问域名返回指定网页。(附带Demo)
- 埋石图根点lisp代码_速腾矿图 用户手册.pdf
- 2022年上半年全球知名企业十大数据泄露事件
- Spark not serializable 异常分析及解决方案
热门文章
- Java Swing井字游戏
- android中有哪些utils的作用,AndroidUtils
- html 不透明阴影,CSS_css box-shadow阴影不透明的解决办法,如下面示例: 复制代码代码如 - phpStudy...
- matlab如何添加度,matlab里的模糊工具箱绘制隶属度函数曲线导入到word的方法
- erosa mysql_MySQL协议和canal实现
- aes子密钥生成c语言_一种基于流密码算法的子密钥生成方法与流程
- 【安卓开发 】Android初级开发(一)控件通用属性
- java用户名检查数据库_登入界面账号密码是访问数据库,但登入问题时if判断时就是执行不了...
- C/C++高级算法之绘制曼德布洛特集
- mui 时间样式错乱_微信公众号素材样式中心在哪?公众号动态分割线怎么添加?...