Android视图手册之Activity生命周期

Android视图手册是本人希望通过结合图文的方式,基于Google官方文档对Android的各个基础知识进行清晰易懂的解释而整理的理论篇。内部尽量不用篇幅较长的代码进行解读,更多的希望通过图文流程的角度理解Android相关的知识,让读者能够容易看懂,容易理解和快速温习,是一本以理论为主的基础手册。
适用人员:初步接触Android理论 需要大致了解相关知识的新手;有几年开发经验需要快速回顾基本知识的老手。
在文中也会将一些面试题结合进来,做到知识自回答,巩固文章知识,方便需面试的同学快速回顾基础知识。

第一篇 Activity生命周期

万事开头难,有个和我长的很像的男人彭于晏曾说过,如果你给自己定了40分钟的计划,但你却只实现了其中的5分钟,这就是你的问题,因为你连自己都控制不了,怎么去影响外界,去改变自己人生的每个阶段。
Activity的生命周期正是我们应用四大组件中Activity的各个阶段过程,它让我们知道Activity在执行时的状态,以及我们应该在执行期间要做的事情。

概述

当用户浏览、退出和返回到应用时,应用中的 Activity 实例会在其生命周期的不同状态间转换。Activity 类会提供许多回调,这些回调会让 Activity 知晓某个状态已经更改:系统正在创建、停止或恢复某个 Activity,或者正在销毁该 Activity 所在的进程。通过生命周期,我们可以知晓Activity目前的进行状态,并进行相应的处理。

Activity生命周期图

生命周期图是许多入门Android的同学接触的第一张图,也是Android概念知识中比较重要的一张图,我这边将其各个阶段和大致的作用也在下图中进行描述出来。
在这里插入图片描述

Activity生命周期主要方法(主链路)

生命周期主要方法就是上图中间涉及各个生命状态的主链路,也是一个Activity最主要经历的一些方法调用的过程。

  • onCreate()
    在Activity首次被创建时会触发该方法,Activity 会在创建后进入“已创建”状态,在此方法中需要执行基本应用启动逻辑,该逻辑在 Activity 的整个生命周期中只应发生一次。其中我们可以进行layout布局资源的加载,也可以让一些网络数据在这里进行请求,因为是最开始的方法,所以尽量把用户进入所需要看见的所有东西(一般是资源)在这个方法中进行初始化,一些耗时操作可通过异步进行。

  • onStart()
    当 Activity 进入“已开始”状态时,系统会调用此回调。此方法调用使 Activity 对用户可见,因为应用会为 Activity 进入前台并支持互动做准备。应用通过此方法来初始化维护界面的代码。例如进行一些每次进入页面都需要进行界面的重置操作,比如进入页面才会进行的刷新操作,此处的刷新表示重新进入页面后进行的数据或界面刷新。

  • onResume()
    Activity 会在进入“已恢复”状态时来到前台,然后系统调用此方法 回调。这时,应用对用户可见和可交互的。应用会一直保持这种状态,直到某些事件发生,让焦点远离应用。此类事件包括接到来电、用户导航到另一个 Activity,或设备屏幕关闭。因为该方法在界面返回时也会被调用,所以当你想进行一些数据的刷新操作时,此方法是一个不错的选择。和在onStart()中的刷新不同的是,onResume多了一条onPause 到 onResume的链路(下一段会讲解该链路)。
    还有在一些特定情况的需求下,比如人脸识别需求下,在一些带有相机的界面我们有时候会主动的去调用onResume方法,使其不断执行去刷新我们截取的相机流内的数据,这时候onResumed的方法会被不断调用进而刷新我们截取的流数据。

  • onPause()
    系统将此方法视为用户将要离开您的 Activity 的第一个标志(尽管这并不总是意味着 Activity 会被销毁);此方法表示 Activity 不再位于前台(尽管在用户处于多窗口模式时 Activity 仍然可见),进入“已暂停”状态。到此方法你可以先暂停一些不在前台时无需运行的功能,用来释放一些资源,比如传感器,相机。一般来说,这些工作不能太耗时,如果是由于启动新的Activity而唤醒的该状态,那会影响到新Activity的显示,当前Activity的onPause必须执行完,新的Activity的onResume才会执行。

  • onStop()
    如果 Activity 不再对用户可见,说明其已进入**“已停止”状态**,因此系统将调用 此方法回调。例如,当新启动的 Activity 覆盖整个屏幕时,可能会发生这种情况。如果 Activity 已结束运行并即将终止,系统还可以调用 此方法。在此方法中,我们可以释放或调整在应用对用户不可见时的无用资源,例如暂停动画效果,或从精确位置更新切换到粗略位置更新。还应使用 onStop() 执行 CPU 相对密集的关闭操作。例如,如果无法找到更合适的时机来将信息保存到数据库,可以在此方法期间执行此操作。

  • onDestory()
    如果 Activity 即将结束,onDestroy() 是 Activity 收到的最后一个生命周期回调,表明该Activity即将被系统销毁,进入“已销毁”状态。当Activity处于停止状态(onStop)时就随处可能进入死亡状态,因为系统可能因内存不足而强行结束该Activity,当然我们也可以用finish()来主动销毁一个Activity使其执行立刻执行此方法准备销毁。可以在此方法来释放在Acitvity中产生的一些资源(如Service、BroadReceiver、Map等)。

