Activity的生命周期和启动模式(基于《Android开发艺术探索》)

1.Activity的生命周期

 1.1 正常情况下的生命周期

  在正常情况下,Activity的生命周期有下面几个回调。

  (1) onCreate:表示Activity正在被创建。生命周期的第一个回调方法。

  (2) onRestart:表示Activity正在被重新启动。一般情况下,Activity从不可见状态重新变为可见状态时,onRestart就会被调用,这个一般是用户行为导致的。比如从一个应用切换到桌面或者重新打开了一个新的Activity,当前的Activity就会暂停,回调onPause和onStop,如果这时用户在onDestroy之前再次回到该Activity,系统就会回调onRestart。

  (3) onStart:表示Activity正在被启动,即将开始。这时Activity已经可见了,但还没有切换到前台,无法和用户进行交互

  (4) onResume:表示Activity已经可见了,并且出现到前台并开始活动,这时用户可以获取焦点以及进行交互。onStart和onResume都表示Activity已经可见,但是onStart的时候Activity还在后台,onResume的时候Activity才显示到前台。这里需要注意与onWindowFocusChanged的区别,onWindowFocusChanged独立于Acitivity生命周期,但我们的很多操作需要依赖于这个回调。具体场景见另一篇文章《onWindowFocusChange与Activity生命周期之间的关系》

  (5) onPause:表示Activity正在停止,正常情况下,紧接着onStop就会被调用。特殊情况下,在onResume已经回调,onStop还未被调用时返回到上一个Activity,则onResume会被调用。不过这属于特殊情况,用户操作很难复现到该场景。这时候可以做一些存储数据,停止动画等工作,但要注意不能太耗时,因为会影响到新Activity的显示。只有当onPause执行完之后,才会执行新启动Activity的onCreate

  (6) onStop:表示Activity即将停止,可以做一些稍微重量级的回收工作,但是同样不能太耗时。

  (7) onDestroy:表示Activity即将被销毁。这是Activity的最后一个生命周期,在这里,我们可以做一些回收工作和最终的资源释放。

  正常情况下,Activity的生命周期就只有上面7个,下图详细描述了Activity各种生命周期的切换过程。

Activity正常情况下生命周期流程图

下面是官方文档的Activity生命周期图

官方生命周期图


关于各种操作场景下生命周期方法的调用,参见《onWindowFocusChange与Activity生命周期之间的关系》。这里特别提出以下几个容易混淆的场景:

  • 使用当前Activity的context弹出的dialog,虽然部分覆盖了Activity的界面,使得当前Activity部分界面不可见,但Activity的onPause方法并不会被调用。因为这个dialog是使用该Activity的context创建的,所以对于Activity来说当前仍然处于前台可以交互的状态。

  • 弹出AlertDialog同样不会使Activity进入onPause状态。因为AlertDialog内部实现最终是直接使用WindowManager.addView()方法,并不会启动一个新的Activity。所以不会使当前Activity进入onPause状态。归根结底我们要弄清楚onPause方法的调用时机,官方文档是这样描述的:

When activity B is launched in front of activity A, this callback will be invoked on A. B will not be created until A’s {@link #onPause} returns, so be sure to not do anything lengthy here.
In situations where the system needs more memory it may kill paused processes to reclaim resources.

  • onStart和onResume,onPause和onStop,这两对从描述上来看差不多,应该如何区分何时使用呢?
    答:onStart和onResume被回调时,Activity都是可见的,他们之间的主要区别在于,Activity是否处于前台,用户是否可以获取view的焦点或者是否可以与Activity进行交互,其他方面区别不大。onPause和onStop则是区分Activity当前是否对用户可见,看下面官方注释:

onPause:

Called as part of the activity lifecycle when an activity is going intothe background, but has not (yet) been killed.

onStop:

Called when you are no longer visible to the user.

可以看到,onPause的时候Activity正要从前台切换到后台,但可能还是可见的,但onStop的时候就已经完全不可见了。

另外,还有一个非常重要的概念我们需要掌握:当从Activity A 切换到Activity B的时候,他们的生命周期调用过程如下:

A.onPause->B.onCreate->B.onStart->B.onResume->A.onStop

通过测试来验证一下上面的结论,代码如下:

MainActicity.java

package com.qiuqifan.myapplication;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";
    private Button button;

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

        button = findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
                MainActivity.this.startActivity(intent);
            }
        });
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "onPause: "+Util.getCurrTime());
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.e(TAG, "onStop: "+Util.getCurrTime());
    }
}

SecondActivity.java

package com.qiuqifan.myapplication;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

import org.jetbrains.annotations.Nullable;

public class SecondActivity extends Activity{

