Android四大组件之Activity
Activity是Android四大组件中唯一的展示页面的组件,唯一的与用户可直接交互的组件。本篇文章从Activity的生命周期讲起,带你重拾Activity知识。
从本篇文章中你将学习到以下几点,若有不足之处请指正。
- 第一次启动App至前台开始接受焦点时,经历着怎样的生命周期状态
- 启动另一个页面或切换至另一个App时,经历着怎样的生命周期状态
- 在各生命周期方法中需做哪些操作
- 例:当播放网络视频时,切到另一个App,需暂停播放并终止网络连接,返回该App时恢复网络连接并允许用户从同样位置恢复播放
- 如何使你的App在不使用时,不占用系统资源
什么是Activity
- Android四大组件之一,提供屏幕进行交互
- 会获得一个用于绘制其用户界面窗口,窗口可充满屏幕也可是小窗口并浮在其他窗口之上
- 一个应用通常由一个或多个Activity组成,主Activity只有一个,为应用首次启动展示的页面
- 不同Activity可跳转,新Activity启动时,旧Activity停止,并入返回栈中(与启动模式有关),新Activity也会入栈,并获取焦点。返回时退出返回栈,并销毁,回至上个Activity
- 存在生命周期,发生变化,执行相关生命周期方法
管理你的Activity生命周期
Activity生命周期
- Activity从开始至结束所经历的各种状态
- 运行(Running):处于活跃状态,位于栈顶,状态可见,可与用户交互
- 暂停(Paused):失去焦点,非全屏Activity或透明Activity位于栈顶,不可与用户交互
- 停止(Stop):Activity被覆盖,其他Activity入栈,不可见
- 回收(Kill):Activity被回收
- 异常被杀执行onSaveInstance(),可保存信息,恢复执行onRestoreInstance()加载保存信息
当用户打开、退出App时,Activity同时经历着不同的生命周期状态。Activity完整的生命周期如下图所示
Activity的生命周期就像登机排队一样,由系统创建后,每回调一个生命周期函数就会往前一步,直到排到最前端就意味着轮到你了(可以和用户进行交互了)。此后会有两种情况:
- 1.来了vip用户,需要插队排在了你的前面,你就会暂居后位继续等待排队,等vip用户登机后回至最前位置或一直等待所有vip用户完成登机
- 2.登机直接走人,完成登机历程
Activity的生命周期方法并不需要我们都来实现,你只需根据具体的业务实现对应的方法即可。此时就需要我们了解每个方法的功能以确保你的App是按预期想象的那样执行
- onCreate():首次创建时调用,创建视图,绑定列表数据等
- onStart():可见,无焦点不可交互
- onResume():可见,可交互
- onPause():可见,失去焦点不可交互,弹出Dialog、退出或启动另一个Activity时回调
- 不可做耗时操作,会影响下一个页面的显示时间
- onStop():不可见,被后入栈Activity覆盖
- onDestroy():Activity销毁前回调
- onRestart():Activity已停止并即将再次启动重建时回调
- 注意事项
- 你的App使用时不会因启动其他App发生crash
- 未使用某项功能时不应消耗系统资源(例未点击获取位置时不应使用定位API获取位置信息)
- 离开你的App时要做好数据保存工作,以便用户返回时,还是当时状态
- 设备发生语言切换、横竖屏切换时,不会丢失用户数据或发生crash
Activity的启动与销毁
本章节主要学习如何启动你的App以及如何执行Activity的创建与销毁,主要介绍onCreate()和onDestroy()的使用。
- 和其他编程范式一样,Android App也有自己的main方法,在ActivityThread类中,但不是本章重点,就不展开讲述了,本小节的重点是App启动时涉及的Activity生命周期中最重要的回调函数。
主Activity设置
当用户点击App图标时,需要一个响应的Activity来启动你的App页面。系统首先会去查找你的App中声明为“launcher”或"main"的Activity,并启动它。
- 在
AndroidManifest.xml文件中将你的主Activity声明如下- 若未声明
action->MAIN或category->LAUNCHER,设备Launcher页面就不会展示你的App图标
- 若未声明
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
Activity简单使用
- onCreate()执行完毕会会迅速执行onStart()和onResume(),不会在onCreate()和onStart()中停留太久,最终停留在onResume()状态,直到其他干扰因素影响该状态(例弹框或启动其他Activity)。
- onDestroy()执行后会将你的Activity从系统中移除(非卸载),一般无需实现该方法,资源清除操作应放在onPause()或onStop()中处理,但你在onCreate()中创建的一些资源需在该方法中释放。
- 该方法在onPause()和onStop()之后执行,除非在onCreate()时就执行了finish()方法(例跳板Activity,用来启动系统浮窗App)
- 该方法中需做好导致内存泄漏的资源释放
class MainActivity: AppCompatActivity() {
private val binding: ActivityMaininding by lazy { ActivityMaininding.inflate(layoutInflater) }
// Activity创建
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 创建视图
setContentView(binding.root)
doSomething()
}
private fun doSomething() {
}
// Activity销毁
override fun onDestroy() {
super.onDestroy()
// 若存在需释放onCreate()中创建资源
// 释放导致内存泄漏的资源
}
}
Activity的暂停与恢复
本章节主要学习Activity暂停与恢复时,你应该做什么?主要介绍onResume()和onPause()的使用。
- 在使用App时,当前展示的Activity页面有可能被Dialog弹框遮挡
或被新的Activity页面遮挡(下节再讲),从而阻塞当前页面的交互,此时的Activity会进入Pause状态,调用Activity的onPause()方法- 此时Activity无焦点,不可与用户进行交互,此时可以做一些释放资源的操作,避免CPU资源浪费
- 暂停视频播放
- 停止动画执行
- 广播、传感器等的解注册
- 移除GPS定位监听
- 若使用WebView需调用onPause()方法
- 若使用Camera需调用release()释放资源
- 不要在onPause()中执行耗时的释放资源操作,可放在onStop()中,onPause会影响进入下一页面的时间(下节再讲)
- 此时Activity无焦点,不可与用户进行交互,此时可以做一些释放资源的操作,避免CPU资源浪费
- 当Dialog弹框关闭时,Activity从新获得焦点,从
Pause状态恢复到Resume状态,会调用Activity的onResume()方法- 此时可以恢复一些操作
- 恢复onPause()中的操作
- 此时可以恢复一些操作
class MainActivity: AppCompatActivity() {
private val binding: ActivityMaininding by lazy { ActivityMaininding.inflate(layoutInflater) }
// 传感器相关
private val sensorManager = getSystemService(Context.SENSOR_SERVICE) as? SensorManager
private var sensorListener: MySensorListener? = null
// Activity恢复
override fun onResume() {
super.onResume()
// 播放视频
// 初始化动画执行
// 广播注册
// 若使用WebView需调用onResume()方法
// 若使用Camera需初始化
// GPS定位监听
locationManager?.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0, 0, locationListener
)
// 注册加速传感器
val sensor = sensorManager?.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
sensor?.let {
// 支持加速传感器,注册
sensorListener = MySensorListener()
sensorManager?.registerListener(sensorListener, it, SensorManager.SENSOR_DELAY_NORMAL)
}
}
// Activity暂停
override fun onPause() {
super.onPause()
// 暂停视频播放
// 停止动画执行
// 广播解注册
// 若使用WebView需调用onPause()方法
// 若使用Camera需调用release()释放资源
// 移除GPS定位监听
locationManager?.removeUpdates(locationListener)
// 传感器解注册
sensorListener?.let {
sensorManager?.unregisterListener(it)
}
}
private inner class MySensorListener: SensorEventListener {
override fun onSensorChanged(event: SensorEvent?) {
// 处理传感器数据变化,x、y、z轴加速度,检测手机的晃动、倾斜等
event?.let {
val x = event.values[0]
val y = event.values[1]
val z = event.values[2]
}
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
// 处理传感器精度变化
}
}
}
Activity的停止与重启
本章节主要学习离开你的App与重启时会发生什么,你需要做什么?主要讲述与暂停、恢复的区别点onStop()、onRestart()、onStart()的使用。
- 首先介绍下Activity停止与重启的几种场景
- 跳转至新Activity页面时停止,返回该页面时会重启
- 点击通知或最近任务列表切换至另一个App时停止,点击桌面App图标和最近任务列表切回时会重启
- Home键回至主页时停止,点击桌面App图标和最近任务列表切回时会重启
- onStop()、onRestart()、onStart()是该场景下的主要生命周期方法
- onStop()区别于onPause()的点在于,此时Activity已不可见并且焦点被切换至新的页面
- 系统正常场景下会在Activity进入
Stop状态时保留该Activity实例,简单业务场景下一般无需实现该方法,实现onPause()即可- 系统资源不够时可能会释放资源杀掉该应用(异常场景暂不考虑,留至下一章节)
- 涉及耗时资源释放时,可重写onStop()释放资源
- 系统正常场景下会在Activity进入
- onRestart()方法中一般不做处理,只有从onStop()状态切回时才会回调该方法
- onStart()区别于onResume()的点在于,此时Activity可见,但还无法获取焦点
- 该方法在正常创建Activity和重启时都会回调
- 可在该方法中做onStop()的恢复工作
- onStop()区别于onPause()的点在于,此时Activity已不可见并且焦点被切换至新的页面
- 停止至重启经历的生命周期方法是onPause() -> onStop() -> onRestart() -> onStart() -> onResume()
class MainActivity: AppCompatActivity() {
private val binding: ActivityMaininding by lazy { ActivityMaininding.inflate(layoutInflater) }
// 该方法中一般不做处理,只有从onStop()状态切回时才会回调该方法
override fun onRestart() {
super.onRestart()
}
// 初始化onStop()中释放的资源
override fun onStart() {
super.onStart()
}
// 耗时的操作可在此处处理,避免阻塞下一个页面的开启
override fun onStop() {
super.onStop()
val values = ContentValues()
values.put("key", "value")
contentResolver.update(uri, values, null, null)
}
}
Activity的重建
本章主要学习哪些场景会导致Activity被销毁并重建,此时我们应该做什么
-
正常销毁场景(此处只列举不展开讲述)
- 按后退键退出当前页面,用户主动退出,无需做任何处理
- 业务逻辑需要退出页面的
finish()方法调用
-
异常场景销毁(此时需要做好数据恢复准备)
- 系统因资源不足时关闭后台进程,再次进入会进入重建过程
- 长时间
Stop状态的Activity也可能被系统关闭,再次进入会进入重建过程 - 横竖屏切换时,会经历销毁重建过程,以加载一些资源(例横竖屏采用不同的布局资源)
-
数据保存
- 默认情况下,一般都使用Bundle对象的key-value保存页面数据(例有编辑框时,保存编辑框内容以便恢复;还有其他状态数据等等)
- onSaveInstanceState(Bundle)和onRestoreInstanceState(Bundle)是Android系统提供了两个用于保存和恢复数据的方法
- 离开Activity时可在onSaveInstanceState(Bundle)中保存数据,以便异常场景恢复重建时在onRestoreInstanceState中取出数据恢复原状态
- onRestoreInstanceState在onStart之后执行,恢复数据最好在该方法中,无需判空
class MainActivity: AppCompatActivity() {
private val binding: ActivityMaininding by lazy { ActivityMaininding.inflate(layoutInflater) }
// 在此方法中恢复数据,无需判空;尽量不要在onCreate中恢复
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
val state = savedInstanceState.getInt("")
val editText = savedInstanceState.getString("")
}
// 需要调用父类的onSaveInstanceState数据才会保存
override fun onSaveInstanceState(outState: Bundle) {
outState.putInt("", status)
outState.putString("", editText)
super.onSaveInstanceState(outState)
}
}
小结
正常场景生命周期回调
-
启动app:onCreate -> onStart -> onResume
- Home键回至主页面:onPause -> onStop
- Home键回至主页面再次打开app:onRestart -> onStart -> onResume
- 返回键:onPause -> onStop -> onDestroy
-
跳转至其他页面:onPause(A) -> onCreate(B) -> onStart(B) -> onResume(B) -> onStop(A)
- 新页面返回键:onPause(B) -> onRestart(A) -> onStart(A) -> onResume(A) -> onStop(B) -> onDestroy(B)
异常场景生命周期回调
- onCreate时调用finish,做中转Activity
- 横竖屏切换时未作任何处理,重走生命周期方法,从onCreate开始
- 栈顶Activity或singleTask的Activity再次启动时直接执行onNewIntent方法,不会执行onCreate