1.简介
2.生命周期
2.1 生命状态概述
Activity是一个很重要、很复杂的组件,他的启动不像我们平时直接new一个对象就完事了,他需要经历一系列的初始化。例如"刚创建状态",“后台状态”,“可见状态”等等。当我们在界面之间进行切换的时候,activity也会在多种状态之间进行切换,例如可见或者不可见状态、前台或者后台状态。当Activity在不同的状态之间切换时,会回调不同的生命周期方法。我们可以重写这一些方法,当进入不同的状态的时候,执行对应的逻辑。
生命周期的一个重要作用就是让activity在不同状态之间切换的时候,可以执行对应的逻辑。我们在界面A使用了相机资源,当我们切换到下个界面B的时候,那么界面A就必须释放相机资源,这样才不会导致界面B无法使用相机;而当我们切回界面A的时候,又希望界面A继续保持拥有相机资源的状态;那么我们就需要在界面不可见的时候释放相机资源,而在界面恢复的时候再次获取相机资源。每个Activity一般情况下可以认为是一个界面或者说,一个屏幕。当我们在界面之间进行导航切换的时候,其实就是在切换Activity。当界面在不同状态之间进行切换的时候,也就是Activity状态的切换,就会回调activity相关的方法。例如当界面不可见的时候会回调onStop方法,恢复的时候会回调onReStart方法等。
2.2 主要生命周期![](https://i-blog.csdnimg.cn/blog_migrate/2dd17c1a7803f0fed0ef819ad957d87f.webp?x-image-process=image/format,png)
首先我们先看到最重要的七个生命周期,这七个生命周期是严格意义上的生命周期,他符合状态切换这个关键定义。
1
-
onCreate:当Activity创建实例完成,并调用attach方法赋值PhoneWindow、ContextImpl等属性之后,调用此方法。该方法在整个Activity生命周期内只会调用一次。调用该方法后Activity进入ON_CREATE状态。
该方法是我们使用最频繁的一个回调方法。
我们需要在这个方法中初始化基础组件和视图。如viewmodel,textview。同时必须在该方法中调用setContentView来给activity设置布局。
这个方法接收一个参数,该参数保留之前状态的数据。如果是第一次启动,则该参数为空。该参数来自onSaveInstanceState存储的数据。只有当activity暂时销毁并且预期一定会被重新创建的时候才会被回调,如屏幕旋转、后台应用被销毁等
2
-
onStart:当Activity准备进入前台时会调用此方法。调用后Activity会进入ON_START状态。
前台并不意味着Activity可见,只是表示activity处于活跃状态
前台activity一般只有一个,所以这也意味着其他的activity都进入后台了。这里的前后台需要结合activity返回栈来理解
这个方法一般用于从别的activity切回来本activity的时候调用。
3
-
onResume:当Activity准备与用户交互的时候调用。调用之后Activity进入ON_RESUME状态。
这个方法一直被认为是activity一定可见,且准备好与用户交互的状态。但事实并不一直是这样。如果在onReume方法中弹出popupWindow你会收获一个异常:token is null,表示界面尚没有被添加到屏幕上。
但是,这种情况只出现在第一次启动activity的时候。当activity启动后decorview就已经拥有token了,再次在onReume方法中弹出popupWindow就不会出现问题了。
因此,在onResume调用的时候activity是否可见要区分是否是第一次创建activity。
onStart方法是后台与前台的区分,而这个方法是是否可交互的区分。使用场景最多是在当弹出别的activity的窗口时,原activity就会进入ON_PAUSE状态,但是仍然可见;当再次回到原activity的时候,就会回调onResume方法了。
4
-
onPause:当前activity窗口失去焦点的时候,会调用此方法。调用后activity进入ON_PAUSE状态,并进入后台。
这个方法一般在另一个activity要进入前台前被调用。只有当前activity进入后台,其他的activity才能进入前台。所以,该方法不能做重量级的操作,不然则会引用界面切换卡顿。
一般的使用场景为界面进入后台时的轻量级资源释放。
最好理解这个状态就是弹出另一个activity的窗口的时候。因为前台activity只能有一个,所以当前可交互的activity变成另一个activity后,原activity就必须调用onPause方法进入ON_PAUSE状态;但是!!仍然是可见的,只是无法进行交互。这里也可以更好地体会前台可交互与可见性的区别。
5
-
onStop:当activity不可见的时候进行调用。调用后activity进入ON_STOP状态。
这里的不可见是严谨意义上的不可见。
当activity不可交互时会回调onPause方法并进入ON_PAUSE状态。但如果进入的是另一个全屏的activity而不是小窗口,那么当新的activity界面显示出来的时候,原Activity才会进入ON_STOP状态,并回调onStop方法。同时,activity第一创建的时候,界面是在onResume方法之后才显示出来,所以onStop方法会在新activity的onResume方法回调之后再被回调。
注意,被启动的activity并不会等待onStop执行完毕之后再显示。因而如果onStop方法里做一些比较耗时的操作也不会导致被启动的activity启动延迟。
onStop方法的目的就是做资源释放操作。因为是在另一个activity显示之后再被回调,所以这里可以做一些相对重量级的资源释放操作,如中断网络请求、断开数据库连接、释放相机资源等。
如果一个应用的全部activity都处于ON_STOP状态,那么这个应用是很有可能被系统杀死的。而如果一个ON_STOP状态的activity被系统回收的话,系统会保留该activity中view的相关信息到bundle中,下一次恢复的时候,可以在onCreate或者onRestoreInstanceState中进行恢复。
6
-
onRestart :当从另一个activity切回到该activity的时候会调用。调用该方法后会立即调用onStart方法,之后activity进入ON_START状态
这个方法一般在activity从ON_STOP状态被重新启动的时候会调用。执行该方法后会立即执行onStart方法,然后Activity进入ON_START状态,进入前台。
7
-
onDestroy:当activity被系统杀死或者调用finish方法之后,会回调该方法。调用该方法之后activity进入ON_DESTROY状态。
这个方法是activity在被销毁前回调的最后一个方法。我们需要在这个方法中释放所有的资源,防止造成内存泄漏问题。
回调该方法后的activity就等待被系统回收了。如果再次打开该activity需要从onCreate开始执行,重新创建activity。
2.3 其他生命周期回调
-
onStart:当Activity准备进入前台时会调用此方法。调用后Activity会进入ON_START状态。
前台并不意味着Activity可见,只是表示activity处于活跃状态
前台activity一般只有一个,所以这也意味着其他的activity都进入后台了。这里的前后台需要结合activity返回栈来理解
这个方法一般用于从别的activity切回来本activity的时候调用。
-
onResume:当Activity准备与用户交互的时候调用。调用之后Activity进入ON_RESUME状态。
这个方法一直被认为是activity一定可见,且准备好与用户交互的状态。但事实并不一直是这样。如果在onReume方法中弹出popupWindow你会收获一个异常:token is null,表示界面尚没有被添加到屏幕上。
但是,这种情况只出现在第一次启动activity的时候。当activity启动后decorview就已经拥有token了,再次在onReume方法中弹出popupWindow就不会出现问题了。
因此,在onResume调用的时候activity是否可见要区分是否是第一次创建activity。
onStart方法是后台与前台的区分,而这个方法是是否可交互的区分。使用场景最多是在当弹出别的activity的窗口时,原activity就会进入ON_PAUSE状态,但是仍然可见;当再次回到原activity的时候,就会回调onResume方法了。
-
onPause:当前activity窗口失去焦点的时候,会调用此方法。调用后activity进入ON_PAUSE状态,并进入后台。
这个方法一般在另一个activity要进入前台前被调用。只有当前activity进入后台,其他的activity才能进入前台。所以,该方法不能做重量级的操作,不然则会引用界面切换卡顿。
一般的使用场景为界面进入后台时的轻量级资源释放。
最好理解这个状态就是弹出另一个activity的窗口的时候。因为前台activity只能有一个,所以当前可交互的activity变成另一个activity后,原activity就必须调用onPause方法进入ON_PAUSE状态;但是!!仍然是可见的,只是无法进行交互。这里也可以更好地体会前台可交互与可见性的区别。
-
onStop:当activity不可见的时候进行调用。调用后activity进入ON_STOP状态。
这里的不可见是严谨意义上的不可见。
当activity不可交互时会回调onPause方法并进入ON_PAUSE状态。但如果进入的是另一个全屏的activity而不是小窗口,那么当新的activity界面显示出来的时候,原Activity才会进入ON_STOP状态,并回调onStop方法。同时,activity第一创建的时候,界面是在onResume方法之后才显示出来,所以onStop方法会在新activity的onResume方法回调之后再被回调。
注意,被启动的activity并不会等待onStop执行完毕之后再显示。因而如果onStop方法里做一些比较耗时的操作也不会导致被启动的activity启动延迟。
onStop方法的目的就是做资源释放操作。因为是在另一个activity显示之后再被回调,所以这里可以做一些相对重量级的资源释放操作,如中断网络请求、断开数据库连接、释放相机资源等。
如果一个应用的全部activity都处于ON_STOP状态,那么这个应用是很有可能被系统杀死的。而如果一个ON_STOP状态的activity被系统回收的话,系统会保留该activity中view的相关信息到bundle中,下一次恢复的时候,可以在onCreate或者onRestoreInstanceState中进行恢复。
-
onRestart :当从另一个activity切回到该activity的时候会调用。调用该方法后会立即调用onStart方法,之后activity进入ON_START状态
这个方法一般在activity从ON_STOP状态被重新启动的时候会调用。执行该方法后会立即执行onStart方法,然后Activity进入ON_START状态,进入前台。
-
onDestroy:当activity被系统杀死或者调用finish方法之后,会回调该方法。调用该方法之后activity进入ON_DESTROY状态。
这个方法是activity在被销毁前回调的最后一个方法。我们需要在这个方法中释放所有的资源,防止造成内存泄漏问题。
回调该方法后的activity就等待被系统回收了。如果再次打开该activity需要从onCreate开始执行,重新创建activity。
2.4场景生命周期流程
-
正常启动与结束 onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy
-
avctivity切换 Activity1:onPause Activity2:onCreate -> onStart -> onResume Activity1:onStop
当切换到另一个activity的时候,本activity会先调用onPause方法,进入后台;被启动的activity依次调用三个回调方法后准备与用户交互;这时原activity再调用onStop方法变得不可见,最后被启动的activity才会显示出来。
理解这个生命周期顺序只需要记住两个点:前后台、是否可见。onPause调用之后,activity会进入后台。而前台交互的activity只能有一个,所以原activity必须先进入后台后,目标activity才能启动并进入前台。onStop调用之后activity变得不可见,因而只有在目标activity即将要与用户交互的时候,需要进行显示了,原Activity才会调用onStop方法进入不可见状态。
当从Activity2回退到Activity1的时候,流程也是类似的,只是Activity1会在其他生命周期之前执行一次onRestart,跟前面的流程是类似的
-
屏幕旋转
当因资源配置改变时,activity会销毁重建,最常见的就是屏幕旋转。这个时候属于异常情况的Activity生命结束。因而,在销毁的时候,会调用onSaveInstanceState来保存数据,在重新创建新的activity的时候,会调用onRestoreInstanceState来恢复数据。
-
后台应用被系统杀死 onDestroy()
-
具有返回值的启动 onActivityResult -> OnRestart -> OnResume
-
重复启动 onPause -> onNewIntent -> onResume
2.4.1 从ActivityThread看生命周期
Activity的启动是受AMS调配的,那具体的调配方式是如何的呢?android的程序执行是使用handler机制来实现消息驱动型的。AMS想要控制Activity的生命周期,就必须不断地向主线程发送message;而程序想要执行AMS的命令,就必须handle这些message执行逻辑,两端配合,才能达到这种效率。
应用程序不止收到AMS的管理,同样的还有WMS、PMS等等系统服务。系统服务是运行在系统服务进程的,当系统服务需要控制应用程序的时候,会通过Binder跨进程通信把消息发送给应用程序。应用程序的Binder线程会通过handler把消息发送给主线程去执行。因而,从这里也可以看出,当应用程序刚被创建的时候,必须初始化的有主线程、binder线程、主线程handler、以及提前编写了命令的执行逻辑的类ActivityThread。
在android程序,肯定有一系列的逻辑,来分别执行来自AMS的“命令”。这就是ActivityThread中的一系列handlexxx方法.
handleLaunchActivity;
handleStartActivity;
handleResumeActivity;
handlePauseActivity;
handleStopActivity;
handleDestroyActivity;
2.4.2 解析onResume
handleResumeActivity肯定是在handleLaunchActivity和handleStartActivity之后被执行的。
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
...
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
...;
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
...
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}
...
}
performResumeActivity最终会执行onResume方法;activity.makeVisible();是真正让界面显示在屏幕个上的方法,我们看一下makeVisible()
void makeVisible() {
//如果尚未添加到屏幕上,那么会调用windowManager的addView方法来添加,之后,activity界面才真正显示在屏幕上
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
在看performResumeActivity中看哪里执行了onResume
public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
String reason) {
...
try {
...
if (r.pendingIntents != null) {
// 判断是否需要执行newIntent方法
deliverNewIntents(r, r.pendingIntents);
r.pendingIntents = null;
}
if (r.pendingResults != null) {
// 判断是否需要执行onActivityResult方法
deliverResults(r, r.pendingResults, reason);
r.pendingResults = null;
}
// 回调onResume方法
r.activity.performResume(r.startsNotResumed, reason);
r.state = null;
r.persistentState = null;
// 设置状态
r.setState(ON_RESUME);
reportTopResumedActivityChanged(r, r.isTopResumedActivity, "topWhenResuming");
}
...
}
这个方法的重点就是,先判断是否是需要执行onNewIntent或者onActivityResult的场景,如果没有则执行调用performResume方法,我们深入performResume看一下:
final void performResume(boolean followedByPause, String reason) {
dispatchActivityPreResumed();
//这个方法内部会判断是否需要执行onRestart方法和onStart方法,如果是从别的activity返回这里是肯定要执行的
performRestart(true /* start */, reason);
...
//使用Instrumentation来回调Activity的onResume方法。
mInstrumentation.callActivityOnResume(this);
...
onPostResume();
...
}
public void callActivityOnResume(Activity activity) {
activity.mResumed = true;
activity.onResume();
...
}
2.5 从系统设计看生命周期
要理解生命周期的设计,首先需要理解Activity本身。想一下,如果没有Activity,那么我们该如何编写程序?有没有忽然反应到,没有了activity,我们的程序竟无处下手?因为这涉及到Activity的一个最大的作用:Activity 类是 Android 应用的关键组件,而 Activity 的启动和组合方式则是该平台应用模型的基本组成部分。
写过c语言、java或者其他语言的课程设计,我们的程序入口就是main函数。从main函数开始,根据用户的输入来进入不同的功能模块,如更改信息模块、查阅模块等等。以功能模块为基本组成部分的应用模型是我们最初的程序设计模型。而android程序,我们会说这个程序有几个界面。我们更关注的是界面之间的跳转,而不是功能模块之间的跳转。我们在设计程序的时候,我们会说这个界面有什么功能,那个界面有什么功能,多个界面之间如何协调。对于用户来说,他们感知的也是一个个独立的界面。当我们通过通讯软件调用邮箱app的发送邮件界面时,我们喜欢看到的只是发送邮件的界面,而不需要看到收件箱、登录注册等界面。以功能模块为应用模型的设计从一个主功能模块入口,然后通过用户的输入去调用不同的功能模块。与其类似,android程序也有一个主界面,通过这个主界面,接受用户的操作去调用其他的界面。组成android程序的,是一个个的界面,而每一个界面,对应一个Activity。因此,Activity是android平台应用模型的基本组成成分。
那如何做到每个界面之间彼此解耦、各自的显示不发生混乱、界面之间的跳转有条不紊等等?这些工作,官方都帮我们做好了。Activity就是在这个设计思想下开发出来的。当我们在Activity上开发的时候,就已经沿用了他的这种设计思想。当我们开发一个app的时候,最开始要考虑的,是界面如何设计。设计好界面之后,就是考虑如何开发每个界面了。那我们如何自定义好每一个界面?如何根据我们的需求去设计每个界面的功能?Activity并没有main方法,我们的代码该写在哪里被执行?答案就是:生命周期回调方法。