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

Activity的生命周期

1 android任务栈/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入栈出栈操作的:

返回栈

2 Activity状态

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

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

3 Activity的生存期

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生命周期的示意图,如图所示:

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的生命周期:

  1. 启动MainActivityonCreate->onStart->onResume
  2. 跳转到NormalActivityonPause->onStop
  startNormalActivity.setOnClickListener {
    val intent = Intent(this, NormalActivity::class.java)
    startActivity(intent)
  }
  1. NormalActivity中返回到MainActivityonRestart->onStart->onResume
  2. 点击返回,关闭MainActivityonPause -> onStop -> onDestory

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

AndroidManifest.xml中配置DialogActivity的主题:

<activity
     android:name=".DialogActivity"
     android:exported="true"
     android:theme="@style/Theme.AppCompat.Dialog" />
  1. 启动MainActivityonCreate->onStart->onResume
  2. 跳转到DialogActivityonPause
  3. 点击返回,关闭DialogActivityonResume
  4. 点击返回,关闭MainActivityonPause -> onStop -> onDestory

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

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

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

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

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

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

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

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

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

onRestoreInstanceState和onSavestanceState

以下是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"。系统配置中所含有的羡慕是非常多的,以下是每个项目的含义:

configChanges的项目和含义

从上图中可以知道,如果没有在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中从而保证进程有一定的优先级,这样就不会轻易的被系统杀死。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值