Android 四大组件系列详解:
Android 四大组件之—Activity 详解
Android 四大组件系列之—-Service 详解
Android 四大组件系列之—BroadcastReceiver 详解
Android Activity生命周期详解
1. 什么是Activity?
- Activity作为Android四大组件之一,它有着举足轻重的地位,每一个Activity都会获得一个用于绘制其用户界面的窗口,Activity是一个view对象的容器,通过Window类的setContentView()方法添加到Activity上,最终提供与用户交互的界面;
- Activity是上下文对象 Context的子类, 并且实现了Window.callback,KeyEvent.callback 这两个接口,因此 Activity 可以响应和处理用户与窗口的交互事件,以及键盘相关的输入事件;
- 一个Android应用通常由一个或者多个Activity 组成;如果是多个Activity,一般会指定应用中的某个 Activity 为“主” Activity,即首次启动应用时呈现给用户的那个 Activity。 而且每个Activity 通过使用Intent(意图)均可启动另一个Activity,这里使用的是IPC机制。 每次启动一个新的Activity 启动时,前一 Activity 便会停止,但系统会在回退桟中保留该 Activity,而新启动的Activity可以放如该栈顶也可以设置其启动方式放入新的回退桟,这就和Activity四种启动方式有关了。
附上一张图,对Activity有一个更直观和全面的认识:
对Activity有了一个比较直观的认识后,我们自然想到的是怎么使用它,其实对于Activity google对其封装的还是挺厉害,开发者使用时主要就是继承Activity,通过setContentView()方法设置布局界面,然后重写它的几个生命周期函数;而跳转新的Acitivty更简单,通过一个Intent然后调用startActivity方法即可;
2. Activity生命周期
其实对于Activity最重要的就是搞清楚它的各个生命周期函数,只有这样我们才能知道Activity在各个生命周期阶段需要做什么事,那些事不适合做,这对于编写高质量的App是至关重要的;
Activity是通过回退桟来管理的,此时Activity可呈现出四种状态:
(1) 当Activity位于回退栈桟顶时,此时将显示在屏幕上,用户可与之交互,此时Activity处于运行状态;
(2) 当Activity失去了焦点但依然可见(如栈顶Activity尺寸小没有完全覆盖屏幕,或者栈顶Activity是透明的),此时Activity处于暂停状态;
(3) 当Activity被新的Activity或者应用完全遮住(新Activity不透明),因此Activity已经对用户不可见,此时Activity处于停止状态;
(4) 当Activity被完全退出或者App进程完全退出时,Activity将会回调onDestory方法,之后Activity将被销毁,Activity将处于销毁状态;
下面我们主要阐述Activity的生命周期:
同样我们先附上图(来自Android官方文档):
1. 首先对Activity主要生命周期函数做介绍:
(1) onCreate
Activity生命周期的第一个方法,表示Activity正在被创建,在该方法中通过setContentView 方法加载xml编写的布局文件,然后通过findByViewId方法获取控件;
onCreate()方法在Activity整个生命周期中只会调用一次,所以该方法中就可以做一些大致只需要做一次的工作,如:一些变量的初始化,资源的加载,初始化控件以及事件的绑定等;
由于此时view还没有加载出来,因此该方法中不能开启动画的;
注:onCreate()的官方文档注释,建议 setContentView()、findViewById() 在 onCreate() 中调用,但在onStart()中调用 setContentView()、findViewById() 功能也是正常的,只是不建议,并且很少会这样做;
(2) onStart
Activity正在启动,此时Activity已经看见,但是没有展现在前台,没有获取到焦点,当然也就不能与用户交互;
因为该方法是Activity重新回到前台时第一个回调的方法,因此在该方法里我们可以去检查某些必须的系统特性是否可用,比如网络是否在连接, GPS是否打开等类似的功能;
该方法中我们通常初始化一些变量,当然这些变量必须是在Activity处于前台的时候才能够被响应;
(3) onResume
Activity可见可交互;
如果Activity是重新打开,此时就需要在该方法中重新实例化在onPause()中释放的资源;
初始化在前台显示时需要的资源,如:动画、播放视频,此外建议在onResume()中打开独占设备,比如相机,之所以在该方法中打开是因为当打开新的Activity时,首先会onPause掉旧Activity,然后在onCreate, onStart, onResume新Activity,如果之前旧Activity已经打开了独占设备(相机), 那此时onPause旧Activity时就可以释放掉独占设备(相机),那么打开的新Activity就能够使用独占设备(相机)了;
(4) onPause
Activity已经暂停,可见但不在前台,因此也不可交互;
该方法中需要持久化用户数据、停止动画,暂停正在播放的视频等不太耗时的操作;
释放部分占用的系统资源(尤其是独占设备),如:相机, GPS等,设置有时会让该Activity断开网络连接,因为这些工作会大幅度占用系统资源,增加电耗或者流量消耗;
因为打开新的Activity前回去回调旧Activity的onPause方法,因此onPause方法中不能做太耗时的操作(如,数据库读写,IO操作),否则调新的 Activity 在切换时可能会出现卡顿现象,这是用户不想看到的;
耗时的清理工作应该放在onStop方法中;
(5) onStop
Activity即将停止,此时当然不可见;
耗时的清理工作应该放在onStop方法中;
Activity 在此状态时仍然存在于内存中,如果在系统内存不够时,系统接下来很快会销毁掉该Activity,在极端情况下,直接 kill Activity 且不执行onDestroy()函数。所以务必在onStop()函数中就清理掉可能引起内存泄露的资源,当然更极端的时系统内存已严重不足,导致系统无法保留该进程的情况下,onStop() 可能都不会被执行;
(6) onDestory
Activity即将被销毁,
很多情况下 Activity 是不需要定义这个函数,因为在onPause()和onStop()中,大多数的清理工作都已经完成了。但是,如果在onCreate()中定义了后台线程,或者可能引起内存泄露的代码,那就需要在onDestroy()中清理,如,静态对象持有其他Activity的引用,广播注销等操作;
(7) onRestart
Activity正在被重新启动
在原Activity没有销毁时重新要回到该Activity时会回调该方法,紧接着会回调onStart方法,一般在该方法中恢复用户数据;
其实Activity生命周期函数可以看成是成对的,onCreate和onDestory成对,onStart和onStop成对,onResume和onPause成对,这在上述每个回调函数的介绍中也可以看出来
2. 下面阐述几种比较常见的情况:
(1) 单个A Activity启动回调流程
onCreate
onStart
onResume
(2) 当用户按下home键时
onPause
onStop
(3) 当用户再次回到原Activity时
onRestart
onStart
onResume
(4) 在A Activity的基础上,打开新的B Activity,此时需要注意的问题是B Activity的大小和透明度
a. B Activity完全覆盖A Activity,并且B Activity是不透明的:
A Activity: onPause
B Activity: onCreate –> on Start –> onResume
A Activity : onStop
b. B Activity因为尺寸小没有完全覆盖A Activity,或者B Activity是透明的, 此时A Activity的onStop方法是不会被执行的
A Activity: onPause
B Activity: onCreate –> on Start –> onResume
(5) 当用户按back键时
onPause
onStop
onDestory
(6). 横竖屏切换时 Activity 的生命周期
此时的生命周期跟清单文件里的配置有关系。
1.不设置 Activity 的 android:configChanges
时,切屏会重新调用各个生命周期默认首先销毁当前 activity,然后重新加载。
2.设置 Activity android:configChanges=”orientation|keyboardHidden|screenSize”
时,切屏不会重新调用各个生命周期,只会执行 onConfigurationChanged
方法。
3. 保存 Activity 的状态
Activity
的状态通常情况下系统会自动保存,只有当我们需要保存额外的数据时才需要使用到这样的功能。
通常调用了 onPause()
和 onStop()
方法后的 Activity 实例仍然存在于内存中, 此时Activity
的信息和状态数据不会丢失, 当activity
重新回到前台之后, 会重新恢复到之前的装填; 但是当系统内存不足时, 调用 onPause()
和 onStop()
方法后的 Activity很可能会被系统销毁, 此时内存中就不会存有该
Activity的实例了, 如果此时再让这个 Activity 回到前台, 它只能重新启动, 执行
onCreate(0,
onStart()和
onResume()`方法, 之前Activity的改变
全部丢失 。
这种情况是我们不想看到的, 怎么样避免发生呢 , 我们可以覆写 onSaveInstanceState()
方法; onSaveInstanceState()
方法接受一个 Bundle
类型的参数, 开发者可以将状态数据存储到这个Bundle对象中, 这样即使Activity
被系统摧毁, 当用户重新启动这个Activity
会调用它的onCreate()
方法时, 我们可以在onCreate()方法中拿到这个 Bundle
对象, 从而取出之前保存的Activity
数据, 然后利用这些数据将 activity 恢复到被摧毁之前的状态。
需要注意的是,
onSaveInstanceState()
方法并不是一定会被调用的, 因为有些场景是不需要保存状态数据的. 比如用户按下 BACK 键退出 activity 时, 用户显然想要关闭这个 activity, 此时是没有必要保存数据 以供下次恢复的, 也就是 onSaveInstanceState()方法不会被调用. 如果 调用onSaveInstanceState()方法, 调用将发生在 onPause()或 onStop()方法之前。
4. 如何在APP退出的时候结束所有的Activity
大致有以下方法可以参考使用:
1. 发送特定广播
1. 在需要结束应用时,发送一个特定的广播,每个 Activity 收到广播后,关闭;
2. 递归退出
在打开新的 Activity 时使用 startActivityForResult
,然后自己加标志,在 onActivityResult 中处理,递归关闭。
3. 其实也可以通过 intent 的 flag 来实现 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
激活一个新的 Activity
。此时如果该任务栈中已经有该 Activity,那么系统会把这个 Activity 上面的所有 Activity 干掉。其实相当于给 Activity 配置的启动模式为 SingleTop
。
如有错误,欢迎指正,谢谢!