赞
踩
activity作为Android四大组件之首是非常重要的,有时候为了满足项目的需求,就必需要使用activity的启动模式,所以我们必须要搞清楚它的启动模式和标志位,本片文章将会一一介绍。
首先要说一下Android默认activity的启动模式是多实例启动也就是我们常说的standard模式。我们知道当我们多次启动同一个activity的时候,系统会创建多个实例并把它放到一个activity任务栈中。当我们点击返回的时候就会发现activity会一一回退。任务栈是一种“后进先出”的数据结构,没按一次back键就会有一个activity出栈,直到栈为空为止,当任务栈为空的时候,系统就会回收这个任务栈。Android系统的activity的启动模式有四种:standard,singleTop,singleTask,singleInstance。
standard:标准模式,这个是activity的模式启动模式。每次启动都会创建一个新的activity实例,不管这个实例是否在任务栈中存在。被创建的实例都会执行activity的所有生命周期。这种模式下,谁启动了这个activity,那么这个activity就会运行在启动他的那么个activity任务栈中。当我们用ApplicationContext去启动一个activity的时候就会报如下错误:
Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
这是一位standard模式的activity模式会进入启动它的activity所属的任务栈中,而由非activity类型的Context并没有任务栈所以就报错了。解决这个问题也很简单从报错的信息中也可以看出,只要在启动的时候给Intent加入FLAG_ACTIVITY_NEW_TASK 标记位,这要启动的时候就会创建一个新的任务栈,这个时候待启动的Activity实际上是以singleTask模式启动的。
singleTop:栈顶复用模式。这种模式下如果新的Activity已经位于栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被执行,通过此方法的参数我们可以去到当前的请求信息。需要注意的是这时候它的onCreate、onStart不会被执行。如果新的Activity不是位于任务栈的栈顶,那么新的Activity就会被重新创建。这时候任务 栈中就会有多个想通过Activity在我们点击back回退的时候就可以看到多个这样的页面。
singleTask:栈内复用模式。这是一种但实例模式,在这种模式下,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,和singleTop一样,系统会调用onNewIntent方法。当一个具有singleTask模式的Activity请求启动后,比如ActivityA,系统首先寻找是否存在A想要的任务栈,如果没有就会创建一个任务栈,然后创建A的实例后把A放到任务栈中。如果存在A想要的任务栈,那么就看A时候在任务栈中存在实例,如果实例存在,那么系统就会把A调到栈顶并调用它的onNewIntent方法,如果实例不存在,就创建A实例并把它压入栈中。
注意:singleTask有clearTop的特性。
singleInstance:单例模式。这是一种加强的singleTask模式,它除了具有 singleTask所有的特性外,还加强强了一点,就是具有此种模式的Activity只能单独的位于一个任务栈中。比如Activity A 是singleInstance模式,当A启动后,系统会为它创建一个新的任务栈,然后A独自在这个任务栈中,由于栈内复用的特性,后续的请求均不会创建行的Activity实例,除非这个独特的任务栈被系统销毁。
要想明白这个问题,我们就要了解TaskAffinity这个参数。这个参数标识了一个Activity所需的任务栈的名字,默认情况下activity所需的任务栈的名字为应用的包名。当然,我们可以为每一个activity都单独指定一个TaskAffinity属性,这个属性的值必须不是应用的包名否则相当于没有指定。TaskAffinity属性主要和singleTask启动模式或allowTaskReparenting配合使用,在其他情况下使用没有任何意义。
任务栈可以分为:
前台任务栈
后台任务栈
后台任务栈中的activity都处于暂停状态,用户可以通过切换将后台任务栈再次调到前台。
当taskAffinity与singleTask启动模式配对使用的时候,待启动的Activity会运行在名字和taskAffinity指定的相同名字的任务栈中
当taskAffinity与allowTaskReparenting结合使用的时候,会产生特殊的效果。比如:当一个应用A 启动了应用B的某个Activity C后,如果这个Activity的allowTaskReparenting为true,那么当B应用被启动后,此Activity C会直接从应用A的任务栈转到应用B的任务栈中。说白了就是用户从桌面启动应用B时看到的并不是B应用主Activity而是Activity C。
在manifest配置文件中通过launchMode属性指定
<activity android:name=".SecondActivity"
android:launchMode="singleTask"/>
通过代码中给Intent设置标记位指定
Intent intent = new Intent(this, SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
这两种都可以指定activity的启动模式但是他们两个是有区别的。
1.第二种方式要比第一种方式优先级高,两种同时存在的时候和以第二种方式为准。
2.两种方式在限定范围上不同。第一种方式无法直接给指定FLAG_ACTIVITY_CLEAR_TOP标识,第二种无法指定singleInstance模式。
我们通过adb shell dumpsys activity 命令来查看activity任务栈的情况,从而验证我们上面提到的内容
验证standard启动模式的效果
比如我们的MainActivity的启动模式standard模式,然后我们连续点击2次按钮启动MainActivity ,通过命令可以看到如下任务栈信息
ACTIVITY MANAGER STARTER (dumpsys activity containers)
com.android.server.wm.RootActivityContainer@7730899 type=undefined mode=fullscreen override-mode=undefined
#0 ActivityDisplay={0 numStacks=2} type=undefined mode=fullscreen override-mode=fullscreen
#1 ActivityStack{8005903 stackId=972 type=standard mode=fullscreen visible=true translucent=false, 1 tasks} type=standard mode=fullscreen override-mode=undefined
#0 TaskRecord{835a356 #944 A=com.gjb.activitylaunchmode U=0 StackId=972 sz=3} type=standard mode=fullscreen override-mode=undefined
#2 ActivityRecord{8335841 u0 com.gjb.activitylaunchmode/.MainActivity t944} type=standard mode=fullscreen override-mode=undefined
#1 ActivityRecord{83359c9 u0 com.gjb.activitylaunchmode/.MainActivity t944} type=standard mode=fullscreen override-mode=undefined
#0 ActivityRecord{8462191 u0 com.gjb.activitylaunchmode/.MainActivity t944} type=standard mode=fullscreen override-mode=undefined
#0 ActivityStack{7d20bb2 stackId=0 type=home mode=fullscreen visible=false translucent=true, 1 tasks} type=home mode=fullscreen override-mode=fullscreen
#0 TaskRecord{78f7d31 #4 A=com.huawei.android.launcher U=0 StackId=0 sz=1} type=home mode=fullscreen override-mode=undefined
#0 ActivityRecord{7f72f91 u0 com.huawei.android.launcher/.unihome.UniHomeLauncher t4} type=home mode=fullscreen override-mode=undefined
从上面的任务栈中我们可以看到,目前有两个任务栈一个是系统的launch一个我们写的测试应用。同时,我们也可以看到有3个MainActivity的ActivityRecord,每一个ActivityRecord代表着一个Activity实例。
验证singleTop启动模式的效果
现在我们有两个activity一个是应用程序的主Activity 即 MainActivity 它的启动模式是standard模式,另一个是SecondActivity 它的启动模式是singleTop。我们先通过MainActivity启动SecondActivity然后再在SencodActivity点击按钮启动一个SecondActvity,然后,通过命令查看任务栈的信息如下:
ACTIVITY MANAGER STARTER (dumpsys activity containers)
com.android.server.wm.RootActivityContainer@7730899 type=undefined mode=fullscreen override-mode=undefined
#0 ActivityDisplay={0 numStacks=2} type=undefined mode=fullscreen override-mode=fullscreen
#1 ActivityStack{83d31e4 stackId=1015 type=standard mode=fullscreen visible=true translucent=false, 1 tasks} type=standard mode=fullscreen override-mode=undefined
#0 TaskRecord{7cd4556 #987 A=com.gjb.activitylaunchmode U=0 StackId=1015 sz=2} type=standard mode=fullscreen override-mode=undefined
#1 ActivityRecord{80f0409 u0 com.gjb.activitylaunchmode/.SecondActivity t987} type=standard mode=fullscreen override-mode=undefined
#0 ActivityRecord{81e2791 u0 com.gjb.activitylaunchmode/.MainActivity t987} type=standard mode=fullscreen override-mode=undefined
#0 ActivityStack{7d20bb2 stackId=0 type=home mode=fullscreen visible=false translucent=true, 1 tasks} type=home mode=fullscreen override-mode=fullscreen
#0 TaskRecord{78f7d31 #4 A=com.huawei.android.launcher U=0 StackId=0 sz=1} type=home mode=fullscreen override-mode=undefined
#0 ActivityRecord{7f72f91 u0 com.huawei.android.launcher/.unihome.UniHomeLauncher t4} type=home mode=fullscreen override-mode=undefined
从上面的栈信息中我们可以看到,我们虽然启动了两次SecondActivity,但是,我们只在任务栈中找到了它的一个实例。说明singleTop启动模式是顶部复用的。
如果我们在启动SecondActivity后再启动一个ThirdActivity,然后再通过ThirdActivity启动一个SecondActivity,这时候任务栈是什么样子的呢?我们通过命令查看一下。
ACTIVITY MANAGER STARTER (dumpsys activity containers)
com.android.server.wm.RootActivityContainer@7730899 type=undefined mode=fullscreen override-mode=undefined
#0 ActivityDisplay={0 numStacks=2} type=undefined mode=fullscreen override-mode=fullscreen
#1 ActivityStack{83195b2 stackId=1019 type=standard mode=fullscreen visible=true translucent=false, 1 tasks} type=standard mode=fullscreen override-mode=undefined
#0 TaskRecord{835a37b #991 A=com.gjb.activitylaunchmode U=0 StackId=1019 sz=4} type=standard mode=fullscreen override-mode=undefined
#3 ActivityRecord{83ad721 u0 com.gjb.activitylaunchmode/.SecondActivity t991} type=standard mode=fullscreen override-mode=undefined
#2 ActivityRecord{83ad759 u0 com.gjb.activitylaunchmode/.ThirdActivity t991} type=standard mode=fullscreen override-mode=undefined
#1 ActivityRecord{83a6721 u0 com.gjb.activitylaunchmode/.SecondActivity t991} type=standard mode=fullscreen override-mode=undefined
#0 ActivityRecord{82d6959 u0 com.gjb.activitylaunchmode/.MainActivity t991} type=standard mode=fullscreen override-mode=undefined
#0 ActivityStack{7d20bb2 stackId=0 type=home mode=fullscreen visible=false translucent=true, 1 tasks} type=home mode=fullscreen override-mode=fullscreen
#0 TaskRecord{78f7d31 #4 A=com.huawei.android.launcher U=0 StackId=0 sz=1} type=home mode=fullscreen override-mode=undefined
#0 ActivityRecord{7f72f91 u0 com.huawei.android.launcher/.unihome.UniHomeLauncher t4} type=home mode=fullscreen override-mode=undefined
通过上面的任务栈信息可以看到,我们现在任务栈中有两个SecondActivity实例。这一点可以说明如果具有SingleTop模式的Activity不在任务栈的顶部,那么就会重新创建新的实例而不是复用任务栈中的实例。
验证singleTask启动模式的效果
我们把上面的例子中SecondActivity的启动模式改为SingleTask,我们在通过命令来查看一下任务栈的情况
ACTIVITY MANAGER STARTER (dumpsys activity containers)
com.android.server.wm.RootActivityContainer@7730899 type=undefined mode=fullscreen override-mode=undefined
#0 ActivityDisplay={0 numStacks=2} type=undefined mode=fullscreen override-mode=fullscreen
#1 ActivityStack{8250086 stackId=1023 type=standard mode=fullscreen visible=true translucent=false, 1 tasks} type=standard mode=fullscreen override-mode=undefined
#0 TaskRecord{81eb853 #995 A=com.gjb.activitylaunchmode U=0 StackId=1023 sz=2} type=standard mode=fullscreen override-mode=undefined
#1 ActivityRecord{8653b91 u0 com.gjb.activitylaunchmode/.SecondActivity t995} type=standard mode=fullscreen override-mode=undefined
#0 ActivityRecord{8653bc9 u0 com.gjb.activitylaunchmode/.MainActivity t995} type=standard mode=fullscreen override-mode=undefined
#0 ActivityStack{7d20bb2 stackId=0 type=home mode=fullscreen visible=false translucent=true, 1 tasks} type=home mode=fullscreen override-mode=fullscreen
#0 TaskRecord{78f7d31 #4 A=com.huawei.android.launcher U=0 StackId=0 sz=1} type=home mode=fullscreen override-mode=undefined
#0 ActivityRecord{7f72f91 u0 com.huawei.android.launcher/.unihome.UniHomeLauncher t4} type=home mode=fullscreen override-mode=undefined
从上面的任务栈信息中我们可以看到,目前任务栈中只有两个Activity 一个是MainActivity一个是SecondActivity。从这一点可以看出singleTask是栈内复用的。还可以看出一点是她具有clearTop的特性,因为我们并没有看到我们启动的ThirdActivity的实例。
验证singleInstance启动模式的效果
ACTIVITY MANAGER STARTER (dumpsys activity containers)
com.android.server.wm.RootActivityContainer@7730899 type=undefined mode=fullscreen override-mode=undefined
#0 ActivityDisplay={0 numStacks=3} type=undefined mode=fullscreen override-mode=fullscreen
#2 ActivityStack{8406f03 stackId=1030 type=standard mode=fullscreen visible=true translucent=false, 1 tasks} type=standard mode=fullscreen override-mode=undefined
#0 TaskRecord{835a30c #1002 A=com.gjb.activitylaunchmode U=0 StackId=1030 sz=1} type=standard mode=fullscreen override-mode=undefined
#0 ActivityRecord{816cd59 u0 com.gjb.activitylaunchmode/.SecondActivity t1002} type=standard mode=fullscreen override-mode=undefined
#1 ActivityStack{8406e86 stackId=1029 type=standard mode=fullscreen visible=false translucent=true, 1 tasks} type=standard mode=fullscreen override-mode=undefined
#0 TaskRecord{835a3c5 #1001 A=com.gjb.activitylaunchmode U=0 StackId=1029 sz=2} type=standard mode=fullscreen override-mode=undefined
#1 ActivityRecord{80b3a41 u0 com.gjb.activitylaunchmode/.ThirdActivity t1001} type=standard mode=fullscreen override-mode=undefined
#0 ActivityRecord{816cc09 u0 com.gjb.activitylaunchmode/.MainActivity t1001} type=standard mode=fullscreen override-mode=undefined
#0 ActivityStack{7d20bb2 stackId=0 type=home mode=fullscreen visible=false translucent=true, 1 tasks} type=home mode=fullscreen override-mode=fullscreen
#0 TaskRecord{78f7d31 #4 A=com.huawei.android.launcher U=0 StackId=0 sz=1} type=home mode=fullscreen override-mode=undefined
#0 ActivityRecord{7f72f91 u0 com.huawei.android.launcher/.unihome.UniHomeLauncher t4} type=home mode=fullscreen override-mode=undefined
从上面的任务栈信息可以看出singleInstance模式启动的Activity会被单独的放到一个任务栈中,把其他模式启动的Activity放到另一个任务栈中。
注意:通过任务栈我们同时也可以发现一个问题,这时候当我们按返回键的时候就会发现ThirdActivity会回退到MainActivity,然后MainActivity在回退就会看到我们的SecondActivity。
注意:还有一个问题就是当用户启动SecondActivity后直接按Home键,将应用切换到后台,然后再通过点击应用图标重新打开应用,你会惊奇的发现我们看到的页面并不是SecondActivity而是MainActivity。这是因为我们在重新打开应用的时候系统会首先去寻找有没有主的任务栈(也就是主Activity所在的任务栈),如果有,那么就会直接显示主的任务栈中的Activity
验证singleTask与taskAffinity配合使用的效果
首先我们如果taskAffinity不配合SingleTask使用任务栈会使什么情况呢
<activity android:name=".SecondActivity"
android:taskAffinity="com.guojingbu.task"/>
ACTIVITY MANAGER STARTER (dumpsys activity containers)
com.android.server.wm.RootActivityContainer@7730899 type=undefined mode=fullscreen override-mode=undefined
#0 ActivityDisplay={0 numStacks=2} type=undefined mode=fullscreen override-mode=fullscreen
#1 ActivityStack{847fc54 stackId=1065 type=standard mode=fullscreen visible=true translucent=false, 1 tasks} type=standard mode=fullscreen override-mode=undefined
#0 TaskRecord{78d4278 #1035 A=com.gjb.activitylaunchmode U=0 StackId=1065 sz=2} type=standard mode=fullscreen override-mode=undefined
#1 ActivityRecord{813c641 u0 com.gjb.activitylaunchmode/.SecondActivity t1035} type=standard mode=fullscreen override-mode=undefined
#0 ActivityRecord{7ffbd91 u0 com.gjb.activitylaunchmode/.MainActivity t1035} type=standard mode=fullscreen override-mode=undefined
#0 ActivityStack{7d20bb2 stackId=0 type=home mode=fullscreen visible=false translucent=true, 1 tasks} type=home mode=fullscreen override-mode=fullscreen
#0 TaskRecord{78f7d31 #4 A=com.huawei.android.launcher U=0 StackId=0 sz=1} type=home mode=fullscreen override-mode=undefined
#0 ActivityRecord{7f72f91 u0 com.huawei.android.launcher/.unihome.UniHomeLauncher t4} type=home mode=fullscreen override-mode=undefined
从上面的任务信息可以看出taskAffinity不配合SingleTask模式使用的话是根本没有什么作用的。
taskAffinity配合SingleTask使用时任务栈的情况
<activity android:name=".SecondActivity"
android:launchMode="singleTask"
android:taskAffinity="com.guojingbu.task"/>
ACTIVITY MANAGER STARTER (dumpsys activity containers)
com.android.server.wm.RootActivityContainer@7730899 type=undefined mode=fullscreen override-mode=undefined
#0 ActivityDisplay={0 numStacks=3} type=undefined mode=fullscreen override-mode=fullscreen
#2 ActivityStack{812e51c stackId=1070 type=standard mode=fullscreen visible=true translucent=false, 1 tasks} type=standard mode=fullscreen override-mode=undefined
#0 TaskRecord{7c14453 #1040 A=com.guojingbu.task U=0 StackId=1070 sz=1} type=standard mode=fullscreen override-mode=undefined
#0 ActivityRecord{81eb079 u0 com.gjb.activitylaunchmode/.SecondActivity t1040} type=standard mode=fullscreen override-mode=undefined
#1 ActivityStack{812e49f stackId=1069 type=standard mode=fullscreen visible=false translucent=true, 1 tasks} type=standard mode=fullscreen override-mode=undefined
#0 TaskRecord{7c1450c #1039 A=com.gjb.activitylaunchmode U=0 StackId=1069 sz=1} type=standard mode=fullscreen override-mode=undefined
#0 ActivityRecord{81eb009 u0 com.gjb.activitylaunchmode/.MainActivity t1039} type=standard mode=fullscreen override-mode=undefined
#0 ActivityStack{7d20bb2 stackId=0 type=home mode=fullscreen visible=false translucent=true, 1 tasks} type=home mode=fullscreen override-mode=fullscreen
#0 TaskRecord{78f7d31 #4 A=com.huawei.android.launcher U=0 StackId=0 sz=1} type=home mode=fullscreen override-mode=undefined
#0 ActivityRecord{7f72f91 u0 com.huawei.android.launcher/.unihome.UniHomeLauncher t4} type=home mode=fullscreen override-mode=undefined
从上面的任务栈信息可以看出taskAffinity配合singleTask使用的时,这个Activity就会启动到你指定的与taskAffinity值相同的名字的任务栈中。
需要注意的是这种情况也是会出现home键了以后重新启动应用看到的并不是SecondActivity的情况。原因和singleInstance的原因是一致的(具体看singleinstance的第二个注意内容)。
taskAffinity与allowTaskReparenting配合使用的效果
我们通过两个应用A和B来验证这种效果,比如我们通过A应用的启动顺序MainActivity->SecondActivity->B应用的CActivity,然后我们按Home键点击B应用的图标我们这时候看到的并不是B应用的主页面而是B应用的Cactivity。
allowTaskReparenting :这个属性的作用就是将此Activity从启动它的任务栈中转移到此Activity自己所属的任务栈中去。
ACTIVITY MANAGER STARTER (dumpsys activity containers) com.android.server.wm.RootActivityContainer@7730899 type=undefined mode=fullscreen override-mode=undefined #0 ActivityDisplay={0 numStacks=4} type=undefined mode=fullscreen override-mode=fullscreen #3 ActivityStack{7ecbc9f stackId=1131 type=standard mode=fullscreen visible=true translucent=false, 1 tasks} type=standard mode=fullscreen override-mode=undefined #0 TaskRecord{7ba1d31 #1101 A=com.gjb.bapp U=0 StackId=1131 sz=1} type=standard mode=fullscreen override-mode=undefined #0 ActivityRecord{8307609 u0 com.gjb.bapp/.CActivity t1101} type=standard mode=fullscreen override-mode=undefined #2 ActivityStack{7d20bb2 stackId=0 type=home mode=fullscreen visible=false translucent=true, 1 tasks} type=home mode=fullscreen override-mode=fullscreen #0 TaskRecord{78f7d31 #4 A=com.huawei.android.launcher U=0 StackId=0 sz=1} type=home mode=fullscreen override-mode=undefined #0 ActivityRecord{7f72f91 u0 com.huawei.android.launcher/.unihome.UniHomeLauncher t4} type=home mode=fullscreen override-mode=undefined #1 ActivityStack{809f535 stackId=1130 type=standard mode=fullscreen visible=false translucent=true, 1 tasks} type=standard mode=fullscreen override-mode=undefined #0 TaskRecord{7ba1da0 #1100 A=com.guojingbu.task U=0 StackId=1130 sz=1} type=standard mode=fullscreen override-mode=undefined #0 ActivityRecord{7fe8a79 u0 com.gjb.activitylaunchmode/.SecondActivity t1100} type=standard mode=fullscreen override-mode=undefined #0 ActivityStack{809f422 stackId=1129 type=standard mode=fullscreen visible=false translucent=true, 1 tasks} type=standard mode=fullscreen override-mode=undefined #0 TaskRecord{7ba1ce7 #1099 A=com.gjb.activitylaunchmode U=0 StackId=1129 sz=1} type=standard mode=fullscreen override-mode=undefined #0 ActivityRecord{7fe1159 u0 com.gjb.activitylaunchmode/.MainActivity t1099} type=standard mode=fullscreen override-mode=undefined
以上就是我对Android中Activity启动模式的总结。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。