【Android API】Activity的四种启动详细分析

来源:互联网 发布:淘宝卖家如何分销 编辑:程序博客网 时间:2024/05/29 12:39

难度★★☆☆☆,Activity有四种启动模式:Standard、SingleTop、SingleTask、SingleInstance,还可以结合Activity的flag一起使用,比如Intent.FLAG_ACTIVITY_CLEAR_TOP,Intent.FLAG_ACTIVITY_NEW_TASK,Intent.FLAG_ACTIVITY_SINGLE_TOP,那么系统是如何实现这些启动模式的呢?

1.认识tasks and back-stack(任务和返回栈)

官方介绍:任务是指在执行特定作业时与用户交互的一系列 Activity。 这些 Activity 按照各自的打开顺序排列在堆栈(即返回栈)中。
  就是说一个Task(任务)包含一个BackStack ( 返回栈 ) 。Task概念对应的类就是TaskRecord.class,而BackStack对应的就是TaskRecord.class中类型为ArrayList< ActivityRecord >的成员变量,ActivityRecord.class对应一个具体的Activity。
  此外,相关的类还有ActivityStack.class,它管理的是一系列的Task,也就是里面ArrayList< TaskRecord >类型的成员变量。
  ActivityStackSupervisor.class和他的内部类ActivityDisplay,是管理一系列的ActivityStack.class的,里面有两个成员变量:

/* The stack containing the launcher app. Assumed to always be attached to Display.DEFAULT_DISPLAY. */    ActivityStack mHomeStack;/* The stack currently receiving input or launching the next activity. */    ActivityStack mFocusedStack;

  注释说的很清楚,mHomeStack是包含launcher这个应用的,也就是“桌面”,那也是一个App,我们按Home键会回到那个应用。mFocusedStack是当前的焦点的ActivityStack,他可以接收输入的事件。

也就是说

  • ActivityStackSupervisor对应一个ActivityDisplay,它是一个统一管理所有ActivityStack的类;一般分为HomeStack,和AppStack,一个是“桌面”,一个是我们启动的App。
  • 一个ActivityDisplay对应一个显示“设备”,比如我们在分屏的情况下,就对应两个ActivityDisplay,分屏功能是在Android 7.0的时候支持的,具体见https://developer.android.com/guide/topics/ui/multi-window.html(需要翻墙)
  • 一个ActivityStack,管理一系列的TaskRecord,比如我们点击“后台键”,会显示很多页,一个页就对应一个TaskRecord,也就是一个“任务”。我们可以选择一个Task将它“杀掉”。
  • 一个TaskRecord中管理一系列的ActivityRecord,ActivityRecord也就是Activity,比如我们启动了一个App,它的启动页面是A,然后又启动了BCD三个页面,这个时候TaskRecord中就有四个ActivityRecord,分别对应ABCD四个Activity。
  • 当我们点击手机上的“Recent”键(除了Home键和Back键的另外一个键),我们就能看到最近启动的应用,每一页代表一个Task(任务)。比如我们用SingleInstance启动一个页面,这时点击“Recent”键,就会看到这个应用的两个Task同时在后台。
  • Task和栈是1对1的关系

2.区分四种启动模式

  下面我们用表格来总结一下四种启动模式的不同。其中,一个Task拥有一个“返回栈”,这个要启动的Activity在当前栈中已经存在,或者说当前Task中已经存在,我们简称它的位置为“栈中”。在其他Task中已经存在,就叫“其他栈中”。如果任何地方都没有这个Activity的一个实例,我们简称为“无”。

要启动Activity模式 要启动的Activity位置 是否新建 是否调用onNewIntent 是否ClearTop 是否新建Task 是否切换Task Standard 无/栈顶/栈中/其他栈顶/其他栈中 ✔️ ✘ ✘ ✘ ✘ SingleTop 无/栈中 /其他栈顶/其他栈中 ✔️ ✘ ✘ ✘ ✘ 栈顶 ✘ ✔️ ✘ ✘ ✘ SingleTask 无 ✔️ ✘ ✘ ✘ ✘ 栈中 ✘ ✔️ ✔️ ✘ ✘ 栈顶 ✘ ✔️ ✘ ✘ ✘ 其他栈中 ✘ ✔️ ✔️ ✘ ✔️ 其他栈顶 ✘ ✔️ ✘ ✘ ✔️ SingleInstance 无 ✔️ ✘ ✘ ✔️ ✔️ 栈中/栈顶 ✔️ ✘ ✘ ✘ ✘ 其他栈顶/其他栈中 ✘ ✔️ ✘ ✘ ✔️

  可以看到,SingleTask的意思就是检查一遍系统中存在的所有Task,如果在某一个Task中找到该Activity的实例,那么就将这个Task转到前台,并且移除它上面的所有Activity,然后调用onNewIntent()。这种模式比较适合一个应用的“主”页面,因为它在所有Task中只存在唯一一个,而且别的App启动这个页面会将它上面的页面自动清空。
  SingleInstance就是Task中的唯一,以这种模式启动的Activity会新建一个Task,如果它再启动一个Activity,那么这个Activity会在原有的Task中启动,并且切换到原有的Task。如果它启动它自己那么将不会有任何反应,onNewIntent也不会调用。

