Activity启动模式

启动模式的一个典型应用:

手机淘宝中我的--右上角设置中,右上角有个首页,点击首页后就可以打开首页,但这时再按返回键却无法回到设置界面了。

这就可以通过启动模式很方便的控制。

先介绍一个查看安卓设备中任务栈以及栈中Activity情况的命令

一. 使用命令

adb shell dumpsys activity

为了可以在控制台直接使用这个命令,我们可以在系统环境变量中为path添加adb.exe文件的目录


例如我的电脑中sdk中的adb.exe位于C:\developTools\SDK\sdk\platform-tools目录中,



我可以这样配置adb的path



当然不配置adb也可以,若不配置,当要使用adb命令时就需要输入adb的完整路径了,比如我的电脑adb路径是C:\developTools\SDK\sdk\platform-tools\adb.exe,那么我可以这样

C:\developTools\SDK\sdk\platform-tools\adb shell dumpsys activity

运行上面命令后我们会看到如下输出,可以看到有两个栈,一个com.xxx.ccc和一个com.example.tt,com.xxx.ccc栈中有4个Activity,com.example.tt栈中有3个Activity,

当按安卓手机中返回键时,会按从上到下顺序依次退栈,

即按com.xxx.ccc栈中MainActivity3->com.xxx.ccc中MainActivity2->->com.xxx.ccc中MainActivity->com.xxx.ccc中MainActivity4->com.example.tt中MainActivity3->com.example.tt中MainActivity2->->com.example.tt中MainActivity->桌面


当切换任务栈时,会有一个Activity缩放动画效果,比如com.xxx.ccc中MainActivity4 按返回键到com.example.tt中MainActivity3时,或者com.example.tt中MainActivity3开启com.xxx.ccc中MainActivity4时都会有一个动画效果



二.启动模式   

Activity才有启动模式,启动模式需要在清单文件中的Activity节点中配置,可以给每一个activity分别配置启动模式

例如   


 启动模式可以不配置,默认是standard模式。

安卓的Activity总共有4种启动模式,分别是standard,singTop,singTask,singInstance。

singTask和singInstance还能指定新启动的activity所在的栈,可以在清单中的activity节点中这样配置

 <activity android:name="com.example.tt.MainActivity4"
            android:taskAffinity="com.xxx.ccc"
              android:launchMode="singleTask"></activity>

这样MainActivity4就运行在了com.xxx.ccc任务栈中。

standard和singTop不支持指定任务栈,所以配置该属性无效。

4种启动模式的activity默认都运行在任务栈名与应用包名相同的任务栈中(即使任务栈名相同也有可能是两个任务栈,具体是不是同一个任务栈需要根据任务栈中某一值来判断)

(1)standard: 默认启动模式,若清单中不配置则是standard模式。每次启动standard模式的activity都会创建新的activity实例。一个任务栈中可以有多个该实例,谁启动的standard模式的activity,那么这个standard模式的activity就运行在启动它的activity所在的任务栈中。(但有个特例,singInstance模式的activity启动了standard模式的activity,则sta模式的activity不会运行在singInstance模式的activity所在的栈中)。

