Activity的生命周期

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Activity的生命周期相关的知识,希望对你有一定的参考价值。

在Activity生命周期中,系统调用App生命周期中设置的回调方法,这些生命周期回调方法在第一层就像一个金字塔。活动生命周期的每个阶段都对应于金字塔的一个步骤。
当系统创建一个新的Activity实例时,回调方法从塔的底部一级一级地移动到塔的顶部。当它位于金字塔的顶部时,活动位于用户的前台,此时用户可以与活动进行交互。当用户想要离开活动时,系统调用另一系列方法将活动的状态从顶部移到底部。在某些情况下,Activity只完成部分状态迁移并等待用户的指令,然后返回到塔顶。
根据活动的复杂性,您可能不必实现所有的生命周期方法。但是,理解每个生命周期回调函数的含义非常重要,以确保您的应用程序按照用户的期望正确运行。
要正确实现生命周期的回调方法,从而使应用程序正确动作,需要注意以下几点:
确保用户使用你时,应用程序可以接听电话或切换到其他应用程序,而不会崩溃。确保您的应用程序在用户不使用时不会消耗系统资源。
确保用户在从其他应用程序切换回您的应用程序时可以继续他们以前的工作,并且在切换用户屏幕或其他操作时不会崩溃或丢失用户数据。
参考技术A Activity 是android的四大组件之一。是用户操作的可视化界面;它为用户提供了一个完成操作指令的窗口。当我们创建完毕Activity之后,需要调用setContentView()方法来完成界面的显示;以此来为用户提供交互的入口。在Android App 中只要能看见的几乎都要依托于Activity,所以Activity是在开发中使用最频繁的一种组件。在这里作为新手总结了一下Activity的生命周期。

该方法在Activity被创建时调用,它是Activity的生命周期第一个调用方法,我们在创建Activity的时候一般都会重写此方法,并在该方法中执行一些初始化操作。

该方法在Activity重新被启动的时候执行,这时候Activity会从不可见变为可见状态,比较常见的情况是当前Activity 上面打开了一个新的Activity 然后关闭新的Activity 回到原来Activity的时候,便会重新启动Activity执行这个方法。

该方法表示此时Activity正在启动,但是还没有在前台显示,当该方法执行完成时,Activity已经启动可见,但是还不能与用户交互。

该方法被调用时,Activity已经可以跟用户进行交互,并且此时Activity已经显示在前台。

这个方法表示Activity正在停止,一般来说在onPause()执行之后会立刻回调onstop()方法。但是也有例外,这里举一个栗子,比如,Activity 去启动一个完全透明的Activity时,此时执行了onPause(),但是不会去执行onStart();该方法中一般不要执行比较耗时的操作。因为新的Activity的onResume()方法会在启动它的Activity 的OnPause()执行完成之后才会去执行。

这个方法在Activity完全不可见的时候调用。它和onPause()方法的主要区别在于,如果启动的新Activity是一个对话框式的activity,那么,onPause()方法会得到执行,而onStop()方法并不会执行。

 这个方法在Activity被销毁之前调用,之后Activity的状态将变为销毁状态。一般在这个方法中做一些资源释放的操作。

说到Activity的生命周期,我们首先想到的是Activity正常的生命周期,但是在非正常情况下Activity的生命周期又会有所不同,这里简单介绍两种情况。这里有一张经典的生命周期流程图。

在正常情况下,生命周期为:onCreate() >onStart()>onResume();

在正常情况下,生命周期为:onPause()>onStop()>onDestroy;

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

A onCreate()>A onStart()> A onResume() > A onPause()>B onCreate() >B onStart() >B onResume() > A onStop();

可以看到 当A的onPause()执行之后会立即开始B的生命周期运行,所以在onPause() 中执行耗时操作,会影响B 的启动速度。

简介:异常生命周期这里指的就是Activity非正常关闭时出现的生命周期,下面两种情况会出现:

1.旋转屏幕(资源相关的系统配置改变)

2.Activity被GC杀死回收

