2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > Activity(二)—— Activity的生命周期

Activity(二)—— Activity的生命周期

时间:2021-09-24 03:36:05

相关推荐

Activity(二)—— Activity的生命周期

Activity的生命周期

1android任务栈/Task

Android中的Activity是可以层叠的。每启动一个新的Activity,就会覆盖在原Activity之上,然后点击Back键会销毁最上面的Activity,下面的Activity就会重新显示出来。

Android是使用任务(task)来管理Activity的,一个任务就是一组存放在栈里的Activity的集合,这个栈也被称作返回栈(back stack)。栈是一种后进先出的数据结构,在默认情况 下,每当我们启动了一个新的Activity,它就会在返回栈中入栈,并处于栈顶的位置。而每当我们按下Back键或调用finish()方法去销毁一个Activity时,处于栈顶的Activity就会出栈,前一个入栈的Activity就会重新处于栈顶的位置。系统总是会显示处于栈顶的Activity给用户。

在退出应用程序时,必须把所有的任务栈中所有的Activity清除出栈,任务栈才会被销毁。当然任务栈也可以移动到后台,并且保留了每一个Activity的状态,可以有序的给用户列出它们的任务,同时也不会丢失Activity的状态信息。

下图展示了返回栈是如何管理Activity入栈出栈操作的:

2Activity状态

每个Activity在其生命周期中最多可能会有4种状态。

运行状态:当一个Activity位于返回栈的栈顶时,Activity就处于运行状态。系统最不愿意回收的就是处于运行状态的Activity,因为这会带来非常差的用户体验。暂停状态:当一个Activity不再处于栈顶位置,但仍然可见时,Activity就进入了暂停状态。既然Activity已经不在栈顶了,怎么会可见呢?这是因为并不是每一个Activity都会占满整个屏幕,比如对话框形式的Activity只会占用屏幕中间的部分区域。处于暂停状态的Activity仍然是完全存活着的,系统也不愿意回收这种Activity(因为它还是可见的,回收可见的东西都会在用户体验方面有不好的影响),只有在内存极低的情况下,系统才会去考虑回收这种Activity停止状态:当一个Activity不再处于栈顶位置,并且完全不可见的时候,就进入了停止状态。系统仍然会为这种Activity保存相应的状态和成员变量,但是这并不是完全可靠的,当其他地方需要内存时,处于停止状态的Activity有可能会被系统回收。销毁状态:一个Activity从返回栈中移除后就变成了销毁状态。系统最倾向于回收处于这种状态的Activity,以保证手机的内存充足。

3Activity的生存期

Activity类中定义了7个回调方法,覆盖了Activity生命周期的每一个环节:

onCreate:表示Activity正在被创建,这是生命周期的第一个方法。在这个方法中,可以做一些初始化工作,比如调用setContentView去加载页面布局资源,初始化Activity所需数据等。onStart:表示Activity正在被启动,即将开始,这时Activity已经可见,但是还没有出现在前台,还无法和用户交互。这个时候其实可以理解为Activity已经显示出来了,但是我们还看不到。onResume:表示Activity已经可见,出现在前台并且开始活动。此时的Activity一定位于返回栈的栈顶,并且处于运行状态。onStartonResume都表示Activity已经可见,但是onStart的时候Activity还在后台,onResume的时候Activity才显示到前台。onPause:表示Activity正在停下,正常情况下,紧接着onStop就会被调用。在特殊情况下,如果这个时候快速的回到当前Activity,那么onResume会被调用,这种属于极端的情况,比较难出现。在此方法中,可以做一些存储数据、停止动画等工作,但是不能太耗时,因为会影响到新的Activity的显示,onPause必须先执行完,新的AcitivtyonResume才会执行。onStop:表示Activity即将停止,可以做一些稍微重量级的回收工作,同样不能太耗时。它和onPause()方法的主要区别在于,如果启动的新Activity是一个对话框式的Activity,那么onPause()方法会得到执行,而onStop()方法并不会执行。onDestory:表示Activity即将被销毁,这是Activity生命周期的最后一个回调,在这个方法中,可以做一些回收工作和最终的资源释放。onRestart:表示Activity正在重新启动。一般情况下,当当前的Activity从不可见重新变成可见状态时,onRestart就会被调用。这种情形一般时用户行为所致,比如用户按Home键切换到桌面或者用户打开了一个新的Activity,这个时候当前的Activity就会暂停,也就是onPauseonStop被执行了,该用户又回到这个Activity,就会出现这种情况。