例如MainActivity,MainActivity2,MainActivity3,MainActivity4都是standard模式, 当MainActivity4启动MainActivity4时,可以看到每次都会创建新的activity

    Running activities (most recent first):
      TaskRecord{53c5ec5 #255 A=com.example.tt U=0 sz=7}
        Run #6: ActivityRecord{5dde76b u0 com.example.tt/.MainActivity4 t255}
        Run #5: ActivityRecord{f13a97b u0 com.example.tt/.MainActivity4 t255}
        Run #4: ActivityRecord{c7a6fbd u0 com.example.tt/.MainActivity4 t255}
        Run #3: ActivityRecord{8c3994d u0 com.example.tt/.MainActivity4 t255}
        Run #2: ActivityRecord{b55c7f u0 com.example.tt/.MainActivity3 t255}
        Run #1: ActivityRecord{36ef18f u0 com.example.tt/.MainActivity2 t255}
        Run #0: ActivityRecord{d379153 u0 com.example.tt/.MainActivity t255}


当我们用getApplicationContext().startActivity(new Intent(getApplicationContext(), MainActivity4.class));启动activity时会抛出如下异常


这是由于context中没有任务栈导致的。


(2)singTop:栈顶复用模式。如果当前activity是singTop模式,当该activity再次启动自己时,并不会创建新的activity,而且也不会调用当前activity的onCreate和onStart方法,但会调用当前activity的onNewIntent方法。 若singTop模式的activityA已经存在栈中,但不是栈顶的话,若再次启动singTop模式的activity,则会创建新的activity,不会执行原singTop模式activity的onNewIntent方法。

例如MainActivity,MainActivity2,MainActivity3都是standard模式,MainActivity4是singTop模式,当MainActivity4启动MainActivity4时,可以看到并没有创建新的activity

    Running activities (most recent first):
      TaskRecord{1553bef #254 A=com.example.tt U=0 sz=4}
        Run #3: ActivityRecord{3038f55 u0 com.example.tt/.MainActivity4 t254}
        Run #2: ActivityRecord{ab22e5 u0 com.example.tt/.MainActivity3 t254}
        Run #1: ActivityRecord{62e00f1 u0 com.example.tt/.MainActivity2 t254}
        Run #0: ActivityRecord{fc3c595 u0 com.example.tt/.MainActivity t254}


再例如MainActivity,MainActivity2,MainActivity3都是standard模式,MainActivity4是singTop模式,依次启动MainActivity,MainActivity2,MainActivity3,MainActivity4,MainActivity,MainActivity2,MainActivity3,MainActivity4,可以看到创建了新的activity4


   Running activities (most recent first):
      TaskRecord{561d45a #256 A=com.example.tt U=0 sz=8}
        Run #7: ActivityRecord{2082c6 u0 com.example.tt/.MainActivity4 t256}
        Run #6: ActivityRecord{ba21d8 u0 com.example.tt/.MainActivity3 t256}
        Run #5: ActivityRecord{f8c1d54 u0 com.example.tt/.MainActivity2 t256}
        Run #4: ActivityRecord{a49a842 u0 com.example.tt/.MainActivity t256}
        Run #3: ActivityRecord{e3a7692 u0 com.example.tt/.MainActivity4 t256}
        Run #2: ActivityRecord{cba592e u0 com.example.tt/.MainActivity3 t256}
        Run #1: ActivityRecord{312ba8a u0 com.example.tt/.MainActivity2 t256}
        Run #0: ActivityRecord{5bc6f1e u0 com.example.tt/.MainActivity t256}

(3)singTask:栈内复用模式。当要启动singTask模式的activity时,系统会先查看是否有其需要的栈(singtask需要的栈在清单中用taskAffinity指定),若不存咋,则创建栈,并创建该activity实例然后加入栈中,若存在需要的栈,则去栈中查找有没有改activity实例,若没有则创建该activity实例并加入栈中,否则把栈中的activity上面的activity移除栈,这样改activity就位于栈顶了,同时会执行该activity的onNewInten方法。

例如 MainActivity,MainActivity2,MainActivity3都是standard模式,MainActivity4是singTask模式,

并指定MainActivity4运行在com.xxx.ccc栈中,

然后依次启动MainActivity,MainActivity2,MainActivity3,MainActivity4,可以看到创建了新的栈com.xxx.ccc和activity4

    Running activities (most recent first):
      TaskRecord{fa0d4de #258 A=com.xxx.ccc U=0 sz=1}
        Run #3: ActivityRecord{62f75b8 u0 com.example.tt/.MainActivity4 t258}
      TaskRecord{a0a76bf #257 A=com.example.tt U=0 sz=3}
        Run #2: ActivityRecord{26c5a88 u0 com.example.tt/.MainActivity3 t257}
        Run #1: ActivityRecord{487e504 u0 com.example.tt/.MainActivity2 t257}
        Run #0: ActivityRecord{45ce62f u0 com.example.tt/.MainActivity t257}
在上面的基础上再启动standa模式的MainActivity,MainActivity2,MainActivity3,会看到MainActivity,MainActivity2,MainActivity3都运行在了com.xxx.ccc任务栈中

    Running activities (most recent first):
      TaskRecord{fa0d4de #258 A=com.xxx.ccc U=0 sz=4}
        Run #6: ActivityRecord{392eaf9 u0 com.example.tt/.MainActivity3 t258}
        Run #5: ActivityRecord{dc37945 u0 com.example.tt/.MainActivity2 t258}
        Run #4: ActivityRecord{c79bfdb u0 com.example.tt/.MainActivity t258}
        Run #3: ActivityRecord{62f75b8 u0 com.example.tt/.MainActivity4 t258}
      TaskRecord{a0a76bf #257 A=com.example.tt U=0 sz=3}
        Run #2: ActivityRecord{26c5a88 u0 com.example.tt/.MainActivity3 t257}
        Run #1: ActivityRecord{487e504 u0 com.example.tt/.MainActivity2 t257}
        Run #0: ActivityRecord{45ce62f u0 com.example.tt/.MainActivity t257}
然后继续启动MainActivity4,则会看到com.xxx.ccc中是MainActivity,MainActivity2,MainActivity3都被移除栈了

    Running activities (most recent first):
      TaskRecord{fa0d4de #258 A=com.xxx.ccc U=0 sz=1}
        Run #3: ActivityRecord{62f75b8 u0 com.example.tt/.MainActivity4 t258}
      TaskRecord{a0a76bf #257 A=com.example.tt U=0 sz=3}
        Run #2: ActivityRecord{26c5a88 u0 com.example.tt/.MainActivity3 t257}
        Run #1: ActivityRecord{487e504 u0 com.example.tt/.MainActivity2 t257}
        Run #0: ActivityRecord{45ce62f u0 com.example.tt/.MainActivity t257}



(4)singInstance:但实例模式。具有singTask所有特性,另外该模式的activity位于单独的一个栈中,该栈中只有一个activity。

例如 MainActivity,MainActivity2,MainActivity3都是standard模式,MainActivity4是singInstance模式,并且采用默认任务栈时,则MainActivity3启动MainActivity4 时会创建新的任务栈,虽然新的任务栈的名字和原来任务栈的名字相同(都是包名)但却是一个新的任务栈。当MainActivity4继续启动MainActivity4时,则任务栈和activity不会有任何变化。


    Running activities (most recent first):
      TaskRecord{60baca6 #260 A=com.example.tt U=0 sz=1}
        Run #3: ActivityRecord{ed1a804 u0 com.example.tt/.MainActivity4 t260}
      TaskRecord{18dc294 #259 A=com.example.tt U=0 sz=3}
        Run #2: ActivityRecord{41f8740 u0 com.example.tt/.MainActivity3 t259}
        Run #1: ActivityRecord{8dc273c u0 com.example.tt/.MainActivity2 t259}
        Run #0: ActivityRecord{77da77b u0 com.example.tt/.MainActivity t259}
当继续通过MainActivity4启动MainActivity3时,会看到MainActivity3又回到了原任务栈中

    Running activities (most recent first):
      TaskRecord{556e59d #261 A=com.example.tt U=0 sz=4}
        Run #4: ActivityRecord{13c8d80 u0 com.example.tt/.MainActivity3 t261}
      TaskRecord{1fab5e3 #262 A=com.example.tt U=0 sz=1}
        Run #3: ActivityRecord{a82bf76 u0 com.example.tt/.MainActivity4 t262}
      TaskRecord{556e59d #261 A=com.example.tt U=0 sz=4}
        Run #2: ActivityRecord{b997b52 u0 com.example.tt/.MainActivity3 t261}
        Run #1: ActivityRecord{28b39ee u0 com.example.tt/.MainActivity2 t261}
        Run #0: ActivityRecord{a513bc1 u0 com.example.tt/.MainActivity t261}

继续由MainActivity3启动MainActivity4,会看到原来的MainActivity4又被移到了栈顶

   Running activities (most recent first):
      TaskRecord{1fab5e3 #262 A=com.example.tt U=0 sz=1}
        Run #4: ActivityRecord{a82bf76 u0 com.example.tt/.MainActivity4 t262}
      TaskRecord{556e59d #261 A=com.example.tt U=0 sz=4}
        Run #3: ActivityRecord{13c8d80 u0 com.example.tt/.MainActivity3 t261}
        Run #2: ActivityRecord{b997b52 u0 com.example.tt/.MainActivity3 t261}
        Run #1: ActivityRecord{28b39ee u0 com.example.tt/.MainActivity2 t261}
        Run #0: ActivityRecord{a513bc1 u0 com.example.tt/.MainActivity t261}


若一开始就指定MainActivity4所在的任务栈的话,比如指定为  android:taskAffinity="com.xxx.ccc",则只需把上面MainActivity4所在的任务栈的名字改为com.xxx.ccc即可,其他都一样。



三,注意   

即使指定了Activity所在的任务栈和启动模式为singTask或singInstance也不能直接用ApplicationContext启动activity,否则同样会抛出同样的异常。解决方法就是在intent中添加flag    FLAG_ACTIVITY_NEW_TASK

例如:

Intent intent=new Intent(getApplicationContext(), MainActivity4.class);
					intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
					getApplicationContext().startActivity(intent);


FLAG_ACTIVITY_NEW_TASK的作用和在清单中指定singTask效果相同。

FLAG_ACTIVITY_SINGLE_TOP的作用和在清单中指定singTop效果相同。

FLAG_ACTIVITY_CLEAR_TOP,在同一任务栈中,若要启动的实例已经存在,则把该实例以及上面的activity全部移除栈,并创建新的实例,然后加入栈中

例如,有4个Activity,全是standard模式,依次启动4个activity

   Running activities (most recent first):
      TaskRecord{13451a2 #271 A=com.example.tt U=0 sz=4}
        Run #3: ActivityRecord{aae2f54 u0 com.example.tt/.MainActivity4 t271}
        Run #2: ActivityRecord{eae7f90 u0 com.example.tt/.MainActivity3 t271}
        Run #1: ActivityRecord{2c1608c u0 com.example.tt/.MainActivity2 t271}
        Run #0: ActivityRecord{435285c u0 com.example.tt/.MainActivity t271}

在MainActivity4中启动MainActivity2,可以看到栈中就剩两个了,而且MainActivity2已经不是原来那个activity了,而MainActivity还是原来那个

   Running activities (most recent first):
      TaskRecord{13451a2 #271 A=com.example.tt U=0 sz=2}
        Run #1: ActivityRecord{7b48125 u0 com.example.tt/.MainActivity2 t271}
        Run #0: ActivityRecord{435285c u0 com.example.tt/.MainActivity t271}


FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:如果不希望用户通过历史列表回到我们的Activity,只需设置该flag,或在清单中配置

 android:excludeFromRecents="true"



清单中还可以给activity配置android:allowTaskReparenting="true",当appA启动了appB的activityB,并且activityB配置了android:allowTaskReparenting="true"后,当回到桌面,然后在点击桌面上appB的图标时,开启的不是appB主activity,而是刚才启动的activityB。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值