生命周期其他链路

从图上我们会发现Acitvity的生命周期也有其他调用次序的可能,对此我从小到大的跨度一一了解这些链路是什么情况下可能触发和经历的。

  1. onPause 到 onResume
      当Activity经历了这一条链路,也表明其从失去焦点到恢复焦点,我们可以从失去焦点的情况出发,当我们点击多任务键进入多窗口模式时会触发,因为无论何时,都只有一个应用(窗口)可以拥有焦点,因此系统会暂停所有其他应用。或者有新的半透明 Activity(例如对话框)覆盖在Activity之上。只要 Activity 仍然部分可见就会失去该焦点,当返回原页面使Acitvity重新获取焦点时也会触发该方法。
  2. onStop onRestart 到 onStart
    一般在Acitvity不可见到返回页面可见时就会调用,只不过中见会再经历一个onRestart方法告诉你Activity被返回了,像此链路在进行其他页面的跳转,或者进入后台后返回时就会被触发。
    比如用户按下Home键切换到桌面或者打开了一个新的Activity,这时当前Activity会暂停,也就是onPause和onStop被调用,接着用户有回到了这个Activity,就会出现这种情况。
  3. onStop 到 onCreate
    当Activity 的状态和从内存中弹出, Activity 所在的进程被终止来释放内存,比如长时间在后台后返回页面或进行横竖屏切换,此时整个应用所在进程就会被释放,当然这不代表这个进程就不存在了,其应用标识和活动栈都会在后台以待恢复。稍微需要注意的是这里被杀死的不仅是这个Activity,而是整一个应用进程,会清除存储在 Activity 实例中的任何界面状态。所以如果我们在用户返回页面的时候需要考虑进行保存和恢复瞬时界面状态,关于这个行为,我也以其他博主的习惯称之为异常生命周期

Activity异常生命周期

当Activity 所在的进程被终止,比如页面内进行横竖屏切换时,而我们又需要在用户重新进入页面时将之前的页面内容和数据进行恢复时,就可以通过异常生命周期中的onSaveInstanceState和onRestoreInstanceState进行恢复。其中onSaveInstanceState可以将状态信息保存到实例状态 Bundle 中。此方法的默认实现保存有关 Activity 视图层次结构状态的瞬时信息,例如 EditText中的文本或 ListView 的滚动位置。我们可以通过重写该父类方法,在Activity被完全销毁前将需要存入的瞬时信息存入Bundle ,此后在Activity被重新创建后就可以通过OnCreate或onRestoreInstanceState中的Bundle将之前存入的值进行获取和恢复,其中OnCreate和onRestoreInstanceState中的Bundle并没有什么不同。

