重新认识Activity—Activity的生命周期

御弟哥哥 等级 319 0 0

Activity的生命周期概念

当用户浏览,退出和返回应用时,Activity实例会在其生命周期中转换为不同的状态。在生命周期回调方法中,可以声明用户离开并重新进入Activity时Activity的行为方式。每个回调允许执行适合于给定状态更改的特定工作。生命周期回调的良好实现可以帮助确保您的应用程序避免:

  • 如果用户在使用您的App时接到电话或切换到其他应用,则会崩溃;
  • 当用户不主动使用它时,消耗宝贵的系统资源;
  • 如果用户离开您的应用并稍后返回,则会丢失用户的进度;
  • 当屏幕在横向和纵向之间旋转时,会崩溃或丢失用户的进度。

重新认识Activity—Activity的生命周期

Activity的生命周期.png

Activity生命周期主要有7个回调方法。其中,
onCreate():创建Activity时回调执行的第一个方法,主要完成初始化操作,通过setContentView()加载布局,findViewById()绑定事件等,在整个生命周期中仅发生一次,是必须要重写的,而且第一行代码必须是调用父类的onCreate()方法,即:

super.onCreate(savedInstanceState); 

该方法中传递一个Bundle对象,主要保存的是Activity不正常销毁时的状态。
onStart():在Activity由不可见状态到可见状态时调用,表示Activity正在启动,主要工作是对资源加载。
onResume():此时Activity处于可见状态并且可以和用户交互,位于Activity栈的栈顶,表示Activity可以进行编辑,捕获所有用户的输入。
onPause():当Activity失去焦点,处于可见但不可编辑状态时调用,在这个方法中会将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动的使用。
onStop():当Activity不再对用户可见时调用,仅在后台运行,在这个方法中可以进行释放资源等操作。
onRestart():当处于“已停止”状态的Activity即将重新启动时调用。紧随其后调用onStart()onDestroy():当Activity被销毁时调用,通常实现释放资源、内存等操作。

整个Activity的生命周期分为四个状态:

  • 运行状态(running):当前显示在屏幕的Activity,用户可见状态,可以与用户进行交互,执行:onCreate()----->onStart()----->onResume();
  • 暂停状态(paused):用户依旧可见,但是失去焦点,不可编辑,无法与用户进行交互,执行:onPause();
  • 停止状态(stopped):用户看不到当前界面,完全被覆盖,无法与用户进行交互,处于后台中运行,执行:onStop();
  • 销毁状态(killed):当前界面被销毁,等待被系统回收,执行:onDestroy()。

注意:由于系统不足可能在暂停状态中直接被系统杀死会直接到销毁状态。

下面,我通过在Activity中重写上述7种回调方法,在每个方法中通过Log日志,具体看一下Activity的生命周期:

Activity的生命周期

  1. 启动MainActivity后:
