Android进阶知识(二):Activity启动模式进阶之多任务栈与Flags

Android进阶知识(二):Activity启动模式进阶之多任务栈与Flags

一、Activity启动模式进阶之多任务栈

  在笔记Android基础知识(三):Android四大组件简介中曾经提到过,Android系统是一个多任务的操作系统,而任务即为Activity中的栈,由一个或多个Activity组成。
  在基础知识的笔记中提到的Activity返回栈,除了特殊的singleInstance模式,其余启动模式下介绍的情况都是默认所有的Activity都是压入同一个返回栈,但是事实上并非如此
  在Android系统中,其将系统的任务和应用程序的任务做了区分,位于不同的Task中。当系统的Task位于前台时则调用该Task,相应的系统会根据处于前台的任务调用不同的Task(在AS中使用命令adb shell dumpsys activity可以查看系统的任务信息)。
在这里插入图片描述
  上述模拟器中,显示了位于栈顶的Task(此处的栈顶不是任务栈的栈顶,而是系统存放多任务的栈的栈顶),该Task表示当前位于前台的任务。
在这里插入图片描述
  在每个Task中都有一个Running activities的一个项,在该项下可以看到当前Task下的多个任务栈,位于栈顶的是处于前台的任务栈,而剩余的即为位于后台的任务栈。举个例子,启动应用程序BaseReceiview和Gmail,可以看到在该项下有两个任务栈,栈名为对应的应用包名,位于前台的栈是Gmail(此时正在使用Gmail)。
在这里插入图片描述
在这里插入图片描述
  这里提及到了对应包名的任务栈,那么问题来了:一个应用程序会有多个任务栈?事实上,之前的笔记中对Activity的四种模式知识简单的提及到了在压栈之后的效果,并未提及到其是如何压栈的,接下来介绍一下Activity四种启动模式的如何对Activity进行压栈。
在这里插入图片描述

  1. standard标准模式

  standard模式下,每次启动一个Activity都会重新创建一个新的实例,一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈。在这种模式下,被启动的Activity将运行在启动该Activity的Activity所在的栈中。为了便于理解,见如下图示,该示例中Activity A启动了Activity B(B是标准模式),那么B将运行在A所在的栈中。
在这里插入图片描述

  1. singleTop栈顶复用模式

  在singleTop模式下,如果新的Activity已经位于任务栈的栈顶,那么该Acitivity不会被重建,同时其onNewIntent方法会被回调(具体参考笔记:Android基础知识(七):Activity互调之间的生命周期变化与onNewIntent()触发机制)。
  singleTop模式下的压栈模式和standard模式的一样,被启动的Activity将运行在启动该Activity的Activity所在的栈中

  1. singleTask栈内复用模式

  singleTask模式的Activity请求启动后(比如Activity A),系统首先会寻找是否存在A想要的任务栈,如果不存在,就重新创建一个任务栈,然后创建A的实例后把A放到栈中。如果存在A所需的任务栈,这时如果实例在该栈中存在那么系统会把A调到栈顶并调用它的onNewIntent()方法,如果实例不存在则创建并压入栈中(具体参考笔记:Android基础知识(七):Activity互调之间的生命周期变化与onNewIntent()触发机制)。
  举几个例子:

  • 目前的任务栈为S1,其中Activity为ABC,这个时候Activity D以singleTask模式请求启动,其所需要的任务栈为S2,由于S2和D实例不存在,所以系统会先创建任务栈S2,然后再创建D的实例并将其入栈道S2。
    在这里插入图片描述
  • 假设D所需的任务栈为S1,由于S1已经存在,所以系统会直接创建D的实例并将其入栈到S1。
    在这里插入图片描述
  • 如果D需要的任务栈为S1,并且当前任务栈S1的情况为ADBC,那么根据singleTask模式,系统会将栈中所有在D上的Activity全部出栈,于是S1变为AD。
    在这里插入图片描述
  1. singleInstance单实例模式

  该模式下的Activity只能单独地位于一个任务栈中,关于其具体的描述见笔记:Android基础知识(六):Activity的启动模式
  前面介绍了几种启动模式,需要指出的一种情况是假设目前有2个任务栈,前台任务栈的情况为AB,而后台任务栈的情况为CD,并且CD的启动模式均为singleTask。现在要求启动D,那么整个后台任务栈会被切换到前台,前台任务栈会切换到后台。
