Activity的启动模式

简介: 任务栈android任务栈又称为Task,它是一个栈结构,具有后进先出的特性,用于存放我们的Activity组件。我们每次打开一个新的Activity或者退出当前Activity都会在一个称为任务栈的结构中添加或者减少一个Activity组件,因此一个任务栈包含了一个activity的集合, android系统可以通过Task有序地管理每个activity,并决定哪个Activity与用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。

任务栈

  1. android任务栈又称为Task,它是一个栈结构,具有后进先出的特性,用于存放我们的Activity组件。
  2. 我们每次打开一个新的Activity或者退出当前Activity都会在一个称为任务栈的结构中添加或者减少一个Activity组件,因此一个任务栈包含了一个activity的集合, android系统可以通过Task有序地管理每个activity,并决定哪个Activity与用户进行交互:只有在任务栈栈顶的activity才可以跟用户进行交互。
  3. 在我们退出应用程序时,必须把所有的任务栈中所有的activity清除出栈时,任务栈才会被销毁。当然任务栈也可以移动到后台, 并且保留了每一个activity的状态. 可以有序的给用户列出它们的任务, 同时也不会丢失Activity的状态信息。
  4. 需要注意的是,一个App中可能不止一个任务栈,某些特殊情况下,单独一个Actvity可以独享一个任务栈。还有一点就是一个Task中的Actvity可以来自不同的App,同一个App的Activity也可能不在一个Task中。

任务栈信息可以通过 adb shell dumpsys activity activities | sed -En -e '/Running activities/,/Run #0/p'指令来查看 栈信息.

四种启动模式

  1. standard : 默认的启动模式,每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否存在.Activity的启动三回调(onCreate()->onStart()->onResume())都会执行。 如在一个任务栈中,连续调用3次MainActivity,那么任务占中就会存在三个MainActivity记录.
  2. singTop : 栈顶复用模式. 当准备启动的Activity已经位于任务栈栈顶时,不会再创建一个新的Activity,此时栈顶Activity的 onNewIntent方法会被回调.当准备启动的Activity不在任务栈的栈顶存在时,(无论在栈中存在或者在非栈顶),都会重新创建 Activity.
  3. singleInstance : 单实例模式. 系统为声明为singleInstance模式的Activity,单独使用一个任务栈存放.即一个Activity对应一个任务栈,且一个Activity最多存在一个实例. 后续请求都不会创建Activity,只会调用其 onNewIntent回调.
  4. singleTask : 栈内复用模式. 在这种模式下,如果Activity已经存在某个任务栈中,多起启动该Activity都不会被重建,只会调用其onNewIntent方法,并将其移动到栈顶位置.

singleTask模式

当启动Activity时,如果Activity已经存在于 任务栈的非栈顶位置, 任务栈中该Activity之上的 Activity将会被全部移除,只保留该Activity以及其一下的Activity.
即 具有 clearTop的效果.

当启动Activity的任务栈B在后台时,此时任务栈A中的Activity启动了,任务栈B中的 singleTask模式的Activity,则任务B栈的 被启动Activity会clearTop到栈顶位置,然后整个任务栈B重返至前台.

引用 官方示例来说明 :


img_703e8bcc6c3e829ffa934cd9df8122ba.png
2018-10-02-22-46-05

前台栈中的栈顶Activity2 启动了 位于后台栈的 ActivityY,此时 后台栈中的 ActivityY和ActivityX 都会被移动至前台栈中,回退两次才能回到 Activity2.

taskAffinity属性

taskAffinityAndroidManifest中 Activity标签的属性,表示任务栈的名称.该属性可以为 Activity指定任务栈.

  1. 当Activity的启动模式为 standard,singletop模式时,taskAffinity属性将失效, Activity的将被加入到 启动它的那个Activity所在的栈.一个例外,如果在入口Activity中指定 taskAffinity属性,则可以生效,因为此时应用刚启动,还没有指定的任务栈(默认的任务栈是以包名来命名的).

  2. 当Activity的启动模式为 singleTask,singleInstance模式时,taskAffinity属性将在Activity被启动的时候指定任务栈,如果任务栈不存在则会创建一个taskAffinity命名的任务栈存放启动的Activity.

注意事项

  1. 如果被启动的Activity是 standard,singletop模式时, Activity将被加入到启动该Activity的任务栈中.

  2. 如果被启动的Activity是 singleTask,singleInstance模式时,如果指定taskAffinity属性,则Activity被加入到 指定的栈任务栈中,未指定则被加入 以包名命名的任务栈. singleInstance模式的Activity,虽然可能被加入到名字相同的栈,但是由于其特殊性,虽然栈名相同但是不属于同一个栈.

  3. 使用 application来启动Activity时, application没有所在的 任务栈.如果没有指定 FLAG_ACTIVITY_NEW_TASK,将会有如下报错.

 android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

