在Android应用程序中,Activity是核心组件。如何生成Activity实例,可以选择不同的启动模式,即LaunchMode。启动模式主要有:standard、singleTop、singleTask、singleInstance。标准模式每次启动,都会创建一个实例;三种单例模式会根据情况选择创建或者复用实例。在Activity启动时,创建实例的生命周期:onCreate->onStart->onResume;复用实例的生命周期:onNewIntent->onResume。在AndroidManifest的Activity中,使用launchMode属性设置启动模式,默认为标准模式;使用taskAffinity属性,加上包名,可以设置Activity栈,默认为当前包名,只能应用于单机模式。希望通过这篇文章,大家可以更好的了解Activity的启动模式(LaunchMode)。观察Activity栈的脚本。adbshel??ldumpsysactivity|sed-n-e'/Stack#/p'-e'/Runningactivities/,/Run#0/p'Standard,启动Activity的默认模式,启动的Activity会运行在启动的Activity栈上,所以必须用Activity的Context启动,不能用Application,否则会报错。例如MainActivity启动TestAActivity.Stack#1:Runningactivities(mostrecentfirst):TaskRecord{3caa65e3#2711A=me.chunyu.spike.wcl_activity_launchmode_demoU=0sz=2}Run#1:ActivityRecord{36b06e99u0me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivityt2711}运行#0.ActivityRecord2.chunyu0spike2711}运行#0.6ike2.chunyu0spike2739ity_launchmode_demo/.MainActivityt2711}Stack#0:Ru??nningactivities(mostrecentfirst):TaskRecord{27d796c9#2695A=com.miui.homeU=0sz=1}Run#0:ActivityRecord{2e5712cbu0com.miui.home/.launcher.Launchert}by269底部到顶部:MainActivity->TestAActivity.SingleTop栈顶多路复用模式。只有Activity位于堆栈的顶部。反复重启时,会使用默认实例,即单例模式;如果它在堆栈中,它仍然会创建一个实例。MainActivity启动TestA,TestA启动TestB,TestB启动自己,TestB是一个单例。观察栈中的情况,TestB只有一个实例,第二次创建被复用。Stack#1:Runningactivities(mostrecentfirst):TaskRecord{12abf566#2712A=me.chunyu.spike.wcl_activity_launchmode_demoU=0sz=3}Run#2:ActivityRecord{187d7ff7u0me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivityt2712}Run#1:ActivityRecord{a551034u0me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivityt2712}Run#0:ActivityRecord{22f9cce4u0me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivityt2712}Inthestack:MainActivity->TestAActivity->TestBActivityMainActivity启动TestA,TestA启动TestB,TestB启动TestC,TestC启动TestB,TestB为单例。观察栈中的情况,因为TestC在栈顶,TestC启动TestB,TestB不在栈顶,重新创建TestB实例,然后保留两份TestB.Stack#1:Runningactivities(mostrecentfirst):TaskRecord{1792f5f0#2715A=me.chunyu.spike.wcl_activity_launchmode_demoU=0sz=5}运行#4:ActivityRecord{1e70110bu0me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivityt2715}运行#3:ActivityRecord{c7f4dceu0me.chunyu.spike.wcl_activity_launchmode_demo/.TestCActivityt2715}运行#2:ActivityRecord{254536clunyudespike.chunyudespike.chun/.TestBActivityt2715}运行#1:ActivityRecord{36b2da15u0me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivityt2715}运行#0:ActivityRecord{3a1c4a6au0me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivityt2715}栈内:MainActivity->BActivity测试->BActivityTestCActivity->TestBActivitySingleTask栈内部多路复用模式,只要Activity存在于栈中,多次调用时不会创建实例,即单例模式。包括以下几种情况:(1)任务栈不存在,第一次创建SingleTask实例。任务堆栈和实例。MainActivity启动TestA,TestA启动TestB,TestB是一个SingleTask,任务栈不同。可以看出系统包含两个任务栈,TestB位于其他任务栈Stack#1:Runningactivities(mostrecentfirst):TaskRecord{d5d53d4#??2727A=me.chunyu.spike.stackU=0sz=1}Run#2:ActivityRecord{1d720e55u0me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivityt2727}TaskRecord{a3f797d#2726A=me.chunyu.spike.wcl_activity_launchmode_demoU=0sz=2}Run#1:ActivityRecord{ffd689d??u0me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivityt2726}Run#0:ActivityRecord{192310acu0me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivityt2726}使用taskAffinity属性,添加新的Activity栈,与SingleTask配合使用,Standard模式无效。新的任务栈是me.chunyu.spike.stack。(2)任务栈存在,第一次启动SingleTask实例时,会直接入栈,与Standard模式相同。(3)Task栈相同,再次启动SingleTask实例,该实例会被放到栈顶,上面的实例会被清空,效果为clearTop。MainActivity启动TestA,TestA启动TestB,TestB是一个SingleTask,TestB启动TestC,TestC重新启动TestB,然后TestC就会出栈。观察可以看出,TestC出栈,TestB在栈顶。Stack#1:Runningactivities(mostrecentfirst):TaskRecord{18230815#2737A=me.chunyu.spike.wcl_activity_launchmode_demoU=0sz=3}Run#4:ActivityRecord{1126c300u0me.春雨.spike.wcl_activity_launchmode_demo/.TestBActivityt2737}Run#3:ActivityRecord{3114fee8u0me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivityt2737}Run#2:ActivityRecord{f8e235du0me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivityt2737}TestC启动TestB,SingleTask模式,导致clearTop,TestC弹出。(4)任务栈不同。再次启动SingleTask实例会导致任务栈切换,后台会被放到前台。这很难理解。MainActivity启动TestA,TestA启动TestB(SingleTask实例,不同的任务栈),TestB启动TestC(类似B),那么MainActivity和TestA同栈,TestB和TestC同栈,此时top堆栈是TestC。按下Home键,再次启动应用程序,这时会启动默认的任务栈,TestA启动,TestA启动TestC。当前应用状态如下Stack#1:Runningactivities(mostrecentfirst):TaskRecord{1d05e6c9#2754A=me.chunyu.spike.stackU=0sz=2}Run#4:ActivityRecord{3f77e822u0me.chunyu.spike.wcl_activity_launchmode_demo/.TestCActivity}Task27#2753A=me.chunyu.spike.wcl_activity_launchmode_demoU=0sz=2}运行#3:活动记录{15f0470eu0me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivityt2753}任务记录{1d05e6c2#2754A=0.spike.chun运行#2:交流tivityRecord{181229e6u0me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivityt2754}TaskRecord{3fe736d0#2753A=me.chunyu.spike.wcl_activity_launchmode_demoU=0sz=2}Run#1:ActivityRecord{28628d61u0me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivityt2753}TaskRecord{2d646058#2719A=com.android.incalluiU=0sz=1}TestC至于栈顶,点击Back按钮,不是返回到TestA(启动TestC的实例),而是返回到TestB,也就是返回到首先是同一堆栈的实例。又是TestA,然后是MainActivity,依次出栈。SingleInstance单实例模式,启动时,系统会为其创建一个单独的任务栈,以后每次使用时,都会一直使用这个单实例,直到销毁,属于真正的单例模式。例子:MainActivity启动TestA,TestA启动TestB(SingleInstance模式),TestB启动TestC,TestC再次启动TestB,然后最后的TestB仍然启动,TestC合并到默认堆栈(MainActivity+TestA)。Stack#1:Runningactivities(mostrecentfirst):TaskRecord{384e3928#2765A=me.chunyu.spike.wcl_activity_launchmode_demoU=0sz=1}Run#3:ActivityRecord{1ffc5b6bu0me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivityt2765}TaskRecord{2ad03544#2764A=me.chunyu..wcl_activity_launchmode_demoU=0sz=3}Run#2:ActivityRecord{293d8c37u0me.chunyu.spike.wcl_activity_launchmode_demo/.TestCActivityt2764}Run#1:ActivityRecord{158bc0f3u0me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivityt2764}Run#0:ActivityRecord{77691cfu0me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivityt2764}startActivityForResultstartActivityForResult不同于startActivity,使用LaunchMode该模式启动Activity时,也有一些区别。数据可以正常传递,但是当它不能连续创建自己时,就会产生多个实例。TestB(singleTask模式)使用startActivity创建自己时,会使用默认实例,即单例;而当使用startActivityForResult创建自己时,会生成一个新的例子。Stack#1:Runningactivities(mostrecentfirst):TaskRecord{323200ac#2786A=me.chunyu.clwang.stackU=0sz=3}Run#4:ActivityRecord{3f9e14f3u0me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivityt2786}Run#3:ActivityRecord{30d8f17bu0me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivityt2786}Run#2:ActivityRecord{11b95b5cu0me.chunyu.spike.wcl_activity_launchmode_demo/.TestBActivityt2786}TaskRecord{c86e175#2785A=me.chunyu.spike.wcl_activity_launchmode_demoU=0sz=2}Run#1:ActivityRecord{3558d7c4u0me.chunyu.spike.wcl_activity_launchmode_demo/.TestAActivityt2785}Run#0:ActivityRecord{1b8620cu0me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivityt2785}可以看出需要覆盖单实例效果。:4.x版本通过startActivityForResult启动singleTask,无法正常获取返回值。参考5.x及以上版本修复该问题。考虑到兼容性,不建议使用startActivityForResult和singleTask.Intent设置标志。Intent可以设置开始标志,即Flag.intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);AndroidManifest不能设置FLAG_ACTIVITY_CLEAR_TOP,即清除栈上的其他实例;Intent无法设置singleInstance启动模式。您可以选择两者之一来使用。如果两者都使用,则Intent的优先级高于AndroidManifestPriority。常用标志:FLAG_ACTIVITY_NEW_TASK:同singleTask启动方式。FLAG_ACTIVITY_SINGLE_TOP:同singleTop启动方式。FLAG_ACTIVITY_CLEAR_TOP:一般出现在singleTask启动模式。如果是singleTask启动方式,会清除栈上的其他实例,重用实例,调用onNewIntent;如果是标准启动模式,即默认模式,会清空自己和其他实例,重新创建,调用onCreate。显示栈的shell命令shell命令adbshel??ldumpsysactivity|sed-n-e'/Stack#/p'-e'/Runningactivities/,/Run#0/p'直接获取Activity信息有点多余,我们只关注堆栈信息。sed可以编辑显示的文本。-n,从拦截处继续Process.-e,多项选择参数。'/Stack#/p',包含Stack#.-e的输出行'/Runningactivities/,/Run#0/p',输出所有从Running活动到Run#0行。输出结果Stack#1:Runningactivities(mostrecentfirst):TaskRecord{299f41ea#2269A=me.chunyu.spike.wcl_activity_launchmode_demoU=0sz=6}Run#5:ActivityRecord{33926043u0me.chunyu.spike.wcl_activity_launchmode_demoU=0sz=6}Run#5:ActivityRecord{33926043u0me.chunyu.spike.wcl_activity_launchmode_de/Runmode24:ActivityRecord{3f181566u0me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivityt2269}Run#3:ActivityRecord{22737e45u0me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivityt2269}Run#2:ActivityRecord{ce0a990u0me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivityt2269}运行#1:ActivityRecord{3de8e378u0me.chunyu.spike.wcl_activity_launchmode_demo/.MainActivityt2269}运行#0:ActivityRecord{1cb28ec4u0me.chunyu.spike.wcl_deactivity_launchtack2.MainActivity_launchtack2.MainActivity9}(最新的优先):TaskRecord{bfee9cf#2241A=com.miui.homeU=0sz=1}运行#0:ActivityRecord{279bc098u0com.miui.home/.launcher.Launchert2241}launchmode是Activity的一个重要属性,还是需要掌握透彻的。好的,就这些!好好享受!
