关于Activity的生命周期

1.简介

2.生命周期

2.1 生命状态概述

Activity是一个很重要、很复杂的组件,他的启动不像我们平时直接new一个对象就完事了,他需要经历一系列的初始化。例如"刚创建状态",“后台状态”,“可见状态”等等。当我们在界面之间进行切换的时候,activity也会在多种状态之间进行切换,例如可见或者不可见状态、前台或者后台状态。当Activity在不同的状态之间切换时,会回调不同的生命周期方法。我们可以重写这一些方法,当进入不同的状态的时候,执行对应的逻辑

生命周期的一个重要作用就是让activity在不同状态之间切换的时候,可以执行对应的逻辑。我们在界面A使用了相机资源,当我们切换到下个界面B的时候,那么界面A就必须释放相机资源,这样才不会导致界面B无法使用相机;而当我们切回界面A的时候,又希望界面A继续保持拥有相机资源的状态;那么我们就需要在界面不可见的时候释放相机资源,而在界面恢复的时候再次获取相机资源。每个Activity一般情况下可以认为是一个界面或者说,一个屏幕。当我们在界面之间进行导航切换的时候,其实就是在切换Activity。当界面在不同状态之间进行切换的时候,也就是Activity状态的切换,就会回调activity相关的方法。例如当界面不可见的时候会回调onStop方法,恢复的时候会回调onReStart方法等。

2.2 主要生命周期

首先我们先看到最重要的七个生命周期,这七个生命周期是严格意义上的生命周期,他符合状态切换这个关键定义。

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方法,我们的代码该写在哪里被执行?答案就是:生命周期回调方法

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值