Android 开发艺术探索 第一章

第一章 Activity的生命周期和启动模式

概述:本章主要介绍Activity相关的一些内容。Activity作为四大组件之首,是使用最频繁的一种组件,中文译为“活动”。如果译为“界面”就会更好理解了,正常情况下,除了 Window,Dialog和Toast,我们能见到的界面只有Activity了。本章的侧重点是Activity在使用过程中的一些不容易搞懂的概念,主要包括生命周期和启动模式,以及IntentFilter的匹配规则分析。

1.1 Activity的生命周期全面分析

1.1.1 典型情况下的生命周期分析

典型情况下的生命周期是指:在有用户参与的情况下,Activity所经过的生命周期的改变。
正常情况下生命周期如下:
(1)onCreate: 表示Activity正在被创建,这是生命周期的第一个方法。在这个方法中我们可以做一些初始 化的工作,比如调用setContentView去加载界面布局资源,初始化Activity所需要的数据。
(2)onRestart:表示Activity正在重新启动。一般情况下,当当前的Activity从不可见重新变为可见状态 时,onRestart就会被调用。这种情况一般是用户行为导致的,比如用户按Home键切换到桌面或者用户打开了 一个新的Activity,这时当前Activity就会暂停,也就是onPause和onStop就执行了,接着用户又回到这个Activity,就会出现这种情况。
(3)onStart:表示正在被启动,即将开始,这时Activity已经可见了,但是还没有出现在前台,还无法与用户交互。这个时候可以理解为Activity已经显示出来了,但是我们还看不到。
(4)onResume:表示Activity已经可见了,并且出现在前台开始活动(此时理解为获得了焦点)。要注意这个和onStart的对比,onStart和onResume都表示Activity可见。但是onStart的时候Activity在后台(此时没有获得焦点),onResume的时候Activity才显现到了前台(此时获得了焦点)。
(5)onPause:表示Activity正在停止(失去焦点),正常情况下,紧接着onStop就会被调用。在onPause中我们可以做一些存储数据,停止动画等工作,但是不能太耗时,因为这会影响到新Activity的显示,onPause必须先执行完,新Activity的onResume才会被执行。
(6)onStop:表示Activity即将停止,可以做一些稍微重量级的回收工作,同样也不能太耗时。
(7)onDestroy:表示Activity即将被销毁,这是Activity生命周期的最后一个回调,在这里,我们可以做一些回收工作和最终资源的释放。
流程图如下:

这里写图片描述

1.1.2 异常情况下的生命周期分析

异常情况下的生命周期是指:Activity被系统回收或者由于当前设备的Configuration发生改变从而导致Activity被销毁重建。
(1)情况1:资源相关的系统配置发生改变导致Activity被杀死并重建

横竖屏切换导致系统配置发生变化,默认情况下,系统配置发生变后,Activity就会被销毁并重新创建,生命周期如下:Activity—系统配置发生变化→onSaveInstanceState→onPause→onStop→onDestroy—重新创建→onCreate→onStart→onRestoreInstanceState→onResume
当系统配置发生改变后,Activity会被重建。我们可以通过一些属性,在系统配置改变时不重建Activity,比如可以指定Activity的configChanges属性,将值设置为orientation,那么横屏时不重建Activity。

(2)情况2:资源内存不足导致低优先级的Activity被杀死

当系统资源内存不足时,会根据Activity的优先级杀死Activity,由低到高。Activity的优先级分为三种:
①前台Activity:正在和用户交互的Activity,优先级最高
②可见非前台的Activity:比如Activity中弹出一个对话框,导致Activity可见但是位于后台无法与用户交互
③后台Activity:已经被暂停的Activity,比如执行了onStop方法,优先级最低。
系统会按照上述优先级去杀死目标Activity所在的进程,并通过onSaveInstanceState和onRestoreInstanceState方法存储和恢复数据。如果一个进程中没有四大组件在执行,那么这个进程将会很快被系统杀死。因此一些后台工作不适合脱离四大组件而独自运行在后台中,这样进程容易被杀死。比较好的方式是将后台工作放在Service中进行从而保证进程有一定的优先级。

1.2 Activity的启动模式

1.2.1 Activity的LaunchMode

Activity有四种启动模式:standard 、singleTop、singleTask singleInstance。有两种方式可以为Activity设置启动模式:①:xml方式 但是此方式不能指定为 FLAG_ACTIVITY_CLEAR_TOP,②:Intent中同过addFlags方式设置,但此种方式不能设置为 singleInstance模式。

(1)standard:标准模式,这也是系统的默认模式。每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。这是一种典型的多实例实现,一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈。在这种模式下,谁启动了这个Activity,这个Activity就运行在启动它的那个Activity所属的任务栈中。
(2)singleTop:栈顶复用模式。在这种模式下,如果新的Activity已经位于任务栈的的栈顶,那么此Activity就不会被重写创建,同时它的onNewIntent方法会被回调,通过此方法参数我们可以读取当前请求信息。如果这个Activity已经存在但是没有位于栈顶,那么这个Activity依然会被重写创建。
(3)singleTask:栈内复用模式。这是一种单例模式,在这种模式下,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,但是会重新调用onNewIntent。具体一点,比如启动一个SingleTask模式的Activity A,系统首先会寻找是否存在A想要的任务栈,如果不存在这个栈,就会重新创建一个任务栈,然后创建A的实例放入栈内。如果存在A想要的任务栈,就会查找是否存在A实例,如果存在就会清楚A顶部的其他Activity实例,这样A机会处于栈顶,如果不存在A实例,就会创建A实例放入栈内。
(4)singleInstance:单实例模式。这是加强的的singleTask模式,他除了singleTask模式的所有特点外,还加强了一点。那就是具有此种模式的Activity只有单独地位于一个任务栈中,换句话说就是,比如Activity A 是singleInstance模式,当A启动后,系统会为它新建一个任务栈,然后A独自存这个任务栈中,由于他具有singleTask的特性,后续的请求均不会创建新的Activity,除非这个任务栈被销毁了。

