Android | Activity的生命周期

前言

Activity是Android系统的四大组件之一。作为Android系统的四大组件之首,Activity主要用来表示一个界面。通过Activity,用户可以看到精彩的内容并且可以和应用进行交互。当用户打开一个应用,将应用退到后台,回到应用,退出应用,这些操作会让应用里的Activity不断地切换状态。Android系统提供了一系列的回调方法来通知Activity的状态变化。Activity的每一个回调方法允许我们执行特定的工作,决定Activity的行为。只有熟悉这些Activity的生命周期回调方法,我们才能在不同的回调方法中执行最适合的工作,这样我们的代码才能更健壮,用户的体验才能更好。

Activity的状态

一般来说,Activity有以下4种状态:

  • 运行状态 当一个Activity位于屏幕的前台时,它处于运行/活动状态。用户只能和处于运行状态的Activity进行交互。
  • 暂停状态 当一个Activity失去屏幕焦点但是仍然可见时,比如有一个未完全遮盖它的或者透明的Activity在它之上时,它处于暂停状态。当系统处于极限低内存的情况下,暂停状态的Activity有可能被杀死。
  • 停止状态 当一个Activity被另一个Activity完全遮盖时,它处于停止状态。停止状态的Activity对用户不可见。当系统处于低内存的情况下,停止状态的Activity很有可能被杀死。
  • 销毁状态 当一个Activity被finish掉,或者它所在的进程被杀死时,它处于销毁状态。

Activity的生命周期

Activity类提供了一系列的生命周期回调方法:onCreate()、onRestart()、onStart()、onResume()、onPause()、onStop()、onDestroy()。当一个Activity进入到一个新状态时,系统就会回调相应的方法。具体可以看下面这张引用自Android官网的图:

Activity的生命周期.png

根据Activity的实际情况,你不需要实现所有的生命周期回调方法。但是,只有熟悉了这些回调方法,你才能写出更健壮的代码。下面我们来详细分析一下这些回调方法。

  • onCreate() 当Activity被创建时回调。接着系统会回调onStart()和onResume()方法。在onCreate()方法中,你应该执行那些在整个生命周期中只需要执行一次的初始化逻辑。比如,指定页面布局,绑定数据到列表,初始化后台线程,初始化全局变量等。

  • onRestart() 当Activity对用户不可见后重新回到前台时回调。接着系统会回调onStart()和onResume()方法。

  • onStart() 当Activity对用户可见时回调。Activity快速地执行完onStart()方法之后接着回调onResume()方法。在onStart()方法中,你可以做一些诸如注册广播接收器的事情。

  • onResume() 当Activity进入前台,可以和用户交互时回调。Activity会停留在这里,直到有让Activity失去焦点的事情发生。比如,有电话打入,用户打开另一个Activity,或者屏幕关闭等。

  • onPause() 当Activity失去屏幕焦点但是仍然可见时回调。比如有一个未完全遮盖它的或者透明的Activity在它之上时。

  • onStop() 当Activity对用户不可见时回调。比如有一个完全遮盖它的Activity在它之上时。如果你在onStart()方法中注册了广播接收器,那么在onStop()方法中要注销它。

  • onDestroy() 当Activity被finish掉,或者被系统销毁时回调。可以通过isFinishing()方法来区分这两种情况。

保存和恢复Activity的页面状态

当系统处于低内存的情况下,停止状态的Activity很有可能被杀死。当系统的Configuration发生变化,比如屏幕方向发生变化时,Activity会被销毁并立即重建。与Activity自己调用finish()方法结束自己不同,这两种情况下系统都会回调onSaveInstanceState()方法,在该方法中Activity可以以键值对的形式保存一些页面状态到Bundle对象中。

当Activity被重建时,我们可以从onCreate()或者onRestoreInstanceState()方法中获取到Bundle对象来恢复之前在onSaveInstanceState()方法中保存的页面状态。因为正常情况下创建一个Activity也会回调onCreate()方法,所以需要检查Bundle对象参数是否为null。

需要注意的是:在我们重写onSaveInstanceState()和onRestoreInstanceState()方法时一定要记得调用父类的onSaveInstanceState()和onRestoreInstanceState()方法。因为父类的onSaveInstanceState()方法默认保存了一些页面状态,比如页面布局视图层级的状态,而父类的onRestoreInstanceState()方法负责恢复这些状态。

总结

纵观Activity的整个生命周期,我们可以总结出Activity的3个生命期。

  • 完整生命期 完整生命期发生在Activity的onCreate()方法回调直到对应的onDestroy()方法回调。Activity应该在onCreate()方法中初始化各种状态,在onDestroy()方法中释放所有未释放的资源。
  • 可见生命期 可见生命期发生在Activity的onStart()方法回调直到对应的onStop()方法回调。在可见生命期中,用户可以看见Activity但是不能和Activity进行交互。
  • 前台生命期 前台生命期发生在Activity的onResume()方法回调到对应的onPause()方法回调。在前台生命期中,Activity处于屏幕前台可以同用户进行交互。通常Activity会频繁的在这两个方法之间切换,所以这两个方法的代码要尽量快速执行。

例子

