Activity 的概念
Activity是应用与用户交互的入口点,它提供窗口供应用在其中绘制UI,这个窗口可能填满整个屏幕,也可能小于屏幕悬浮在其他窗口之上。通常来说一个应用会存在多个Activity,但只会存在一个主Activity(用户启动应用时显示的第一个Activity),然后每个Activity都可以启动另外的Activity以组成多屏幕的应用。
配置清单
如果要使用Activity,我们必须在AndroidManifest.xmk清单中配置,如下
xml
<!--主Activity-->
<activity
android:name=".activity.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--正常Activity-->
<activity
android:name=".activity.SecondActivity"
android:exported="true">
</activity>
Activity启动
Activity的启动由Intent触发,其中Intent又分为显示Intent和隐式Intent,显示Intent可以明确的指向某一个Activity,隐式Intent则指向一个或多个Activity。一般来讲一个Intent不应该既是显示又是隐式,如果二者共存以显示为主。
显示Intent
属于精确匹配,有以下三种构建方式
1. 在Intent构造函数中指定
kotlin
startActivity(Intent(this@MainActivity,SecondActivity::class.java))
2. 调用意图对象的setClass方法指定
kotlin
val intent = Intent()
intent.setClass(this@MainActivity,SecondActivity::class.java)
startActivity(intent)
3. 调用意图对象的setComponent方法指定
kotlin
val intent = Intent()
val componentName = ComponentName(this@MainActivity,SecondActivity::class.java)
intent.setComponent(componentName)
隐式Intent
没有明确指定要跳转的目标Activity,通过IntentFilter匹配规则来指定跳转的Avtivity,过滤信息有action、category和data,如下所示是一个例子
xml
<activity
android:name=".activity.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="com.abiao.action.a" />
<action android:name="com.abiao.action.b" />
<category android:name="com.abiao.category.a" />
<category android:name="com.abiao.category.b" />
<data android:mimeType="text/plain"/>
</intent-filter>
<intent-filter>
<action android:name="com.abiao.action2.a" />
<action android:name="com.abiao.action2.b" />
<category android:name="com.abiao.category2.a" />
<category android:name="com.abiao.category2.b" />
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
一个Activity可以有一个或多个intent-filter,一个intent-filter可以有多个action、category和data,只要一个Intent同时匹配到一个intent-filter中的action、category和data就表示匹配成功,否则失败。
action 匹配规则
- action是一个字符串,系统有一些预定义的action,我们也可以在应用中定义自己的action。
- 匹配规则是字符串完全相同,区分大小写。
- Intent中只存在一个action。
- Intent中的action需要存在且和规则中的其中一个action相同,否则匹配失败。
category 匹配规则
- category是一个字符串,系统有一些预定义的category,我们也可以在应用中定义自己的category。
- 匹配规则是字符串完全相同,区分大小写。
- Intent中可以存在多个category。
- 匹配规则是Intent中任意一个category都能和category过滤规则中的其中一个匹配上。
- 如果Intent中没有category,依然能匹配成功,因为系统在调用startActivity或者startActivityForResulet的时候默认添加了android.intent.category.DEFAULT。
- 在匹配规则中我们需要添加android.intent.category.DEFAULT这个category
data 匹配规则
data的结构如下:
xml
<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组成
-
mimeType指媒体类型(image/jepg、audio/mpeg4-generic和video/* 等表示图片、文本、视频),有默认值(content和File)
-
URI 由以下结构
xml<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
- scheme URI 模式,如http、file、content等,如果不指定则URI无效。
- host URI 主机名,如www.baidu.com,如果不指定则无效
- port URI 端口号,如 80
- path 完整的路径信息
- pathPattern 完整的路径信息,包含通配符*,*表示0个或者多个任意字符
- pathPrefix 路径前缀信息
-
设置方法如下
kotlin
intent.setDataAndType(Uri.parse(""),"image/png")
//会将mimeType设置为null等价于intent.setDataAndType(Uri.parse(""),null)
intent.setData(Uri.parse("file://abs"))
//会将uri设置为null等价于intent.setDataAndType(null,"image/png")
intent.setType("image/png")
- 匹配规则如下
- data存在且只要匹配上规则上其中一条,表示匹配成功。
- 特殊写法,以下两种写法作用是一样的:
xml
<!--写法一-->
<intent-filter>
<data android:mimeType="text/plain" android:scheme="file" android:host="www.baidu.com"/>
</intent-filter>
<!--写法二-->
<intent-filter>
<data android:mimeType="text/plain"/>
<data android:scheme="file"/>
<data android:host="www.baidu.com"/>
</intent-filter>
- 查找失败判断 通过隐式Intent启动Activity的时候可能会遇到找不到Activity的情况,这个时候系统会报错导致App崩溃,为了避免这种问题有以下两种方法可以判断是否存在Activty,如果这两个方法返回值不等于null,就可以启动成功。
- PackageManager的resolveActivity(Intent,flags)方法,flags 需要MATCH_DEFAULT_ONLY这个标记位
- Intent的resolveActivity
生命周期
正常情况下的生命周期
正常情况下,Activity会经历以下的生命周期
-
onCreate
表示Activity正在被创建,这里可以做一些初始化工作(加载界面布局资源,初始化Activity所需要的一些数据)
-
onRestart
表示Activity正在重新启动,当当前Activity从不可见变为可见状态时就会被调用
-
onStart
表示Activity正在被启动,这时候Activity已经可见但是还未出现在前台,无法与用户交互。
-
onResume
Activity已经可见,在前台出现并开始活动,可以与用户交互。
-
onPause
表示Activity正在停止,在正常情况下马上会调用onStop,但是在特殊情况下快速返回当前Activity,onReseume就会被调用,但这种情况很极端,用户很难遇见。这里可以做一些存储数据、停止动画之类的操作。但是不能太耗时,因为只有onPause执行完了新的Activity的onResume才会执行。
-
onStop
Activity即将停止,同样不能做太耗时工作,可以比onPause稍微重一点的任务
-
onDestroy
表示Activity即将销毁,这里可以做一些回收工作和最终的资源释放。
- 注意
- 当用户打开了一个新的Activity,当前Activity回调如下:onPause -> onStop,但是当新的Activit是一个透明Activity时,当前Activity不会回调onStop.
- 当用户按下back键时,回调如下:onPause -> onStop -> onDestroy
- onCreate和onDestroy配对的,表示Activity的创建与销毁,整个生命周期中只调用一次。onStart和onStop也是配对的,便是Activity的可见与否,随着用户的操作或者屏幕点亮与否可能会回调多次。onResume和onPause也是配对的,表示Activity是否在前台。与onStart和onStop一样可能会被调用多次。
异常情况下的生命周期
Activity的生命周期除了受到用户操作影响之外也很可能因为资源相关的系统配置改变或者内存不足的时候被杀死。
资源相关的配置改变导致Activity被杀死并重建
资源相关配置会改变与系统的资源加载机制有关,举个例子,当我们把一张图片放在drawable目录后,可以通过Resource去获取,为了兼容不同设备我们可能会在其他目录(drawable-mdpi、drawable-hdpi、drawable-land等等),系统会根据不同的机型加载不同的Resource资源。但是假如Activity当前处于竖屏状态突然旋转屏幕,系统配置就发生了改变。默认情况下系统就会销毁当前Activity并重新创建。
这个时候当前Activity的生命周期如下: 系统资源被改变之后,Activity的onPause、onStop、onDestory会被调用,因为是异常终止所以,在onStop被调用之前系统会调用onSaveInstanceState来保存当前Activity的状态。Activity被重新创建之后,系统会把Activity销毁时在onSaveInstanceState中保存的Bundle对象作为参数传个onRestoreInstanceState和onCreate,因此我们可以通过onRestoreInstanceState和onCreate来判断Activity是否被重新创建了。onRestoreInstanceState的调用时机是在onStart之后。
资源改变时候我们可以通过配置configChanges这个属性来让Activity不重新创建
xml
android:configChanges="orientation"
内存不足倒是低优先级的Activity被杀死
Activity的优先级
- 前台Activty 正在和用户交互的Activity 优先级最高
- 可见但非前台Activity
- 后台Activity 已经被暂停了的Activity
当系统内存不足的时候,系统会按照以上优先级杀死目标Activity,并通过onSaveInstanceState和onRestoreInstanceState来存储和恢复数据。
Activity启动模式
STANDARD 标准模式(默认)
每次启动都会重新创建一个新的Activity实例,不管当前实例是否存在。一个任务栈中可以存在多个实例,每个实例也可以属于不同的任务栈。谁启动了当前Activity那么这个Activity就在谁所在的那个任务栈当中。注意,如果是非Activity(如ApplicationContext)类型的Context去启动了一个新Activity会报错,是因为ApplicationContext没有所谓的任务栈,要启动需要使用下面准备介绍的SINGLE_TASK启动模式
SINGLE_TOP 栈顶复用模式
如果要创建的Activity位于栈顶,那么将不会重新创建实例,同时会调用Activity的onNewIntent方法,当前Activity的onCreate、onStart方法不会被系统调用。假如创建的Activity不在栈顶,那么就会重新创建一个新的实例。
SINGLE_TASK 站内复用
一种单实例模式,只要Activity在任务栈中存在,多次去启动改Activity都不会重新创建实例,同时和SINGLE_TOP一样会调用它的onNewIntent方法。当用该模式启动之后,系统会寻找是否存在其想要的任务栈,如果不存在则创建新的任务栈正常创建其实例,如果存在则将其实例调到栈顶并复用(调用其onNewIntent方法)。
SINGLE_INSTANCE 单实例模式
加强版的SINGLE_TASK,具有SINGLE_TASK的所有特性,另外具有此模式的Activity只能独立位于单独的任务栈中。由于SINGLE_TASK的特性,通过其创建的Activity都位于这个任务栈内,且只能存在一个实例。