Android官方提供了一张Activity生命周期的示意图,如图所示:

以上7个方法中除了onRestart()方法,其他都是两两相对的,从而又可以将Activity分为以 下3种生存期:

完整生存期:ActivityonCreate()方法和onDestroy()方法之间所经历的就是完整生存期。一般情况下,一个Activity会在onCreate()方法中完成各种初始化操作,而在onDestroy()方法中完成释放内存的操作。可见生存期:ActivityonStart()方法和onStop()方法之间所经历的就是可见生期。在可见生存期内,Activity对于用户总是可见的,即便有可能无法和用户进行交互。可以通过这两个方法合理地管理那些对用户可见的资源。比如在onStart()方法中对资源进行加载,而在onStop()方法中对资源进行释放,从而保证处于停止状态的Activity不会占用过多内存。前台生存期:ActivityonResume()方法和onPause()方法之间所经历的就是前台生存期。在前台生存期内,Activity总是处于运行状态,此时的Activity是可以和用户进行交互的,我们平时看到和接触最多的就是这个状态下的Activity

从整个生命周期来说,onCreateonDestory是配对的,分别标识着Activity的创建和销毁,并且只可能有一次调用;从Activity是否可见来说,onStartonStop是配对的,这两个方法可能被调用多次;从Activity是否在前台来说,onResumeonPause是配对的,这两个方法可能被调用多次。

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

情况1. 从某个普通的Activity——MainActivity,跳转到另一个普通的Activity——NormalActivityMainActivity的生命周期:

启动MainActivityonCreate->onStart->onResume跳转到NormalActivityonPause->onStop

startNormalActivity.setOnClickListener {val intent = Intent(this, NormalActivity::class.java)startActivity(intent)}

NormalActivity中返回到MainActivityonRestart->onStart->onResume点击返回,关闭MainActivityonPause -> onStop -> onDestory

情况2. 从某个普通的Activity——MainActivity,跳转到另一个对话框式的Activity——DialogActivity或透明主题的ActivityMainActivity的生命周期:

AndroidManifest.xml中配置DialogActivity的主题:

<activityandroid:name=".DialogActivity"android:exported="true"android:theme="@style/Theme.AppCompat.Dialog" />

启动MainActivityonCreate->onStart->onResume跳转到DialogActivityonPause点击返回,关闭DialogActivityonResume点击返回,关闭MainActivityonPause -> onStop -> onDestory

另外,如果Dialog是直接是通过WindowManager.addView显示的(没有经过AMS),是不会对生命周期有任何影响的。

情况3:假设当前为Activity A,如果这时用户打开一个新的Activity B,那么B.onResumeA.onPause哪个先执行

启动Activity AA.onCreate->A.onStart->A.onResume跳转到Activity BA.onPause -> B.onCreate -> B.onStart -> B.onResume -> A.onStop点击返回到Activity AB.onPause -> A.onRestart -> A.onStart -> A.onResume -> B.onStop -> B.onDesotry

情况4:点击Home键或者锁屏键,再次回到应用:

启动:onCreate->onStart->onResume点击Home键:onPause -> onStop回到应用:onRestart -> onStart -> onResume

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

异常情况下的生命周期是指Activity被系统回收或者由于当前设备的Configuration发生改变从而导致Activity被销毁重建。

5.1 资源相关的系统配置发生改变导致Activity被杀死并重新创建

系统的资源加载机制,比如说图片加载,一张图片放在drawable目录后,就可以通过Resource去获取这张图片,同时为了兼容不同的设备,可能还需要在其他一些目录下放置不同的图片,比如drawable-mdpidrawable-hdpidrawable-land等,这样,当应用程序启动时,系统就会根据当前设备的情况去加载合适的Resource资源,比如说横屏手机和竖屏手机会拿到两张不同的图片(设定了landscapeportrait状态下的图片)。比如说当前Activity处于竖屏状态,如果突然旋转屏幕,由于系统配置发生了改变,在默认情况下,Activity就会销毁并且重建,当然,也可以阻止系统重新创建Activity

在默认情况下,如果Activity不做特殊处理,那么当系统配置发生改变后,Activity就会被销毁并且重新创建,其生命周期如下所示:

当系统配置发生改变后,Activity会被销毁,其onPauseonStoponDestory均会被调用,同时,**由于Activity是在异常情况下终止的,系统会调用onSaveInstanceState来保存当前Activity的状态。**这个方法的调用时机是在onStop之前,它和onPause没有既定的时序关系,既可能在onPause之前调用,也可能在onPause之后调用。需要强调的一点是,这个方法只会出现在Activity被异常终止的情况下,正常情况下,系统不会回调这个方法。