这里提供两个例子来实践Activity的生命周期。例子代码地址:

https://github.com/chongyucaiyan/ActivityDemo

第一个例子主要用来实践正常情况下Activity的生命周期。代码里在Activity的每个生命周期回调方法中添加了日志打印。启动Lifecycle应用之后,点击demo01按钮进入demo01页面。使用Demo01Activity关键字过滤,启动Demo01Activity打印的日志如下图所示:

启动Demo01Activity的日志.png

可以看到Demo01Activity依次执行了onCreate()、onStart()和onResume()方法。此时Demo01Activity进入前台,可以和用户进行交互。Demo01Activity的页面布局如下图所示:

demo01页面.png

首先,我们看下Demo01Activity被不完全遮盖时的生命周期。点击Start DialogActivity按钮启动DialogActivity。如下图所示:

DialogActivity页面.png

DialogActivity设置了theme为Dialog,所以它不完全遮盖住Demo01Activity。此时打印的日志如下图所示:

启动DialogActivity的日志.png

可以看到Demo01Activity只执行了onPause()方法。接着我们点击空白处或者按下back键回到Demo01Activity。此时打印的日志如下图所示:

从DialogActivity回到Demo01Activity的日志.png

可以看到Demo01Activity只执行了onResume()方法,回到了前台。接着我们再按下back键退出Demo01Activity。此时打印的日志如下图所示:

退出Demo01Activity的日志.png

可以看到Demo01Activity依次执行了onPause()、onStop()和onDestroy()方法。

然后,我们看下Demo01Activity被完全遮盖时的生命周期。点击demo01按钮再次进入demo01页面,启动Demo01Activity的日志同上面,接着点击Start AnotherActivity按钮启动AnotherActivity。如下图所示:

AnotherActivity页面.png

AnotherActivity完全遮盖住Demo01Activity。此时打印的日志如下图所示:

启动AnotherActivity的日志.png

可以看到Demo01Activity执行了onPause方法和onStop()方法,不再可见。接着我们按下back键回到Demo01Activity。此时打印的日志如下图所示:

从AnotherActivity回到Demo01Activity的日志.png

可以看到Demo01Activity依次执行了onRestart()、onStart()和onResume()方法,回到了前台。接着我们再按下back键退出Demo01Activity。退出Demo01Activity的日志同上面。

最后,我们看下Demo01Activity显示对话框时的生命周期。点击demo01按钮再次进入demo01页面,启动Demo01Activity的日志同上面,接着点击Show Dialog按钮显示对话框。如下图所示:

Dialog页面.png

Dialog像DialogActivity一样不完全遮盖住Demo01Activity。此时打印的日志如下图所示:

启动Dialog的日志.png

可以看到Demo01Activity没有执行任何回调方法。接着我们按下back键回到Demo01Activity,会发现Demo01Activity仍然没有执行任何回调方法。所以我们可以得出结论,显示对话框是不会有Activity生命周期回调的。

通过这个例子我们可以更加深刻地理解正常情况下Activity的生命周期。我们可能还有一个疑问,启动一个新Activity时,新旧Activity的生命周期回调顺序是怎样的?我们可以实践一下,点击demo01按钮启动Demo01Activity,然后点击Start AnotherActivity按钮启动AnotherActivity。使用Activity关键字过滤打印的日志,如下图所示:

新旧Activity生命周期回调顺序的日志.png

可以看到启动一个新Activity时,系统会先回调旧Activity的onPause()方法。然后才启动新Activity,回调新Activity的onCreate()、onStart()和onResume()方法。当新Activity进入前台之后才回调旧Activity的onStop()方法。所以我们在onPause()方法中不能执行耗时的操作,否则会影响新Activity的启动。

第二个例子主要用来实践异常情况下Activity的生命周期。代码里在onSaveInstanceState()方法回调时保存了数据,然后当页面重建时,在onCreate()和onRestoreInstanceState()方法回调时都恢复了数据。关键代码如下所示:

private static final String KEY_STATE = "key_state";
private static final String STATE = "state";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_demo02);

    if (savedInstanceState == null) {
        Log.i(TAG, "onCreate()");
    } else {
        String data = savedInstanceState.getString(KEY_STATE);
        Log.i(TAG, "onCreate(), restore: " + data);
    }
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putString(KEY_STATE, STATE);
    Log.i(TAG, "onSaveInstanceState(), save: " + STATE);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    String data = savedInstanceState.getString(KEY_STATE);
    Log.i(TAG, "onRestoreInstanceState(), restore: " + data);
}

启动Lifecycle应用之后,点击demo02按钮进入demo02页面。如下图所示:

demo02页面.png

Demo02Activity进入前台,打印的日志如下图所示:

启动Demo02Activity的日志.png

然后旋转屏幕,系统会销毁Demo02Activity并立即重建页面。如下图所示:

demo02页面横屏.png

此时打印的日志如下图所示:

旋转Demo02Activity的日志.png

可以看到系统先调用onSaveInstanceState()方法来保存数据,然后销毁Activity,接着立即重建Activity。Activity重建时,在onCreate()和onRestoreInstanceState()方法中都正确地恢复了在onSaveInstanceState()方法中保存的数据。

参考

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值