因为Activity可能被杀掉,所以线程中使用的变量和一些界面元素就会被回收,因此可以考虑采用Android的消息机制 (Handler)来处理多线程和界面交互的问题。

其中需要注意的是,只有当Activity 所在的进程被终止这种意外情况下异常生命周期才会被触发,否在一般是调用不到onSaveInstanceState和onRestoreInstanceState方法的。

在这里插入图片描述

Activity生命周期测试代码

可复制以下代码对生命周期进行验证和打印测试,实践方出真知。

public class MainActivity extends AppCompatActivity {
    
    
 
    /**
     * Activity创建时被调用
     * @param savedInstanceState
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.e("onCreate");
    }
 
    /**
     * Activity被异常终止后 在onStop方法前被调用
     * @param outState
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
    
    
        super.onSaveInstanceState(outState);
        Log.e("onSaveInstanceState is invoke!!!");
    }
 
    /**
     * Activity被异常终止后 在onCreate方法后被调用
     * @param savedInstanceState
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
    
    
        super.onRestoreInstanceState(savedInstanceState);
        Log.e("onRestoreInstanceState is invoke!!!");
    }
 
    /**
     * Activity从后台重新回到前台时被调用
     */
    @Override
    protected void onRestart() {
    
    
        super.onRestart();
        Log.e("onRestart is invoke!!!");
    }
 
    /**
     *Activity创建或者从后台重新回到前台时被调用
     */
    @Override
    protected void onStart() {
    
    
        super.onStart();
        Log.e("onStart is invoke!!!");
    }
 
 
    /**
     *Activity创建或者从被覆盖、后台重新回到前台时被调用
     */
    @Override
    protected void onResume() {
    
    
        super.onResume();
        Log.e("onResume is invoke!!!");
    }
 
    /**
     *  Activity被覆盖到下面或者锁屏时被调用
      */
    @Override
    protected void onPause() {
    
    
        super.onPause();
        Log.e("onPause is invoke!!!");
    }
 
    /**
     *退出当前Activity或者跳转到新Activity时被调用
     */
    @Override
    protected void onStop() {
    
    
        super.onStop();
        Log.e("onStop is invoke!!!");
    }
 
    /**
     *退出当前Activity前被调用,调用之后Activity就结束了
     */
    @Override
    protected void onDestroy() {
    
    
        super.onDestroy();
        Log.e("onDestroy is invoke!!!");
    }
}

小知识

1、可让横竖屏不使生命周期重建的方法?
刚刚文章中提到,如果进行页面内动态的横竖屏切换会触发生命周期的销毁重走,也就是异常生命周期的触发流程,不过从Android 3.2(API Level 13)开始,Google官方考虑到横竖屏使用场景的日益增加,我们在Activity的配置项中加入screenSize,即configChanges = orientation|screenSize就可以避免该情况的发生。如下配置:

	<activity
   	 	android:name="com.ftd.activity.ActivityXXX"
    	android:configChanges="orientation|keyboardHidden|screenSize"/>

而以Api13为划分点,处理情况如下:

  • 如果不手动配置Activity configChanges属性,系统默认对Activity进行销毁重建操作。
  • API13以下,Activity configChanges属性中含有orientation即可避免Activity销毁重建
  • API13及以上,Activity configChanges属性中同时含有orientation和screenSize即可避免Activity销毁重建。

2、onStart()的可见是指什么?
刚刚提到onStart()的调用表示对用户可见了,需要注意下其中的对用户可见不是指界面可见,表示的是Activity对用户可见,是Activity被创建出来了,被用户所知晓,但是不在前台,还没绘制界面,所以无法交互。也可以意指其所在的进程为可见进程
其中onStart到onResume这个阶段,Activity被创建,布局已加载,但界面其实还没有绘制,而是在执行onResume方法后才会通过handleResumeActivity方法将界面显示出来。如下为Activity启动过程中调用了的handleResumeActivity()方法,在此方法中调用了onResume方法和addView方法,完成了View的第一次绘制,并显示到界面上

	@Override
    public void handleResumeActivity() {
    
    
        //onResume 
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
        //addView 将view添加和显示
        if (r.window == null && !a.mFinished && willBeVisible) {
    
    
            wm.addView(decor, l);
        }
    }

