Activity的四种启动模式与生命周期

一般情况下,Android中每个应用程序一开启就会创建一个任务栈,任务栈的ID是自增长的。最小化的时候,应用程序实际上是后台运行,任务栈是保留的。

  • Standard 标准启动模式:这种模式下每开启一个新的Activity,都会被放置在任务栈的栈顶,不存在复用
  • SingleTop 启动模式:这种模式下,如果栈顶已经存在了要开启的Activity,系统就不会重复创建了,而是利用这个已经存在的Activity,只复用栈顶的Activity
  • SingleTask 启动模式:这种模式下,它要求当前Activity只会在任务栈存在一个实例,如果要开启的 Activity已经在任务栈中,系统会直接复用这个已经存在的Activity,并清空这个 Activity上面所有的栈引用,复用所有已存在的Activity
  • SingleInstance 启动模式:这种模式下,系统会创建一个单独的任务栈,这个任务栈里只有它自己,并且在整个手机操作系统内存里,它是唯一的。比如打电话时的通话界面,全局唯一

然后是Activity的生命周期,被迫退出时的信息状态保存,返回键监听,Activity之间的数据传递等。

Activity的四种启动模式

Activity的四种启动模式:

1、Standard 标准启动模式

这种模式下每开启一个新的Activity,都会被放置在任务栈的栈顶,不存在复用。

2、SingleTop 启动模式

这种模式下,如果栈顶已经存在了要开启的Activity,系统就不会重复创建了,而是利用这个已经存在的Activity,只复用栈顶的Activity。

3、SingleTask 启动模式

这种模式下,它要求当前Activity只会在任务栈存在一个实例,如果要开启的 Activity已经在任务栈中,系统会直接复用这个已经存在的Activity,并清空这个 Activity上面所有的栈引用,复用所有已存在的Activity。

4、SingleInstance 启动模式

这种模式下,系统会创建一个单独的任务栈,这个任务栈里只有它自己,并且在整个手机操作系统内存里,它是唯一的。比如打电话时的通话界面,全局唯一。

Activity生命周期

Activity是Android组件中最基本也是最为常见用的四大组件之一,也是我们在开发过程之中接触最多的组件,所以了解Activity的生命周期,并正确的理解与应用,是必不可少的,下面就来介绍Activity生命周期。

Tips: AndroidStudio中通过logt可以快速生成TAG,logd、logv、logi、loge分别是打印不同级别日志的快捷键。

onCreate() :当Activity第一次创建时调用。该方法(如果有)会提供给你一个包含之前活动的冻结状态信息bundle包。

onStart():当Activity被展示在用户眼前时调用。如果活动出现在前台紧接着是onResume(),如果活动直接隐藏则紧接着是onStop()。

onResume():当Activity将开始与用户进行交互时调用。在这个时间点你的活动将会在活动堆栈的顶端,用户输入将会访问它。

onPause():当系统将要恢复一个之前的活动。这是一个有代表性的常常用于提交未被存储的改动信息为持久数据,停止动画和消耗CPU的东西等。实现该方法必须要特别的迅速,因为在此方法返回之前,下一个活动将不会恢复。如果活动将返回到前台则接下来调用onResume(),如果要隐藏到用户看不见的地方时,则调用onStop()。

onStop():当另一个活动被恢复且完全覆盖该活动,而该Activity将不在展示给用户时调用。这种情况将发生在一个新的活动将被开始,一个退出的活动将被恢复,又或者该活动将要被销毁。如果该活动将恢复与用户交互则调用onRestart(),如果该活动将被销毁则调用onDestory()。

onDestory():Activity被销毁钱最后一个被调用的方法。这个方法将会发生因为活动将会结束(在活动中调用finish()方法,或者系统临时销毁该实例节约空间。你可以使用isFinishing()方法区别这两种场景)。

从打开应用进入MainActivity再到返回键退出应用:

现在打开SecondActivity,那么MainActivity和SecondActivity的生命周期又是怎样的呢?

首先可以看到MainActivity进入暂停状态,然后SecondActivity进入初始化阶段(onCreate、onStart、onResume),SecondActivity完全展示在用户面前并且等待用户操作的时候,MainActivity才进入onStop()方法,所以即是Activity不再显示的时候才进行onStop。当返回MainActivity的时候,会执行onRestart() -> onStart() -> onResume()即途中最右边那一条路径,而SecondActivity先进入onPause,也是等MainActivity的onResme执行完成后才逐步销毁。

那么如果换成是DialogActivity呢?

可以看到,由于MainActivity并未完全被DialogActivity遮挡,所以并未进入onStop(),而是只进入了暂停状态(onPause),当退出DialogActivity后MainActivity直接执行onResume方法。所以当Activity未被完全遮挡会进入暂停状态,暂停恢复的时候,直接执行了onResume。

直接打开Dialog弹框跟Activity生命周期没关系,所以也就没有打印出任何关于Activity生命周期的Log。

系统退出Activity的状态保存