总结

①一个栈中存放的Activity不一定是同一个应用的Activity。(举个例子,当A应用的A页面启动了B应用的B页面,如果此时B页面是标注模式那么此时B页面会进入A页面所在的栈。那么此时A应用的A页面和B应用的B页面存在一个栈中。重点来了:如果此时,用户home键回到桌面打开了B应用,那么此时B页面会立刻马上回到B应用开启的新栈中。默认情况下栈的名字和应用的包名一样,通过 taskAffinity属性可以为Activity选在想要存放的栈)
②启动一个应用,系统就会寻找或者创建一个栈名为该应用包名的栈 ,默认情况下,栈名即是包名,来放置根Activity
③一个应用不一定只存在一个栈
④按back键回退时,Activity后进行先出,系统存在的栈也会按一定规则回退。

1.2.2 Activity的Flags

Activity的Flags有很多,这里主要分析一些常用的的标记位。标记位的作用有很多,有的标记位可以设定Activity的启动模式,比如:FLAG_ACTIVITY_NEW_TASK 和 FLAG_ACTIVITY_SINGLE_TOP等 ,还有的标记位可以影响Activity的运行状态,比如:FLAG_ACTIVITY_CLEAR_TOP 和 FlAG_ACTIVITY_EXCLUDE_FROM_RECENTS 等。
(1)FLAG_ACTIVITY_NEW_TASK :这个标记的作用是为了Activity指定“singleTask”的启动模式,其效果和在xml中指定该启动模式相同。
(2)FLAG_ACTIVITY_SINGLE_TOP:这个标记的作用是为了Activity指定“singleTop”的启动模式,其效果和在xml中指定该启动模式相同。
(3)FLAG_ACTIVITY_CLEAR_TOP:具体该标记的Activity,当启动它时,在同一个任务栈所有位于它上部的Activity都要出栈,这个标记一般会和singleTask启动模式一起出现。
(4)FlAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有这个标记的Activity不会出现在历史Activity列表中,当某些情况下我们不希望用户通过历史列表回到我们的Activity的时候这个标记比较有用。它等于在xml中指定Activity的属性:Android:excludeFromRecents=“true”。

1.3 IntentFilter的匹配规则

我们知道,启动Activity有两种方法,显式调用和隐式调用。显示调用需要明确指定被启动对象的组件信息,包括包名和类名。而隐式调用则不需要指定被启动组件的信息。原则上 一个Intent不能及时显式调用又是隐式调用,如果二者都存在,则以显式调用为主。

IntentFilter 就是为隐式调用提供匹配规则的。在隐式调用过程中Intent不能匹配目标组件中IntentFilter所设置的过滤信息。则无法启动目标Activity。IntentFilter中的顾虑信息有 action category data 。下面是一个过滤规则的示例:

       <activity
            android:name=".SecondActivity"
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="com.jack.charpter_1.c" />
                <action android:name="com.jack.charpter_1.d" />

                <category android:name="com.jack.category.c" />
                <category android:name="com.jack.category.d" />
                <category android:name="android.intent.category.DEFAULT" />

                <data android:mimeType="text/plain" />
            </intent-filter>
        </activity>
可以清楚的看到,一个匹配规则过滤列表中的 action category data 有多个。只有一个Intent同时匹配任意一个action 所有category 任意一个data时,才能匹配成功。
(1)action 匹配规则 :
action 是一个字符串,系统预定义了一些 action ,同时我们也可以在应用中定义自己的 action 。action 的匹配规则是 Intent 中的 action 必须能够和过滤规则中的 action 匹配,这里说的是指 action 的字符串值完全一样。一个过滤规则中可以有多个 action ,那么只要 Intent 中必须有 action 能够和和过滤规则中的任意一个 action 相同即可匹配成功。
(2)category 的匹配规则
category 是一个字符串,系统预定义了一些 category ,同时我们也可以在应用中定义自己的 category 。category的匹配规则和 action 不同。它要求 Intent 中出现的所有 category 在过滤规则中都必须存在。当然 Intent 中也可以没有 category ,如果没有 category 的话,按照上述规则任然可以匹配成功。如果不设置 category ,系统会默认为我们的 Intent 设置一个 “android.intent.category.DEFAULT”这个 category ,为了我们的 Activity 能够接受隐式调用,就必须在 Intent-Filter 中指定“android.intent.category.DEFAULT”这个category。
(3)data 匹配规则
data 结构语法:
                <data
                    android:mimeType="string"
                    android:scheme="string"
                    android:host="string"
                    android:port="8080"
                    android:path="/string"
                    android:pathPrefix="/string"
                    android:pathPattern="string" />
可以清楚看到 data 由两部分组成,mimeType 和 URI 。mimeType 指媒体类型,比如 image/jpeg andio/mpeg4-generic 和 video/* 等。可以表示 图片 文本 视频等不同的媒体格式,而URI 是统一资源标识符。
data 匹配规则:和 action 类似,如果规则中定义了 data ,那么 Intent中必须含有 data 数据,并且 data 数据能够 完全匹配规则中的某一个 data。这里的完全匹配是指 规则中出现的 data 部分,也出现在 Intent 的 data 中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值