Activtiy 的4种启动模式以及实际应用
activtiy的launchMode有四种:standard、singleTask、singleTop,singleInstance
在默认情况下,多次启动Activty时候,系统会创建多个实例,并压入任务栈中;当按back回退键时,会将activiy出栈,直到任务栈为空后,回收任务栈。
Standard:每次启动一个Activity就会创建新的实例,不管这个实例存不存在。这是一种典型的多实例实现,一个栈中可以有多个实例,每个实例也可以属于不同的任务栈;在此种模式下,谁启动了Activity,那这个Activtiy就运行在启动它的Activity所在的栈中。举个例子:Activity A启动了Activtiy B(B是standard模式),那么Activity B就运行在Activity A所在的任务栈中。如果你用一个非Activty 的context (例如:ApplicationContext),就会报错:
“ calling startactivity() from outside of an activity context requires the flag_activity_new_task flag”
这是因为,所启动的Activity会进入到启动它的Activity所在栈中,但是ApplicatinContext没有任务栈,所以,需要为带启动的Activty加上flag标记FLAG_ACTIVITY_NEW_TASK,这样在启动时,就会为它新创建一个任务栈,其实这个Activty就是以singleTask启动的了。
SingleTop:栈顶复用,即如果要启动的Activity在任务栈栈顶,则不会重新创建实例,而是直接用,此时它的onNewIntent()会回调,但是onCreate() onStart()不会回调。如果新Actiivtys实例存在但不在栈顶,则新的Activity需要重建。例如:栈内ABCD,现在要启动D(d是singleTop模式),则因为在栈顶,所以直接复用。如果是standard模式,栈内就是ABCDD.
SingleTask: 栈内复用模式。只要Activity在栈内,就不会重新创建,而是直接复用,并回调onNewIntent()方法。具体一点就是,例如如果要启动Activity A ,就先寻找是否存在A所需要的任务栈,如果不存在,就创建一个任务栈并创建Activity实例压入栈中;存在,就检查任务栈是否有Activty实例,如果有,就将A调到栈顶,并回调它的onNewIntent();如果不存在,就创建A的实例,压入栈中。
常见的几种例子如下:
假设目前任务栈S1中的Activity是 ABC,现要启动的Activity D singleTask模式启动, 如果
1)所需要的任务栈s2
则:因为任务栈s2和D均不存在,所以,先创建任务s2,再创建D,将D压入s2;
2)所需任务栈是s1
则:直接创建D并压入栈中
3)如果将前提改为S1中的Activity是 ADBC,且所需要的任务栈s1
则:系统不会重建D,而是会将D置于栈顶,并调用其newInstance().
singleTask本具有clearTop的功能,所以,会将位于D上面的所有Activity出栈,最终S1中只有AD。
SingleTask相关的情况:
情况一:假设前台任务栈AB,后台任务栈情况CD(luanchMode=singleTask),现在要启动D,则会发生如下图1-7所示:
1-7 任务栈示例.png
整个后台任务栈切为前台,此时前台任务栈ABCD,然后back 键,则一一出栈;
如果上面例子中改为要启动C,则任务栈情况如下1-8:
1-8任务栈示例.png
则前台任务栈情况是ABC,back键按下后,B、A依次出栈;
情况二:在singleTask 启动模式中,多次提到的Activty所需要的任务栈,这个所需的任务栈的名字就是通过taskAffinity来标识的,默认是应用的包名,也可以指定。TaskAffinity属性主要和singleTask启动模式和allowTaskReparenting配对使用,其他情况没有意义。
任务栈分前台任务栈、后台任务栈;后台任务栈的Activity暂停状态,用户可以切换将后台任务栈再次调到前台。
TaskAffinity和 allowTaskReparenting=true配对使用时,情况是:应用a启动应用B的Activity C,再点击home 返回到桌面,此时,打开应用B时候,就会直接到Activity C ;分析:由于A启动C,C应该在A的任务栈中,但是因为C属于应用B,正常情况下,C的TaskAffinity肯定不和A一样,此时启动应用B,B会创建自己的任务栈,系统发现C的任务栈已经存在,就会将C从A的任务栈转移回来。
SingleInstance: 单例模式。是加强的singleTask模式,除了具有singleTask特性外,还加强了一点:具有此luanchMode的activity只能单独地存在一个任务栈中,由于栈内复用原则,后续的请求均不会创建新的Activity,除非这个任务栈被销毁。
如何给Activity增加启动模式?2种方式:
1.AndroidManifest里面
2.通过在intent中设置flag:
Intent intent =new Intent();
intent.setClass(MainActivity.this,SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
2种方式有区别,优先级2高;1无法为Activity 指定 FLAG_ACTIVITY_CLEAR_TOP;2无法直接设定Activity的singleInstance模式
二、Activity四种启动模式常见使用场景:
这也是面试中最为长见的面试题;
lunchMode
singleTop :栈顶复用;适合登录页面 、消息推送WXPayEntryActivityWXEntryActivity
例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。
这里的WXEntryActivity:在WXEntryActivity中一定要参考官方的文档,实现onNewIntent(Intent intent)方法,这个方法为微信客户端分享成功后回调我们应用中的WXEntryActivity类,通过newintent(Intent intent)来启动WXEntryActivity类,并在newIntent方法中通过IWXAPI接口中的handleIntent方法,注册监听。
singleTask:
适合作为程序的主入口,
比如浏览器的主页面,不管从多少个地方启动主页面,都会启动主界面一次,其余情况走onNewInstance(),并会清空主页面上面的其他页面。
其他情况包括:程序逻辑模块入口页面:Fagment的containnerActiivty Webview 页面 扫一扫页面;电商中:购物界面、确认订单界面、付款界面‘
singleInstance:
适合需要与程序分离开的页面。例如闹钟提醒,与闹钟设置分离开
https://stackoverflow.com/questions/2626218/examples-for-android-launch-modes
使用 adb shell dumpsys
andriod studio 的terminal 中输入:Adb shell dumpsys检测Android的Activity任务栈
打印:
比较长,不再放了
信息:
每个stack 有n个task;
activity 是放在task里的;
每一个#Hist就是一个Activity