这里除了上面的生命周期外,还会有两个方法,Android 为了解决这种异常情况,专门有方法进行数据的保存和读取。

这个方法用来保存

这个方法用来读取

举个栗子:我们重写这两个方法

当我们横屏切换时 :

当然,我们经常使用的控件,例如Edittext,Android 已经帮我们做完了保存和回复,当我们界面中有Edittext的时候,填入数据,切换横屏,会发现Edittext中输入的数据并没有丢失。不过我们如果有列表,或者其他数据还是需要自己去完成保存,因为转屏时Activity销毁后 然后启动了。

首先了解一下Android用来管理Activity的栈。

Android是使用任务(Task)来管理Activity的,一个任务就是一组存放在栈里的Activity集合,被称为返回栈,栈是一种先进后出的数据结构。

常见的数据结构:先进先出-如队列,先进后出如栈

Activity处于活动状态,此时Activity处于栈顶,是可见状态,可与用户进行交互。 

当Activity失去焦点时,或被一个新的非全屏的Activity,或被一个透明的Activity放置在栈顶时,Activity就转化为Paused状态。但我们需要明白,此时Activity只是失去了与用户交互的能力,其所有的状态信息及其成员变量都还存在,只有在系统内存紧张的情况下,才有可能被系统回收掉。 

当一个Activity被另一个Activity完全覆盖时,被覆盖的Activity就会进入Stopped状态,此时它不再可见,但是跟Paused状态一样保持着其所有状态信息及其成员变量。 

当Activity被系统回收掉时,Activity就处于Killed状态。 

Activity会在以上四种形态中相互切换,至于如何切换,这因用户的操作不同而异。

该方法在Activity 获取焦点和失去焦点的时候会被调用,我们也可以认为是当Activity完全加载之后会调用该方法,而在activity 关闭时,在执行了onPause之后 会调用该方法,也就是onPause Activity失去焦点之后 不能与用户交互了。

如果之前你写过FrameAnimation你会发现,当我们在onCreate内start动画时,Activity启动了但并没有动画的效果,如果你将start放在onWindowFocusChanged内就会达到预期的效果了。这是因为在onCreate的时候Activity并没有获得焦点,而onWindowFocusChanged是在Activity获得焦点之后调用。

Activity生命周期的掌握,相信对每一位Android 开发人员都非常重要,能让我们在对应的生命周期中做适当的操作,Activity作为Android的四大控件之一,毋容置疑是必须掌握的。祝各位Android 开发者 技术越来越好,本人菜鸟,如果有什么写错的地方,欢迎大家指出。

本文参考了:

Activity生命周期全面总结

Android之Activity生命周期浅析(一)

Android技能树 — Activity小结    (写的超级棒)

彻底弄懂Activity四大启动模式

Activity的生命周期和启动模式

1.1 Activity 生命周期全面分析
Activity 生命周期分两部分:典型情况下生命周期,异常情况下生命周期( Activity 被系统回收或由于当前设备的 configuration 发生改变导致 Activity 被销毁重建)。
先上一张Activity生命周期图

1.1.1 典型情况下的生命周期分析