![](https://img-hello-world.oss-cn-beijing.aliyuncs.com/5dd1af86ce815ae94c5969fc8cceba1a.png)

图1.png

onCreate()--->onStart()--->onResume()

  1. 点击Home键:
![](https://img-hello-world.oss-cn-beijing.aliyuncs.com/404ae98ffd0ee9c51aaa93b27520bedf.png)

图2.png

onPause()--->onStop()

  1. 再次进入MainActivity:
![](https://img-hello-world.oss-cn-beijing.aliyuncs.com/5c025beed9d5f829fc0a50824d3c34be.png)

图3.png

onRestart()--->onStart()--->onResume()

  1. 按返回键,退出MainActivity:
![](https://img-hello-world.oss-cn-beijing.aliyuncs.com/e5e1e07c77b03f3f6587ba64219bc9f5.png)

图4.png

onPause()--->onStop()--->onDestroy()

Activity横竖屏切换的生命周期

准备工作:确保系统设置是否锁屏,如果锁屏,取消锁屏设置。

  1. 启动MainActivity:
![](https://img-hello-world.oss-cn-beijing.aliyuncs.com/b043c8919dc80f425119afbf9b508180.png)

图5.png

onCreate()--->onStart()--->onResume()

  1. 转换屏幕:
![](https://img-hello-world.oss-cn-beijing.aliyuncs.com/3e5880814ee7fb3af42cdc9026efd2c8.png)

图6.png

onPause()--->onStop()--->onDestroy()
--->onCreate()--->onStart()--->onResume()

  1. 再次转换屏幕:
![](https://img-hello-world.oss-cn-beijing.aliyuncs.com/b70d7f0c04c181d9eeec8cad204af8cf.png)

图7.png

onPause()--->onStop()--->onDestroy()
--->onCreate()--->onStart()--->onResume()

  1. 退出Activity:
![](https://img-hello-world.oss-cn-beijing.aliyuncs.com/2648694c8db7cd78ba77b1aaed133fce.png)

图8.png

onPause()--->onStop()--->onDestroy()

如果我们的需求是竖屏或者横屏时,我们需要给Activity设置属性android:screenOrientation,属性值为portrait(竖屏)或者landscape(横屏)。

启动另一个Activity的生命周期

以MainActivity(A)启动NormalActivity(B)为例:

  1. 启动A:
![](https://img-hello-world.oss-cn-beijing.aliyuncs.com/848f7fae4c42a411f49ecef08d98bd9f.png)

图9.png

A:onCreate()--->onStart()--->onResume()

  1. A启动B:
![](https://img-hello-world.oss-cn-beijing.aliyuncs.com/de799a411d92bd9364eb94f617495f72.png)

图10.png

A:onPause()
B:onCreate()--->onStart()--->onResume()
A:onStop()

  1. 按返回键退出B,显示A:
![](https://img-hello-world.oss-cn-beijing.aliyuncs.com/a7c64e007da73fdf2c5ffaeafa42b8c9.png)

图11.png

B:onPause()
A:onRestart()--->onStart()--->onResume()
B:onStop()--->onDestroy()

退出A同一个Activity退出是一样的,这里就不再描述。

Activity启动Dialog样式的Activity的生命周期

首先要确认我们创建的Activity是dialog样式的,例如,我创建了一个DialogActivity,继承Activity,在配置文件中设置它的样式:

<activity
    android:name=".DialogActivity"
    android:theme="@android:style/Theme.Dialog">
</activity> 

这个时候,我们定义MainActivity(A),NormalActivity(C),
启动A,我就不再描述,直接看A启动C:

重新认识Activity—Activity的生命周期

图12.png

A:onPause()
C:onCreate()--->onStart()--->onResume()

退出C,显示A:

重新认识Activity—Activity的生命周期

图13.png

C:onPause()
A:onResume()
C:onStop()--->onDestroy()

退出A不再描述。

Activity启动Dialog或者PopupWindow的生命周期

在MainActivity中定义两个按钮,一个是弹出Dialog,一个弹出PopupWindow。发现,弹出dialog或者PopupWindow后,生命周期没有任何的变化;取消dialog或者PopupWindow后也没有任何变化。

总结:

  1. Dialog样式的Activity,虽然展示样式是Dialog,但是其本质是Activity;
  2. 弹出的Dialog,本质是Dialog;
  3. 弹出Dialog样式的Activity是会触发生命周期的回调方法的,但是Dialog和PopupWindow是不会触发生命周期的回调方法的。

非典型生命周期的状态保存

上述的生命周期图上,描述的是当Activity在暂停状态或者停止状态时,由于优先级较高的App内存不足,系统会将优先级较低的App销毁。这个时候,用户是不知道的,当用户再次打开发现原先的数据没有了,这样,就导致用户体验性不是很友好,所以,下面介绍两个方法:

  • onSaveInstanceState(Bundle outState):保存数据,Activity生命周期结束的时候,需要保存Activity状态的时候,会将要保存的数据以键值对的方式保存在Bundle对象中。

调用时机:
横竖屏切换时,会销毁当前Activity并重建;
按下Home键、电源键:Activity进入了后台,其中按下电源键屏幕会熄灭;
Activity被系统不正常销毁;
启动其他Activity,Activity被压入了返回栈的栈底等。

注意事项:
用户主动销毁Activity时不会调用:当用户调用finish()方法或者用户按下返回键时;
调用时机不确定:在onPause()之前或者之后,但是一定在onStop()之前;
布局中组件状态存储:每个组件都实现了该方法,在调用的时候,会自动保存组件的状态,但是只有有id的组件才会保存;
super.onSaveInstanceState(outState);该方法是默认实现组件保存状态的。

  • onRestoreInstanceState(Bundle savedInstanceState):Activity被不正常销毁再次恢复时被调用,通过Bundle对象中的键值对,获取保存的数据,组件的状态。Bundle对象也会传递到onCreate()方法中。如果系统没有销毁Activity,是不需要调用的。该方法会在onResume()方法之前回调。

下面我以横竖屏切换为例,看一下上述两个方法的实现:
我在Activity中实现这个回调方法,主要通过Log日志查看,具体代码:

 @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG,"MainActivity***onSaveInstanceState");
        String tempData = "Something you just typed";
        outState.putString("data_key",tempData);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG,"MainActivity***onRestoreInstanceState():" + savedInstanceState.getString("data_key"));
    } 

上面已经描述了Activity的生命周期,这次作对比看一下有什么不一样的地方。
启动MainActivity后查看Log日志:

重新认识Activity—Activity的生命周期

图14.png

onCreate()--->onStart()--->onResume()

我切换一下横竖屏:

重新认识Activity—Activity的生命周期

图15.png

此时,发现Activity在执行完onPause()方法后执行了onSaveInstanceState(),然后又执行了onStop()--->onDestroy()--->onCreate()--->onStart()--->onRestoreInstanceState()--->onResume()。
上面介绍onRestoreInstanceState()方法时已经说了Bundle对象也会传递到onCreate(Bundle savedInstanceState)中,下面是onCreate()方法中的部分代码:

if(savedInstanceState != null){
    String tempData = savedInstanceState.getString("data_key");
    Log.d(TAG,"MainActivity***onCreate:" + tempData);
} 

横竖屏切换后,通过Log日志查看:

重新认识Activity—Activity的生命周期

图16.png

通过上图,可以看到我们保存的数据在onCreate中也能获取到,前提是Activity被不正常销毁,再次恢复数据。

好了,以上就是我整理的关于Activity的生命周期的相关知识,如果有什么问题,大家可以积极留言,一起探讨!也请大家继续关注我的文章!

收藏
评论区

相关推荐

Android Activity生命周期,启动模式,启动过程详解
前言 接触过Android开发的同学都知道Activity,Activity作为Android四大组件之一,使用频率高。简单来说Activity提供了一个显示界面,让用户进行各种操作,本文主要分为以下三个部分:Activity的生命周期,启动模式,以及Activity的工作过程。文中大部分篇幅来自《Android开发艺术探索》一书,尽管想多以流程或图
Android中一个Activity关闭另一个Activity或者在一个Activity中关闭多个Activity
前言 最近项目中涉及需要在一个Activity中关闭另一个Activity或者在一个Activity中关闭多个Activity的需求,不涉及到应用的退出。自己首先想了一些方案,同时也查了一些方案,就各个方案比较下优劣。 方案一 广播的方式 这个是最容易想到的,同时也是网上提供最多的。 由于多个Activity要使用,关闭页面
Android通过URL打开Activity
关注公众号 QXF069 为每个 Activity 绑定一个 url 可以方便的让第三方 app 直接打开这些 Activity。也可以方便在 app 内部进行页面跳转,解耦。 背景 举一个常见的案例,假设我们有个产品 A,产品 A 包含 h5 网页端和客户端,当用户在手机打开我们的 h5 网页端的时候,我们会期望如果用户手机安装了我们的客户端,则直接打
重新认识Activity—Activity的生命周期
Activity的生命周期概念 当用户浏览,退出和返回应用时,Activity实例会在其生命周期中转换为不同的状态。在生命周期回调方法中,可以声明用户离开并重新进入Activity时Activity的行为方式。每个回调允许执行适合于给定状态更改的特定工作。生命周期回调的良好实现可以帮助确保您的应用程序避免: 如果用户在使用您的App时接到电话或切换
Android Fragment生命周期
Fragment 是在 Android 3.0 中引入,用于解决不同屏幕分辨率的设备上 UI 显示、交互的问题。Fragment 有自己的布局,有自己的生命周期,有自己的事件响应。 但 Fragment 又是依赖于 Activity 存在的,你可以把多个 Fragment 嵌入到一个 Activity 中或者多个 Activity 重用一个 Fragmen
Android开发 经验技巧汇总(基于Android Studio)(二)
1.复制Assets文件到手机SD卡 assets文件夹里面的文件都是保持原始的文件格式,需要用AssetManager以字节流的形式读取文件。 先在Activity里面调用getAssets() 来获取AssetManager引用; 再用AssetManager的open(String fileName, int accessMode) 方法则指定
基于Xposed自动化框架XposedAppium
基于Xposed做的一款自动化点击,滑动框架(基于安卓原生的事件分发)。可以模拟手指的一切操作,基于Xpath表达式获取View。此框架在virjar大佬的框架基础上进行的修改的,修复了部分Bug,添加常用方法等.在登入页面输入账号密码后,跳转到第二个Activity并点击对话框确定按钮。 Xposed模块:很简单,添加对应的Activity,需要实Page
创建圆角Dialog风格的Activity
一、前言:在开发中有时我们需要用到dialog,可是系统提供的dialog有时不能满足我们的要求,比如显示位置等,不够灵活,我们这时可以创建activity,使其风格和dialog一样。二、实现 1\. 1.创建样式在res/values/styles.xml中<style name"DialogActivityStyle"
数组越界导致系统重启的案例
一. 问题描述 引言一般数组越界问题, 往往是涉及多线程并发的情况下, 某个或多个临界资源(比如类或对象的成员变量)多线程并发读写而导致的异常。出现这样情况, 一般是该保护的地方没有用同步锁保护,或者是用错了同步锁,这类问题比较常规。但本文要分享的案例却是一个方法内的临界资源已被加锁保护的情况下仍然出现的数组越界问题, 导致system\server挂掉,手
如果一个Activity启动比较慢,需要优化,你觉得可以从哪些方面入手?
打开一个app的时候速度比较慢,等一会才能看到UI,有很多种原因,下面是我根据这些个情况做出的多种优化,记录 一下。1、采用动态布局:先是优化了布局,减少层级嵌套,使用merge优化等等。但发现加载xml布局还是慢了点,于是改为动态布局,布局的 时间减少了好几倍。2、利用MessageQueue.IdleHandler()回调 按照activity的生命周期
Android深入四大组件(一)应用程序启动过程(后篇)
Android框架层 Android深入四大组件categories: Android框架层本文首发于微信公众号「刘望舒」 1.ActivityManageService到ApplicationThread的调用流程AMS的startActivity方法中return了startActivityAsUser方法:<!moreframeworks/base/s
Android深入四大组件(七)Android8.0 根Activity启动过程(后篇)
Android框架层 Android深入四大组件categories: Android框架层本文首发于微信公众号「刘望舒」 前言在几个月前我写了和这两篇文章,它们都是基于Android 7.0,当我开始阅读Android 8.0源码时发现应用程序(根Activity)启动过程照Android 7.0有了一些变化,因此又写下了本篇文章,本篇文章照此前的文章不仅
Android解析ActivityManagerService(二)ActivityTask和Activity栈管理
Android框架层 Android系统服务 ActivityManagerService Android框架层本文首发于微信公众号「刘望舒」 前言关于AMS,原计划是只写一篇文章来介绍,但是AMS功能繁多,一篇文章的篇幅远远不够。这一篇我们接着来学习与AMS相关的ActivityTask和Activity栈管理。 1.ActivityStackActivi
IntentFilter匹配规则
1、Activity启动方式我们知道,启动Activity分为两种,显式调用和隐式调用。显式调用需要明确指定被启动对象的组件信息,包括包名和类名。隐式调用不需要指定组件信息,但需要匹配目标组件的IntentFilter中所设置的过滤信息。 2、IntentFilterIntentFilter中的过滤信息包括:action、category、data。为了匹配
这是一份用心整理的Android面试总结,涨姿势!
Android Jetpack组件的作用是什么? Navigation:一个用于管理Fragment切换的工具类,可视化、可绑定控件、支持动画等是其优点。 Data Binding:不用说,都知道,加速MVVM的创建。 Lifecycle:他是我们能够处理Activity和Fragment的生命周期的重要原因,在AndroidX的Fragment和Activ