Activity被重新创建后,系统会调用onRestoreInstanceState,并且把Activity销毁时onSaveInstanceState方法所保存的Bundle对象作为参数同时传递给onRestoreInstanceStateonCreate方法。因此,可以通过onRestoreInstanceStateonCreate方法来判断Activity是否被重建了,如果被重建了,那么就可以取出之前保存的数据并恢复,从时序上来说,onRestoreInstanceState的调用时机在onStart之后。

onSaveInstanceStateonRestoreInstanceState方法中,系统会自动做一定的恢复工作。当Activity在异常情况下需要重新创建时,系统会默认为我们保存当前Activity的视图结构,并且在Activity重启后会恢复这些数据,比如文本框中用户输入的数据、ListView滚动的位置等,这些View相关的状态系统都能够默认恢复。具体针对某一个特定的View系统能恢复哪些数据,可以查看View的源码,和Activity一样,每个View都有onSaveInstanceStateonRestoreInstanceState这两个方法。

关于保存和恢复View层次结构:首先Activity被意外终止时,Activity会调用onSaveInstanceState去保存数据,然后Activity会委托Window去保存数据,接着Window再委托它上面的顶级容器去保存数据。顶层容器是一个ViewGroup,一般来说他可能是DecorView。最后顶层容器再去一一通知它的子元素去保存数据,这样整个数据保存过程就完成了。这一种典型的委托思想,上层委托下层,父容器委托子元素去处理一件事情。

onRestoreInstanceStateonCreate的区别是:onSaveInstanceState不一定会被调用,因为它只有在Activity被回收了才会调用。onRestoreInstanceState一旦被调用,其参数Bundle savedInstanceState一定是有值的,不用额外的判断是否为空;但onCreate不行,onCreate如果是正常启动的话,其参数Bundle savedInstanceStatenull,所以必须采用额外的判断。这两个方法可以选择任意一个进行数据恢复,但是官方文档的建议是采用onRestoreInstanceState去恢复数据。

// MainActivity: onPause: // MainActivity: onSaveInstanceState: // MainActivity: onStop: // MainActivity: onDestroy:

Activity被销毁以后调用了onSaveIntanceState来保存数据,重新创建以后在onCreateonRestoreInstanceState种都能够正确地恢复之前存储的数据。**针对onSaveInstanceState方法还有一点需要说明,那就是系统只会在Activity即将被销毁并且有机会重新显示的情况下才会去调用它。当Activity正常销毁的时候,系统不会调用onSaveInstanceState,因为被销毁的Activity不可能再次被显示。**比如,对比一下旋转屏幕所造成的Activity异常销毁,这个过程和正常停止Activity是不一样的,因为旋转屏幕后,Activity被销毁的同时会立刻创建新的Activity实例,这个时候Activity有机会再次立刻展示,所以系统要进行数据存储。可以简单地理解成,系统只在Activity异常终止的时候才会调用onSaveInstanceStateonRestoreInstanceState来存储和恢复数据,其他情况不会触发这个过程。

onSaveInstanceStateonResoreInstanceState的相关流程:

以下是onSaveInstanceState的相关源码:

public final class ActivityThread {final void performStopActivity(IBinder token, boolean saveState, String reason) {ActivityClientRecord r = mActivities.get(token);performStopActivityInner(r, null, false, saveState, reason);}private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown, boolean saveState, String reason) {// One must first be paused before stopped...performPauseActivityIfNeeded(r, reason);// Next have the activity save its current state and managed dialogs...if (!r.activity.mFinished && saveState) {if (r.state == null) {callCallActivityOnSaveInstanceState(r);}}}private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {if (r.isPersistable()) {mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);}}}public class Instrumentation {public void callActivityOnSaveInstanceState(Activity activity, Bundle outState) {activity.performSaveInstanceState(outState);}public void callActivityOnSaveInstanceState(Activity activity, Bundle outState,PersistableBundle outPersistentState) {activity.performSaveInstanceState(outState, outPersistentState);}}public class Activity extends ContextThemeWrapper implements Window.Callback {final void performSaveInstanceState(Bundle outState) {onSaveInstanceState(outState);}final void performSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {onSaveInstanceState(outState, outPersistentState);saveManagedDialogs(outState);storeHasCurrentPermissionRequest(outState);}public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {onSaveInstanceState(outState);} }

以下时onResoreInstanceState的源码:

public final class ActivityThread {private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}if (!r.activity.mFinished) {activity.performStart();}if (!r.activity.mFinished) {if (r.isPersistable()) {if (r.state != null || r.persistentState != null) {mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, r.persistentState);}} else if (r.state != null) {mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);}}}}public class Instrumentation {public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) {activity.performRestoreInstanceState(savedInstanceState);}public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState,PersistableBundle persistentState) {activity.performRestoreInstanceState(savedInstanceState, persistentState);}}public class Activity extends ContextThemeWrapper implements Window.Callback {final void performRestoreInstanceState(Bundle savedInstanceState) {onRestoreInstanceState(savedInstanceState);restoreManagedDialogs(savedInstanceState);}final void performRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState) {onRestoreInstanceState(savedInstanceState, persistentState);if (savedInstanceState != null) {restoreManagedDialogs(savedInstanceState);}}}