(1)onCreate(): Activity 正在被创建,我们可以在此方法中做一些初始化的操作。
(2)onStart(): Activity 正在被启动,Activity 可见但没有出现在前台。无法与用户进行交互。可以理解为已经显示出来了,但是我们看不到。
(3)onResume(): Activity 可见,且在前台显示,用户可以交互。
(4)onPause(): Activity 正在停止,可见。
(5)onStop(): Activity 即将停止,可做一些回收工作,不能太耗时。
(6)onRestart(): Activity 正在被重新启动,Activity 从不可见重新别为可见状态会调用该方法。
(7)onDestory(): Activity 即将被销毁,可做回收和资源的最终释放。
具体说明有如下几种情况:
(1)打开XxActivity,其生命周期:onCreate-onStart-onResume
(2)当在XxActivity中打开一个新的 Activity 或者切换到其他窗口或桌面时候,其生命周期回调:onPause - onStop(),但是如果新的 Activity 采用透明主题,那么XxActivity不会回调 onStop();
(3)当重新回到 XxActivity,回调如下:onReStart - onStart - onResume
(4)当点击 back 键回退时回调如下: onPause - onStop - onDestory
(5)当被系统回收掉再次打开是生命周期跟(1)一样,但是过程不一样
说明:1.onStart和onStop是从Activity是否可见这个角度来回调,而 onResume 和 onStop 则是从是否在前台角度来回调;2.当从A进入B页面是先执行A的 onPause 方法B的 onResume 方法才回执行,所以在官方文档中也提到在 onPause 方法中不要执行耗时的操作。3.Activity 启动过程简单描述:启动 Activity 请求由 Instrumentation 来处理,然后它通过 Binder 向 AMS 发请求, AMS 内部维护着一个 ActivityStack 并负责栈内 Activity 的状态的同步。AMS 通过 ActivityThread 去同步 Activity 的状态从而完成生命周期方法的调用(可查看源码去了解)。

1.1.2 异常情况下的生命周期分析

  1. 资源相关的系统配置发生改变导致 Activity 被杀死并重新创建
    典型的情况就是切换横竖屏幕导致 Activity 会被销毁并且重新创建。当然我们也可以阻止系统重新创建 Activity。在默认情况下(不做阻止特殊处理)其生命周期如下图所示:

    被销毁时,其 onPause onStop onDestroy 均会被调用,同时系统会在 onStop 方法之前调用 onSaveInstanceState 来保存当前 Activity 的状态,这个方法和 onPause 没有特定的时序关系。onSaveInstanceState 方法只会出现在 Activity 被异常终止的情况下。当 Activity 被重新创建后,系统会调用 onRestoreInstanceState (在onStart之前调用),并把 Activity 销毁时 onSaveInstanceState 方法所保存的Bundle对象作为参数同时传递给 onRestoreInstanceState 和 onCreate方法。同时在 onSaveInstanceState 和 onRestoreInstanceState 方法中,系统会做一定的恢复工作,当 Activity 需要重新创建时,系统会默认为保存当前的 Activity 的视图结构,并且在 Activity 重启后恢复这些数据。
    和 Activity 一样,每个 View 都有 onSaveInstanceState 和 onRestoreInstanceState 这两个方法,保存和恢复 View 层次结构的工作流程:Activity 被意外终止时,Activity 会调用 onSaveInstanceState 保存数据,然后委托 Window 去保存数据,Window 再委托它上面的顶级容器去保存数据,顶层容器再去一一通知其子元素来保存数据,这是一种委托的思想。

  2. 资源内存不足导致低优先级的 Activity 被杀死
    这种情况其数据存储和恢复过程跟上述完全一致,主要说一下 Activity 的优先级情况,从高到低可以分三种:1.前台 Activity -正在和用户交互的 Activity ,优先级最高;2.可见但非前台 Activity -比如 Activity 中弹出一个对话框;3.后台Activity-已经被暂停的 Activity,优先级最低。
    如果不想系统重新创建 Activity,可以给 Activity 指定 configChanges 这个属性;

android:configChanges="orientation|keyboardHidden|mnc|mcc|            locale|layoutDirection|screenLayout|fontScale|uiMode|touchscreen
|navigation|screenSize|smallestScreenSize|keyboard"