Activity中的 Flags

  1. FLAG_ACTIVITY_NEW_TASK : 为Activity指定 singleTask模式,相当于在xml中指定启动模式一样,除了application来启动Activity时,在xml指定singleTask是无效的,一定要在intent中指定该标志.
  2. FLAG_ACTIVITY_SINGLE_TOP : 指定singleTop模式.
  3. FLAG_ACTIVITY_CLEAR_TOP : 具有此标记的Activity,当它启东市,在同一个任务栈中的所有位于它上面的Activity都将被移除任务栈.
  4. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS : 设置了该标志,该Activity所在的任务栈将不会出现在 多任务列表(最近使用列表)中.相当于设置了android:excludeFromRecents="true".

IntentFilter匹配规则

intent的启动有两种方式,显式调用和隐式调用.
显示调用,我们需要明确的指定被启动的Activity的组件信息,Activity的class对象.
隐式调用则不需要明确的知道 被调用的Activity信息,而是通过IntentFilter来指定action,category,data过滤规则配合来启动Activity.

Intent只有同时匹配了 action规则,category规则 和 data规则,才能成功的启动目标Activity.

一个 IntentFilter中可以设置多个 action,多个category和多个data.

action

intent中必须设置 action, 且能过匹配 IntentFilter中的任意一个 action就算匹配成功.

category

intent中如果含有 category,那么所有的category都能在IntentFilter中匹配上,intent中也可以不显式的设置category.

在调用 startActivity或者startActivityForResult时,系统会为intent自动添加 android.intent.category.DEFAULT标志,所以如果要想隐式的调用Activity,就必须在 IntentFilter中添加 <category android:name="android.intent.category.DEFAULT" />规则.

data

<data android:scheme="string"
      android:host="string"
      android:port="string"
      android:path="string"
      android:pathPattern="string"
      android:pathPrefix="string"
      android:mimeType="string" />

data由两部分组成, URI 和 mimeType(媒体类型).

URI结构 : <scheme>://<host>:<port>[<path>|<pathPrefix>|<pathPattern>]
mimeType : image/jpeg,video/*等.

如果IntentFilter中设置了 data属性.则intent中必须设置 setData或者setType或者setDataAndType.
setData或者setType方法的属性会相互覆盖.各自的方法会将对方属性设置为null.

data中指设置了 mimeType时,可以使用 schemefile或content类型来设置data.
如果需要同时指定URImimeType,需要使用intent的setDataAndType方法.

隐式调用,可达性检查

隐式intent启动之前,我们可以先检查 目标Activity的可达性,避免出现 android.content.ActivityNotFoundException: No Activity found to handle Intent的错误.

使用 intent的 intent.resolveActivity(packageManager) 和 packageManager的packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY)来检查, 返回 null则表示找不到匹配的Activity.

参考

  1. Android开发艺术探索(任玉刚)
  2. 任务和返回栈(android官方教程)
目录
相关文章
|
Shell Android开发 容器
你真了解Android任务栈 Task 与启动模式吗?
你真了解Android任务栈 Task 与启动模式吗?
132 0
|
存储 Android开发
Activity的启动模式和启动流程
标准模式(standard) 栈顶复用模式(singleTop) 栈内复用模式(singleTask) 单例模式(singleInstance) 启动模式可在AndroidManifest.xml中,通过<activity>标签的android:launchMode属性设置。
|
Java Android开发
Activity的四种启动模式
Android的冷门知识,大家有兴趣可以了解了解
196 0
|
Android开发 容器
Android Activity的启动模式
关于activity的启动模式,相信但凡有点android开发基础的人都知道,但是为什么还要说呢,主要还是容易忘记,基础的东西更加容易让人忘记,而且我最近看了一本书,关于activity的启动模式的,虽然书中的内容跟我平时对activity启动模式的理解是一样的,但是比较详细,容易懂,在这里记录一下。
127 0
|
Android开发
Activity四种启动模式
Activity四种启动模式
|
Android开发
理解Activity的启动模式
Activity的启动模式有哪几种,分别用于什么场景? standard:标准模式 系统的默认模式。一种典型的多实例实现。每次启动一个Activity都会重新创建一个新的实例。
1065 0
|
Web App开发 JavaScript 前端开发