如果系统由于系统约束(而不是正常的应用程序行为,比如内存不足)而破坏了Activity,那么尽管实际 Activity实例已经消失,但是系统还是会记住它已经存在,这样如果用户导航回到它,系统会创建一个新的实例的Activity使用一组保存的数据来描述Activity在被销毁时的状态。系统用于恢复以前状态的已保存数据称为“实例状态”,是存储在Bundle对象中的键值对的集合。

在Activity中覆写如下方法,下面的例子就是程序异常退出的时候写入一个String键值对:

@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putString("name", "Tim");
    Log.i(TAG, "onSaveInstanceState: Success!");
}

因为onCreate()调用该方法是否系统正在创建一个新的Activity实例或重新创建一个以前的实例,所以您必须Bundle在尝试读取之前检查该状态是否为空。如果它为空,那么系统正在创建一个Activity的新实例,而不是恢复之前被销毁的实例:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Log.i(TAG, "onCreate: ");

    if(savedInstanceState != null){
        String name = savedInstanceState.getString("name");
        // TODO ...
    }
}

onBackPressed()

覆写onBackPressed可以监听用户按下返回键:

@Override
public void onBackPressed() {
    super.onBackPressed();
    Log.i(TAG, "onBackPressed: 用户按下返回键");
}

基于这个方法我们很容易实现用户按下返回键进行提示程序是否退出的功能:

@Override
public void onBackPressed() {
    //super.onBackPressed();
    Log.i(TAG, "onBackPressed: 用户按下返回键");
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("提示");
    builder.setMessage("确定退出程序吗?");
    builder.setPositiveButton("确定", (dialog, which) -> {
        super.onBackPressed();
    });
    builder.setNegativeButton("取消", null);
    builder.show();
}

Activity之间的数据传递

Intent传递基本数据

MainActivity中打开新的Activity的点击事件:

public void newActivity(View view) {
    Intent intent = new Intent(this, SecondActivity.class);
    intent.putExtra("appName", getString(R.string.app_name));
    intent.putExtra("strArray", new String[]{"A", "B", "C"});
    startActivity(intent);
}

SecondActivity中接收数据:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_second);
    Log.i(TAG, "onCreate: ");
    Intent intent = getIntent();
    String[] arrays = intent.getStringArrayExtra("strArray");
    String appName = intent.getStringExtra("appName");
    Log.i(TAG, "onCreate: arrays = " + Arrays.toString(arrays));
    Log.i(TAG, "onCreate: appName = " + appName);
}

Intent传递Bundle

MainActivity中打开新的Activity的点击事件:

public void newActivity(View view) {
    Intent intent = new Intent(this, SecondActivity.class);
    Bundle bundle = new Bundle();
    bundle.putString("appName", getString(R.string.app_name));
    bundle.putStringArray("strArray", new String[]{"A", "B", "C"});
    intent.putExtra("data", bundle);
    startActivity(intent);
}

SecondActivity中接收数据:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_second);
    Log.i(TAG, "onCreate: ");
    Intent intent = getIntent();
    Bundle bundle = intent.getBundleExtra("data");
    if (bundle != null) {
        String[] arrays = bundle.getStringArray("strArray");
        String appName = bundle.getString("appName");
        Log.i(TAG, "onCreate: arrays = " + Arrays.toString(arrays));
        Log.i(TAG, "onCreate: appName = " + appName);
    }
}

Intent传递对象

传递这样一个简单的对象:

public class User implements Serializable {
    public String name;
    public int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    
    // getter and setter..
}

MainActivity中打开新的Activity的点击事件:

public void newActivity(View view) {
    Intent intent = new Intent(this, SecondActivity.class);
    intent.putExtra("user", new User("Tim", 18));
    startActivity(intent);
}

SecondActivity中接收数据:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_second);
    Log.i(TAG, "onCreate: ");
    Intent intent = getIntent();
    Serializable user = intent.getSerializableExtra("user");
    Log.i(TAG, "onCreate: user = " + user);
}

Activity数据回传

上面的例子都是从MainActivity到SecondActivity,但是SecondActivity没有回传数据。下面演示一个Activity数据回传的例子:

首先按钮的点击事件写为:

public void newActivity(View view) {
    Intent intent = new Intent(this, SecondActivity.class);
    // 666是我自定义的请求码requestCode
    startActivityForResult(intent, 666);
}

同时需要在MainActivity中覆写onActivityResult()方法

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == 666 && resultCode == RESULT_OK){
        setTitle("SecondActivity成功返回");
        if (data != null) {
            Bundle resultData = data.getBundleExtra("resultData");
            String appName = resultData.getString("appName");
            Log.i(TAG, "onActivityResult: appName = " + appName);
        }
    }
}

在SecondActivity中,按钮的点击事件写为:(无非就是传数据 + 关闭当前Activity)

public void backMainActivity(View view) {
    Intent intent = new Intent();
    Bundle bundle = new Bundle();
    bundle.putString("appName", getString(R.string.app_name));
    intent.putExtra("resultData", bundle);
    setResult(RESULT_OK, intent);
    finish();
}