orientation:屏幕方向发生了改变
keyboardHidden:键盘的可访问性发生了改变
keyboard:键盘类型发生了改变,使用了外插键盘
mcc:SIM卡唯一标识IMSI中国家代码发生了改变
mnc:SIM卡唯一标识IMSI中运营商代码发生了改变
locale:设备的本地位置发生了改变,一般指切换了系统语言
layoutDirection:布局方向发生变化(API17新添加)
screenLayout:屏幕布局发生了变化,很有可能是用户激活了另外一个显示设备
fontScale:系统字体缩放比例发生了改变
uiMode:用户界面模式发生改变,比如开启了夜间模式(API8新添加)
touchscreen:触摸屏发生了改变
navigation:系统导航方式发生了改变,比如采用了轨迹球导航
screenSize:屏幕尺寸信息发生了改变,当旋转屏幕,屏幕尺寸会发生改变。跟编译选项有关,如果 minSdkVersion 和 targetSdkVersion 均低于13时,此选项不会导致 Activity 重启,否则会导致(API13新添加)
smallestScreenSize:设备的物理屏幕尺寸发生了改变,跟屏幕方向没有关系,比如切换到外部显示设备,其跟 screenSize 一样。

1.2 Activity 的启动模式
1.2.1 Activity的LaunchMode
Activity 有四种启动模式:standard sinleTop singleTask 和 singleInstance
(1) standard: 标准模式,也是系统默认模式。每次启动 Activity 都会重新创建一个新的实例。一个任务栈中可以有多个实例,一个实例也可以属于不同的任务栈。在这种模式下,谁启动了这个 Activity,那么这个 Activity 就运行在启动它的那个 Activity 所在的任务栈中。注意:用 ApplicationContext 去启动 standard 模式的 Activity 的时候会报错,因为非 Activity 类型的 Context 并没有所谓的任务栈。解决这个问题可以为待启动的 Activity 指定 FLAG_ACTIVITY_NEW_TASK 标记位。
(2) singleTop: 栈顶复用模式,如果新的 Activity 已经位于任务栈的栈顶,则不会创建新的实例。
(3) singleTask: 栈内复用模式,就是一种单实例模式,如果栈内存在,则不会去创建,和 singleTop 一样,系统会回调 onNewIntent。三种情况说明:1.任务栈是S1中为ABC,D以 singleTask 模式请求启动,其所需人物栈为S2,由于 S2和D的实例都不存在,所以系统会先创建任务栈S2,然后把创建D实例压入S2;2.假设D所需任务栈是S1,其他情况如上,则直接创建D实例压入S1;3.假设S1中为ADCB,由于singleTask默认具有 clearTop 的效果,所以S1最终结果会是AD。
(4). singleInstance:单实例模式,加强的 singleTask 模式,具备 singleTask 的一切特性,同时此模式的 Activity 只能单独位于一个任务栈中。

Activity 所需的任务栈,可以由 TaskAffinity 来指定,默认情况下,所有 Activity 所需的任务栈的名字为应用的包名,可以为 Activity 单独指定 TaskAffinity 属性,不能跟包名相同,否则相当于没指定。其值为字符串,且中间必须含有包名分隔符“.”。TaskAffinity 属性主要和 singleTask 启动模式或者 allowTaskReparenting属性配对使用,在其他情况下没有意义。

给 Activity 指定启动模式有两种方法:一是通过 AndroidMenifest 为 Activity 指定;一是代码中通过在 Intent 中设置标志位来为 Activity 指定启动模式。二者区别如下:1.第二种方式的优先级比第一种高,同时存在时,以第二种为主。2.限定范围不同,第一种无法直接为 Activity 设定 FLAG_ACTIVITY_CLEAR_TOP 标识,而第二种无法为 Activity 指定 singleInstance 模式。

1.2.2 Activity 的Flags
Activity 的 Flags 有很多,有的标记位可以设定启动模式,如 FLAG_ACTIVITY_NEW_TASK 和 FLAG_ACTIVITY_SINGLE_TOP等。还有标记位影响 Activity 的运行状态,如 FLAG_ACTIVITY_CLEAR_TOP 和 FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS等。主要以下几种:
FLAG_ACTIVITY_NEW_TASK 其作用是为 Activity指定“singleTask”启动模式。
FLAG_ACTIVITY_SINGLE_TOP 其作用是为 Activity指定“singleTop”启动模式。
FLAG_ACTIVITY_CLEAR_TOP 具备此标记的 Activity,在启动时会将同一个栈中位于它上面的 Activity都要出栈。这个标记一般跟 FLAG_ACTIVITY_NEW_TASK 配合使用。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 具备此标记的 Activity 不会出现在历史 Activity 的列表中。当不希望通过历史列表回到此 Activity 时候此标记有用。等同于XML中指定 Activity 的属性 android:excludeFromRecents=”true”