在这里插入图片描述
  但是如果请求启动的是C,那么情况就不一样了,同样前后台栈会切换,不过由于C是singleTask模式因此切换到前台栈后,D会被出栈。
在这里插入图片描述

二、singleTask模式的Activity所需的任务栈

  在singleTask启动模式中,多次提到了Activity所需的任务栈,那么什么是Activity所需要的任务栈?
在这里插入图片描述
  需要涉及的一个参数为taskAffinity,即任务相关性,这个参数表示了一个Activity所需要的任务栈的名字,默认情况下,所有Activity所需的任务栈的名字为应用的包名。可以单独为每个Activity指定taskAfinity属性,该属性值必须不能和包名相同,否则无意义。
在这里插入图片描述
  taskAfinity属性主要和singleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有意义。另外,任务栈分为前台任务栈和后台任务栈,后台任务栈中的Activity位于暂停状态,用户可以通过切换后台任务栈再次调到前台。

  1. taskAfinity与singleTask启动模式配合

  当taskAfinity和singleTask启动模式配合使用时,其是具有该模式的Activity的目前任务栈的名字,待启动的Activity会运行在名字与taskAfinity相同的任务栈中

  1. taskAfinity与allowTaskReparenting配合

  当taskAfinity与allowTaskReparenting配合时,情况比较复杂,会产生特殊的效果。当应用A启动应用B的某个Activity后,如果这个Activity的allowTaskReparenting属性为true的话,那么应用B被启动后,此Activity会直接从应用程序A的任务栈转移到应用B的任务栈中。
在这里插入图片描述

三、Activity的Flags

  之前的笔记中所介绍的指定Activity启动模式仅仅涉及到通过AndroidManifes.xml中的launchMode属性进行指定。事实上,还有一种方式可以指定Activity的启动模式,即在Intent中设置标志位

intent = new Intent(MainActivity.this, SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 指定启动模式
startActivity(intent);

  这两种方式的区别在于:优先级上,第二种方式优先级高于第一种,当两种方式都存在时,以第二种方式为准;其次,上述两种方式在限定范围上有所不同

  1. FLAG_ACTIVITY_NEW_TASK

  这个标志位的作用是为Activity指定“singleTask”启动模式,其效果和在XML中指定该启动模式相同。

  1. FLAG_ACTIVITY_SINGLE_TOP

  这个标志位的作用是为Activity指定“singleTop”启动模式,其效果和在XML中指定该启动模式相同。

  1. FLAG_ACTIVITY_CLEAR_TOP

  具有该标志位的Activity,当它启动时,同一个任务栈中所有位于它上面的Activity都要出栈。这个模式一般需要和FLAG_ACTIVITY_NEW_TASK配合使用,这种情况下,被启动Activity的实例如果已经存在,那么系统就会调用它的onNewIntent。如果被启动的Activity采用standard模式启动,那么它连同它之上的Activity都要出栈
在这里插入图片描述

  1. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

  具有这个标志位的Activity不会出现在历史Activity的列表中,当某些情况下不希望用户通过历史列表回到Activity的时候这个标记比较有用。等同于XML中指定Activity属性android:excludeFromRecents=“true”。

四、IntentFilter的匹配规则

  对于隐式Intent,需要Intent能够匹配目标组件的IntentFilter中所设置的过滤信息,如果不匹配将无法启动目标组件。
  一个过滤列表中的action、category和data可以有多个,所有的action、category、data分别构成不同类别,同一类别的信息共同约束当前类别的匹配过程。一个Activity中可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应的Activity
  一个Intent只有同时匹配action类别、category类别、data类别才算完全匹配,只有完全匹配才能成功启动目标Activity。

  1. action的匹配规则

  action的匹配规则是只要Intent中的action存在且能够和过滤规则中的任何一个action相同即可匹配成功。

  1. category的匹配规则

  category的匹配规则是Intent可以没有category,但是如果有category无论有几个,每个都要能够和过滤规则中的任何一个category相同

  1. data的匹配规则

  data的匹配规则是如果过滤规则中定义了data,那么Intent中必须定义可匹配的data
在这里插入图片描述

参考资料:《Android开发艺术探索》

原创文章 78 获赞 25 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_38196407/article/details/89924983