《Android开发艺术探索》Activity | 生命周期 | 启动模式 | Flags | IntentFilter action data的匹配规则 (一)

版权声明:本文出自阿钟的博客,转载请注明出处: https://blog.csdn.net/a_zhon/article/details/80006709

说几点

1.文章中大部分(所有吧)的内容都是与《Android开发艺术探索》书中写的内容是一致的,所以可以说是直接copy了一遍(没办法,作者写的太好了)。
2.为什么要copy一遍呢?,主要还是为了加深对知识的记忆和理解 不然只是匆匆忙忙的看了一遍,过后就啥都没印象了。
3.记录在博客里面,也是为了以后找起来更加的方便!

一:Activity的生命周期

正常情况下启动一个Activity的生命周期:

onCreate、onStart、onResume、onPause、onStop、onDestory

这里说一下每一个生命周期函数的描述

  • onCreate

    表示Activity正在创建,这这个函数中我们一般是做初始化操作比如加载布局资源

  • onStart

    表示Activity正在启动,即将开始这时Activity已经可见了但是还没有出现在前台,用户无法交互。

  • onResume

    表示Activity已经可见,出现在前台并开始活动,用户可以与之交互

  • onPause

    表示Activity正在停止,正常情况下onStop紧跟着会被调用.(这里需要注意的是只有onPause执行完新的Activity的Resume才会执行)

  • onStop

    表示Activity即将停止

  • onDestory

    表示Activity即将即将被销毁,这是最后执行的一个生命周期函数、在这里可以做一些资源回收的操作。

当从MainActivity跳转至SecondActivity时的生命周期:

A:onCreate、A:onStart、A:onResume、A:onPause、B:onCreate、B:onStart、B:onResume、A:onStop

当在SecondActivity按下返回键回到MainActivity时的生命周期:

B:onPause、A:onRestart、A:onStart、A:onResume、B:onStop、B:onDestory

Activity的优先级

  • 前台Activity:正在和用户交互的Activity,优先级最高
  • 可见但非前台Activity:比如对话框,导致Activity可见但是位于后台无法和用户直接交互
  • 后台Activity:已经被暂停的Activity,比如执行了onStop,优先级最低

二:Activity的启动模式

首先说一下Activity为什么需要启动模式,我们知道,在默认的情况下,当我们多次启动同一个Activity的时候,系统会创建多个实例并把他们一一放入任务栈中,当我们点击back键的时候会发现这些Activity会一一回退,任务栈是一种先进先出的栈结构,这个好理解, 每按一次back键就有一个activity退出栈,知道栈空为止,当这个栈为空的时候,系统就会回收这个任务栈,关于任务栈的系统工作原理,这里我们暂且不说,在后续章节也会介绍任务栈,知道了Activity的启动模式,我们可发现一个问题,:多次启动同一个Activity会创建多个实例,这样是不是很逗,Activity在设计的时候不可能不考虑到这个问题,所以他提供了启动模式来修改系统的默认行为,目前有四种启动模式

  • standard

    标准模式,这也是系统默认的模式。每次启动一个Activity都会被重新创建一个新的实例,不管这个实例是否已经存在被创建的实例的生命周期符合典型情况下Activity的生命周期,如上述:onCreate(),onStart();onResume()都会被调用,这是一种典型的多实例实现,一个任务栈都可以有多个实例,每个实例都可以属于不同的任务栈,在这种模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的Activity所在的栈内,比如Activity A启动了Activity B(B是标准模式),那么B就会进入到A所在的栈内,不知道读者有没有注意到,当我们用ApplicationContext去启动standard模式的Activity的时候就会报错如下代码:

    getApplicationContext().startActivity(
        new Intent(MainActivity.this, ThirdActivity.class));
    android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. 
    Is this really what you want?
  • singleTop(栈顶复用模式)

    如果启动的新Activity已经位于任务栈的栈顶,那么这个Activity将不会被重新创建,同时他的newIntent方法会被调用,通过此方法的参数我们可以取出当前请求的信息。需要注意的是这个Activity的onCreate,onStart不会被系统调用,因为他并没有发生改变。如果新的Actvity不在栈顶,那么新的Activity将会被重新创建。举个例子:栈底->栈顶的Activity依次为 A B C,(假设A的启动模式为:singleTop)当启动A页面的时候栈的情况就变成了这样:栈底—–>栈顶的Activity依次为 A B C A。

    栈底—–>栈顶的Activity依次为 B C A,(假设A的启动模式为:singleTop)当启动A页面的时候栈的情况就不会发生改变:栈底—–>栈顶的Activity依次为 B C A。

  • singleTask(栈内复用模式)

    这是一种单例模式,在这种模式下只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例;同时也会调用newIntent函数。
    假设栈内情况为A(standard) B(singleTask) C(singleTask) 此时在C页面启动B页面 栈内情况为A(standard) B(singleTask) C页面已经出栈了。

  • singleInstance(单实例模式)

    单例模式,这是一种加强的singleTask模式据、它除了具有singleTask模式的所有特性外,还加强了一点,它除了具有singleTask模式的所有特性外,还加强了一点,那就是具有此种模式的Activity只能单独地位于一个任务栈。如果这个特定的任务栈被系统销毁了,在启动这个Activity系统又会重新创建、如果没有销毁则不会再次创建任务栈。