1.3 IntentFilter 的匹配原则
启动 Activity 分为两种:显式调用和隐式调用。显式调用需明确指出被启动对象的组件信息如包名和类名。原则上一个 Intent 不应该既是显式调用又是隐式调用,但如果二者共存,则以显式调用为主。隐式调用需要 Intent 能够匹配目标组件的 IntentFilter 中所设置的过滤信息(包括:action category data)。必须同时匹配过滤列表中的 action category data 信息,否则匹配失败。一个过滤列表中的action category data 可以多个。一个 Activity 可以有多个 intent-filter,一个 Intent 只要能够匹配任何一组 intent-filter 即可成功启动对应的 Activity。

  1. action 的匹配规则
    action 的匹配规则是 Intent 中 action 必须能够和过滤规则中的 action 匹配,这里说的匹配是指 action 的字符串值完全一样。一个过滤规则中可以有多个 action,那么只要 Intent 中的 action 能够和其中任何一个 action 相同即可匹配成功。action 区分大小写。
  2. category 的匹配规则
    要求如果 Intent 中如果含有 category,那所有的 category 都必须和过滤规则中的其中一个相同。不设置也可以匹配,因为系统在调用 startActivity 和 startActivityForResult 的时候会默认为 Intent 加上“android .intent.category.DEFAULT”
  3. data 的匹配规则
    data 的匹配原则和 action 类似,如果过滤规则中定义了 data,那么Intent 中必须也要定义可匹配的 data。
    data 由两部分组成,mimeType 和 URI。 mimeType 指媒体类型,比如 image/jpeg audio/mpeg4-generic 和 video/*等,而 URI 中包含的数据比较多。
    URI 结构如下:< scheme >://< host >:< port >/[< path > | < pathPrefix> | < pathPattern >]
    Scheme: URI 的模式,比如 http file content 等,必须指定
    Host: URI 的主机名,必须指定,否则 URI 无效。
    Port: 端口号,仅当制定了 Scheme 和 Host 参数时候 port 参数才有意义。
    Path pathPrefix pathPattern:这个三个参数表述路径信息,其中 path 表示完整的路径信息;pathPattern 也表示完整的路径信息,但它里面包含通配符“ * ”,“ * ” 表示0个或多个任意字符,需要注意的是由于正则表达式的规范,如果想表示真实的字符串,那么“ * ”要写成“\\*”,“\\”要写成“\\\\”;pathPrefix 表示路径的前缀信息。
    注意:如果要为 Intent 指定完整的 data,必须要调用 setDataAndType 方法,不能先调用 setData 再调用 setType,因为这两个方法彼此会消除对方的值。

IntentFilter的匹配规则对于 Service 和 BroadcastReceiver 也是同样的道理,不过系统对于 Service 的建议是尽量使用显式调用方式来启动服务。
最后当通过隐式方式启动一个 Activity 的时候,可以判断是否能够匹配隐式 Intent,判断方法有两种:1.采用 PackeageManager 的 resloveActivity(返回最佳匹配的Activity) 方法或者 Intent 的resloveActivity 方法,如果找不到匹配的 Activity 就会返回 null;2. PackeageManager 还提供了 queryIntentActivities 方法,这个方法跟 resloveActivity 不同是它返回所有成功匹配的Activity信息。针对 Service 和 BroadcastReceiver,PackeageManager 同样提供了类似的方法去获取成功匹配的组件信息。

以上是关于Activity的生命周期的主要内容,如果未能解决你的问题,请参考以下文章

Activity的生命周期及常见回调顺序

Activity与Fragment的生命周期详解

Activity的生命周期

Activity横竖屏切换生命周期变化

Android 的生命周期

Activity-运行状态及生命周期