onSaveInstanceState()的调用时机:

从当前Activity启动一个新的Activity时:onPause -> onSaveInstanceState -> onStop屏幕方向切换(论竖屏切横屏还是横屏切竖屏都会调用)时:onPause -> onSaveInstanceState -> onStop按下HOME键时:onPause -> onSaveInstanceState -> onStop按下电源按键(关闭屏幕显示)时:onPause -> onSaveInstanceState -> onStop从最近应用中选择运行其他的程序时:onPause -> onSaveInstanceState -> onStop

onRestoreInstanceState的调用时机:onRestoreInstanceState()只有在Activity确实是被系统回收,重新创建Activity的情况下才会被调用

屏幕方向切换时,Activity生命周期如下:onPause -> onSaveInstanceState -> onStop -> onDestroy -> onCreate -> onStart -> onRestoreInstanceState -> onResume被后台回收

HOME键返回桌面,又马上点击应用图标回到原来页面时不会被回收。

在一般情况下,横竖屏切换的完整生命周期:onCreate -> onStart ->onResume -> onPause -> onSaveInstanceState -> onStop -> onDestroy -> onCreate -> onStart -> onRestoreInstanceState -> onResume

当系统配置发生改变后,Activity会被重新创建,如果不想系统重新创建Activity,可以给Activity指定configChanges属性。比如不想让Activity在屏幕旋转的时候重新创建,就可以给configChanges属性添加orientation这个值:android:configChanges="orientation"

orientation [ˌɔːriənˈteɪʃn] 方向;定向;适应;情况介绍

如果想指定多个值,可以用|连接起来,比如android:configChanges="orientation|keyboardHidden"。系统配置中所含有的羡慕是非常多的,以下是每个项目的含义:

从上图中可以知道,如果没有在ActivityconfigChanges属性中指定该选项的话,当配置发生改变后就会导致Activity重新创建,常用的只有localeorientationkeyboardHidden这三个选项,其他很少使用。需要注意的是screenSizesmallestScreenSize,它们两个比较特殊,它们的行为和变异选项有关,但和运行环境无关。

不设置ActivityandroidconfigChanges,或设置ActivityandroidconfigChanges="orientation",或设置Activityandroid:configChanges="orientation|keyboardHidden",切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行一次。

配置android:configChanges="orientation|keyboardHidden|screenSize",才不会销毁Activity,且只调用onConfigurationChanged方法。

由上面的日志可见,Activity的确没有重新创建,并且没有调用onSaveInstanceStateonRestoreInstanceState来存储和恢复数据,取而代之的是系统调用了ActivityonConfigurationChanged方法,这个时候就可以做一下自己的特殊处理了。

5.2 资源内存不足导致低优先级的Activity被杀死

Activity按照优先级从高到低,可以分为以下3种情况:

前台Activity— 正在和用户交互的Activity,优先级最高可见但非前台Activity— 比如Activity中弹出一个对话框,导致Activity可见但是位于后台无法和用户直接交互后台Activity— 已经被暂停的Activity,比如执行了onStop,优先级最低

当系统内存不足时,系统会按照上述的优先级去杀死目标Activity所在的进程,并在后续通过onSaveInstanceStateonRestoreInstanceState来存储和恢复数据。如果一个进程中没有四大组件在执行,那么这个进程将很快被系统杀死,因此,一些后台工作不适合脱离四大组件而独立运行在后台中,这样进程很容易被杀死。比较好的方法是将后台工作放入Service中从而保证进程有一定的优先级,这样就不会轻易的被系统杀死。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。