    private static final String TAG = "SecondActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e(TAG, "onCreate: "+Util.getCurrTime());
    }


    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "onStart: "+Util.getCurrTime());
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "onResume: "+Util.getCurrTime());
    }
}

Util.java

package com.qiuqifan.myapplication;

import java.text.SimpleDateFormat;
import java.util.Date;

public class Util {

    public static String getCurrTime(){
        long currTime = System.currentTimeMillis();
        Date date = new Date(currTime);
        return new SimpleDateFormat(" HH:mm:ss:SSS").format(date);
    }
}

测试结果如下:

01-18 19:14:44.291 23134-23134/com.qiuqifan.myapplication E/MainActivity: onPause:  19:14:44:305
01-18 19:14:44.351 23134-23134/com.qiuqifan.myapplication E/SecondActivity: onCreate:  19:14:44:358
01-18 19:14:44.361 23134-23134/com.qiuqifan.myapplication E/SecondActivity: onStart:  19:14:44:371
01-18 19:14:44.361 23134-23134/com.qiuqifan.myapplication E/SecondActivity: onResume:  19:14:44:371
01-18 19:14:44.701 23134-23134/com.qiuqifan.myapplication E/MainActivity: onStop:  19:14:44:714

可以看到,确实跟我们上面所说的生命周期跳转一致。

这里其实颠覆了我以前对Activity生命周期的理解。我以前一直认为生命周期的跳转应该是这样的:
  A.onPause->A.onStop->B.onCreate->B.onStart->B.onResume
实际上是这样的:

A.onPause->B.onCreate->B.onStart->B.onResume->A.onStop

至于为什么,只能从源码找答案了。具体分析可以看《startActivity源码分析,Activity启动流程探秘》

通过分析源码,我们知道了当启动一个新Activity的时候,必须先等旧的Activity执行完,然后才会执行新的Activity。这也是为什么官方强烈建议不要在onPause中进行一些耗时操作的原因:

When activity B is launched in front of activity A, this callback will be invoked on A. B will not be created until A’s {@link #onPause} returns, so be sure to not do anything lengthy here.

如果这样做,将会阻塞新Activity的弹出,造成卡顿的体验。

分析到这里,我又有了一个问题:Activity A的onStop方法一定在Activity B的onResume方法执行完以后才会执行吗?如果Activity B启动比较慢,Activity A的onStop方法会不会先于Activity B的onResume被回调?

让我们来做个实验测试一下。修改一下SecondActivity.java,在onCreate中加上一个500ms延时,模拟一些耗时操作,看看是什么结果。

SecondActivity.java

package com.qiuqifan.myapplication;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

import org.jetbrains.annotations.Nullable;

public class SecondActivity extends Activity{

    private static final String TAG = "SecondActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e(TAG, "onCreate: "+Util.getCurrTime());
        try {
            Thread.sleep(500);
            Log.e(TAG, "onCreate: sleep 500ms after onCreate"+Util.getCurrTime());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "onStart: "+Util.getCurrTime());
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "onResume: "+Util.getCurrTime());
    }
}

测试结果如下:

01-18 19:21:29.481 26299-26299/com.qiuqifan.myapplication E/MainActivity: onPause:  19:21:29:493
01-18 19:21:29.511 26299-26299/com.qiuqifan.myapplication E/SecondActivity: onCreate:  19:21:29:522
01-18 19:21:30.011 26299-26299/com.qiuqifan.myapplication E/SecondActivity: onCreate: sleep 500ms after onCreate 19:21:30:022
01-18 19:21:30.011 26299-26299/com.qiuqifan.myapplication E/SecondActivity: onStart:  19:21:30:023
01-18 19:21:30.011 26299-26299/com.qiuqifan.myapplication E/SecondActivity: onResume:  19:21:30:023
01-18 19:21:30.381 26299-26299/com.qiuqifan.myapplication E/MainActivity: onStop:  19:21:30:389

我们发现,Activity B的onCreate方法竟然会阻塞Activity A的onStop方法执行!
现在看来,上面那个问题的答案就很清晰了,的确在Activity B的onResume执行完以后才会回调Activity A的onStop方法。
其实,我们再去看看onStop的官方注释发现,人家写的很清楚:

Note that this method may never be called, in low memory situations where the system does not have enough memory to keep your activity’s process running after its onPause() method is called.

上面那段翻译下,大概意思就是:onStop可能永远也不会被调用,在onPause被调用后,系统有可能因为内存过低会把已经执行完onPause的Activity进程杀掉。

所以,总结一下,onPause一定会被回调,而onStop,onDestroy并不总是会被回调的,但一定注意不能在onPause中做耗时操作,因为这会阻塞新启动Activity的显示造成卡顿现象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值