2.Intent中设定Activity的启动模式

  主要有三种flag,可以在代码中设置Activity的启动模式,FLAG_ACTIVITY_SINGLE_TOP、FLAG_ACTIVITY_SINGLE_TOP、FLAG_ACTIVITY_CLEAR_TOP
  我们还是通过表格来描述他们的不同

模式 要启动的Activity位置 是否新建 是否调用onNewIntent 是否ClearTop 是否新建Task 是否切换Task Standard+ FLAG_ACTIVITY_NEW_TASK+ taskAffinity=”com.liyafeng” 无 ✔️ ✘ ✘ ✔️ ✔️ 栈顶/栈中 ✘ ✘ ✘ ✘ ✘ 其他栈顶/其他栈中 ✘ ✘ ✘ ✘ ✔️ Standard+ FLAG_ACTIVITY_SINGLE_TOP 所有情况效果和SingleTop完全相同 Standard+ FLAG_ACTIVITY_CLEAR_TOP 无/其他栈顶/其他栈中 ✔️ ✘ ✘ ✘ ✘ 栈顶/栈中 ✔️ ✘ ✔️ ✘ ✘ SingleTop+ FLAG_ACTIVITY_CLEAR_TOP 或者 FLAG_ACTIVITY_SINGLE_TOP+ FLAG_ACTIVITY_CLEAR_TOP 无/其他栈顶/其他栈中 ✔️ ✘ ✘ ✘ ✘ 栈顶/栈中 ✘ ✔️ ✔️ ✘ ✘ FLAG_ACTIVITY_NEW_TASK+ FLAG_ACTIVITY_CLEAR_TOP+ taskAffinity=”com.liyafeng” 无 ✔️ ✘ ✘ ✔️ ✔️ 栈顶 ✔️ ✘ ✘ ✘ ✘ 栈中 ✔️ ✘ ✔️ ✘ ✘ 其他栈顶 ✔️ ✘ ✘ ✘ ✔️ 其他栈中 ✔️ ✘ ✔️ ✘ ✔️ FLAG_ACTIVITY_NEW_TASK+ FLAG_ACTIVITY_CLEAR_TOP+ FLAG_ACTIVITY_SINGLE_TOP+ taskAffinity=”com.liyafeng” 无 ✔️ ✘ ✘ ✔️ ✔️ 栈顶 ✘ ✘ ✘ ✘ ✘ 栈中 ✘ ✔️ ✔️ ✘ ✘ 其他栈顶 ✘ ✘ ✘ ✘ ✔️ 其他栈中 ✘ ✘ ✘ ✘ ✔️

我们看到

  • 如果只是FLAG_ACTIVITY_NEW_TASK但是没有指定task,就不会有任何效果,就和Standard一样,如果指定task但是没有newTask也没效果
  • 要FLAG_ACTIVITY_NEW_TASK和taskAffinity一起使用,如果不存在,就创建新的Task,然后切换过去。
  • FLAG_ACTIVITY_NEW_TASK,如果要启动的Activity在当前栈顶,就没效果,也不走onNewIntent,当前栈中也是。
  • FLAG_ACTIVITY_NEW_TASK,如果要启动的Activity在其他栈顶或栈中,也只是将那个Task切换到前台,不会ClearTop,也不会调用onNewIntent。
  • FLAG_ACTIVITY_NEW_TASK这种模式和SingleTask有点像,只是这种模式没有ClearTop的效果。适合于唤起某个模块但是保留现有状态的情况。
  • FLAG_ACTIVITY_CLEAR_TOP这个不但会清空上面的Activity,还会销毁哪个已经存在的Activity,然后重新创建一个。如果不想销毁那个Activity,加上FLAG_ACTIVITY_SINGLE_TOP,即可,这两个标志一起用,就有类似SingleTask的效果
  • 有一点细节很重要,如果同时设置两个flag,要调用Intent.addFlags(),而不是Intent.setFlags(),否则两个Flag不能同时起效果。
  • 注意,销毁然后再创建一个Activity的生命周期为A-onPause,B-onCreate,B-onStart,B-onResume ,A-onStop, A-onDestory
  • 页面A开启B,并且切换Task,先调用A的onPause(),然后调用B,onCreate(),onStart(),onResume(),B显示后,再调用A的onStop()
  • ABCD,D开启A,用CLEAR_TOP形式, 先调用D的onPause(),然后C的onDestroy(),B的onDestroy(),A的onDestroy(),然后创建A,调用onCreate(),onStart(),onResume(),最后,调用D的onStop(),onDestroy()
  • NEW_TASK+CLEAR_TOP这种组合和SingleTask类似,只不过这种组合不但会清空上面的Activity,还会销毁那个已经存在的Activity,并且创建一个新的页面。官方注释中写到,这种组合适合从notification manager(通知栏)中点击通知启动的Activity,因为每个通知都可以共用一个界面,而且每个通知内容不一样,Activity需要重建,这种模式就很适合这种情况
  • 三种Flag一起使用,和SingleTask区别就是在其他栈的时候没有ClearTop效果,只是将那个Task切换到前台

  最后我们先介绍到这里,至于启动模式的源码,还有在5.0后新加的document-centric model(以文档为中心的模式),对应新增的启动Flag:FLAG_ACTIVITY_NEW_DOCUMENT,和AndroidManifest.xml中< activity >的属性android:documentLaunchMode,关注www.liyafeng.com,这些我们在后面的文章会介绍到。

原创粉丝点击