可能遇到的相关问题

问题答案可参考下方回答,也可基于本文在下方回答的基础上进行适当扩充

1、了解生命周期吗? 请描述一下Activity的生命周期?
这两个问题,我们可以从这些角度出发讲解,生命周期是什么,有什么作用以及它生命周期中具体实现的方法有哪些,这些方法又是做什么用的?
可答:
  生命周期即Activity从开始到结束所经历的各种状态。从开始到结束所经历的各个状态。从一个状态到另一个状态的转变,从最开始启动到运行再到最后被关闭,这样一个过程中所经历的状态就叫做生命周期。(此处解释什么是生命周期,当然所有的生命周期其实都是状态的改变,可用此进行通用解释)
  通过Activity生命周期的回调方法,我们可以知道Activity各个阶段过程,它让我们知道Activity在执行时的状态,以及我们能够在这些状态方法执行期间去做对应的事情。(此处解释生命周期的作用)
  其中Activity的生命周期,往往会经历以下几个方法:
    onCreate:此时进入“已创建”状态,在这个方法中可以做一些初始化的工作(加载布局资源、初始化Activity所需要的数据等)。
    onStart:此时进入“已开始”状态,表示此时的Activity 对用户可见,并且即将开始。
    onResume:此时进入“已恢复”状态,表示Activity已经创建完成,并且可以开始活动了,这个时候用户已经可以看到界面了,这时,应用对用户可见和可交互的。(完成该周期之后便可以响应用户的交互事件了)。
    onPause:此时进入“已暂停”状态,表示Activity正在暂停,正常情况下,onStop接着就会被调用。在特殊情况下,如果这个时候用户快速地再回到当前的Activity,那么onResume会被调用(极端情况)。
    onStop:此时进入“已停止”状态,表示 Activity 不再位于前台,可以做一些稍微重量级的回收工作,同样也不能太耗时。
    onDestroy:此时进入“已销毁”状态,这是Activity生命周期的最后一个回调,我们可以做一些回收工作和最终的资源释放。

2、当两个 Activity 在同一个进程(应用)中,并且其中Activity A启动Activity B并返回时。两个Activity的生命周期方法顺序?
需要注意的是只有Activity A的onPause方法执行后,Activity B才相应开始创建,创建完成后且Activity A 在屏幕上不再显示时才会相继执行onStop() 方法,如果Activity B是透明dialog主题的Activity就不会执行。

以下是 Activity A 启动 Activity B 时的操作发生顺序:

  1. Activity A 的 onPause() 方法执行。
  2. Activity B 的 onCreate()、onStart() 和onResume() 方法依次执行(Activity B 现在具有用户焦点)。
  3. 然后,如果 Activity A 在屏幕上不再显示,其onStop() 方法执行。
  4. Activity B执行返回操作,同时进入onPause() 方法。
  5. 返回后Activity A执行onReStart(),onStart()和onResume() 方法
  6. 因为返回本身就是将此Activity退出栈,Activity B会进而执行onStop()和onDestory() 方法
    在这里插入图片描述

面试技巧之引申问题

通过恰当的引申问题,不但可以适当的扩展自己对问题的理解,同时也能够将自己的节奏带入到面试中,引导面试官接下来的提问路线,尽可能将问题优势偏向自己擅长的领域。此处仅为提示,实际情况各不相同,但也希望能给各位提供部分回答思路。
如对上面的第一个问题,我们可以将onStart中的可见结合本文的小知识例子引申到可见进程,一方面可表现你的基础较为扎实,另一方面可诱导面试官进一步提出进程的相关问题。或者扩充异常生命周期的知识,同时提及可用handler处理多线程和界面交互的问题来引导出多线程的相关问题等等。

猜你喜欢

转载自blog.csdn.net/number_cmd9/article/details/123412642