三:Activity 的 Flags

Activity的Flags有很多,这里主要分析一些比较常用的标记位。标记位的作用很多,有的标记位可以设定Activity的启动模式,比如FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_SINGLE_TOP等…还有的标记位可以影响Activity的运行状态,比如FLAG_ACTIVITY_CLEAR_TOPFLAG_ACTIVITY_EXCLUDE_FROM_RECENTS等。下面主要介绍几个常用的标记位,剩下的标记位读者可以查阅官方文档去了解,大部分情况下,我们不需要为Activity指定标记位,因此对于标记位理解即可。在使用标记位的时候,要注意有些标记位是系统内部使用的,应用程序不需要手动设置这些标记位以防出现问题。

FLAG_ACTIVITY_NEW_TASK

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

FLAG_ACTIVITY_SINGLE_TOP

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

FLAG_ACTIVITY_CLEAR_TOP

具有此标记位的Activity,当他启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。这个模式一般要和FLAG_ACTIVITY_NEW_TASK配合使用,在这种情况下,被启动Activity的实例如果已经存在,那么系统就会调用它的onNewIntent。如果被启动的Activity采用standard模式启动,那么它连同它之上的Activity都要出栈,系统会创建新的Activity实例并放人栈顶。(singleTask启动模式默认就具有此标记位的效果)

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

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

IntentFilter的匹配过则

我们知道启动Activity分为两种,显示调用和隐式调用。二者的区别这里就不多说了,显示调用需哟明确的指定被启动对象的组建信息,包括包名和类名,而隐式调用则不需要明确指定组件信息。原则上一个Intent不应该既是显示调用又是隐式调用,如果二者共存的话以显示调用为主。显示调用很简单,这里主要介绍一下隐式调用。隐式调用需要Intent能够匹配目标组建的IntentFilter中所设定的过滤信息,如果不匹配将无法启动目标Activity。IntentFilter中的过滤信息有actioncategorydata下面是一个过滤规则示例:

<activity
    android:name="com.azhon.launchmode.MainActivity"
    android:configChanges="orientation"
    android:launchMode="singleTask"
    android:taskAffinity="com.azhon.launchmode1">
    <intent-filter>
        <action android:name="com.azhon.launchmode.custom" />
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.LAUNCHER" />
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>

为了匹配过滤列表,需要同时匹配过滤列表中的actioncategorydata信息,否则匹配失败。一个过滤列表中的actioncategorydata可以有多个,所有的actioncategorydata分别构成不同的类别,同一类别的信息共同约束当前类别的匹配过程。只有一个Intent同时匹配action类别、category类别、data类别才算完全匹配,只有完全匹配才能成功启动目标Activity。另外一点,一个Activity中可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应的Activity,如下所示:

<activity android:name=".BActivity">
    <intent-filter>
        <action android:name="com.azhon.custom" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
    <intent-filter>
        <action android:name="com.azhon.lanchmode" />
        <action android:name="android.intent.action.SEND_MULTIPLE" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="application/vnd.google.panorama360+jpg" />
        <data android:mimeType="image/*" />
        <data android:mimeType="video/*" />
    </intent-filter>
</activity>

下面详细分析各种属性的匹配规则

1.action的匹配规则

action是一个字符串,系统预定义了一些action,同时我们也可以在应用中定义自己的action。action的匹配规则是Intent中的action必须能够和过滤规则中的action匹配,这里说的匹配是指action的字符串值完全一样(区分大小写)。一个过滤规则中可以有多个action,那么只要Intent中的action能够和过滤规则中的任何一个action相同即可匹配成功。针对上面的过滤规则,只要我们的Intent中的action值为com.azhon.custom或者com.azhon.launchmode都能匹配成功。需要注意的是,Intent中,没有指定action,那么匹配失败。总结一下:action的匹配要求Intent中的action存在且必须和过滤规则中的其中一个action相同,这里需要注意它和category匹配规则不同。

2.category的匹配规则

category是一个字符串,系统预定了一些category,同时我们也可以在应用中定义自己的category,category的匹配规则和action不同,它要求Intent中如果含有category,那么所有的category都必须和过滤规则中的其中一个category相同。换句话说,Intent中如果出现了category,不管有几个category 对于每一个category来说,它必须是过滤规则中已经定义了的category。当然Intent中可以没有category,如果咩有category的话 按照上面的描述,这个Intent仍然可以匹配成功。这里要注意下他和action匹配过程的不同,action是要求Intent中必须要有一个action且必须能够和顾虑规则中的某个action相同,而category要求Intent可以没有category,但是你一旦有category 不管有几个 每个都要能够和过滤规则中的任何一个category相同。

3.data的匹配规则

注:我之前写过一篇解锁Activity的跳转新姿势———使用scheme跳转其中使用的就是data匹配规则,有需要的了解下?

阅读更多

扫码向博主提问

Code-Porter

博客专家

非学,无以致疑;非问,无以广识
  • 擅长领域:
  • Android
  • ReactNativ
  • 微信小程序
去开通我的Chat快问

没有更多推荐了,返回首页