Android Activity生命周期的理解

时间:2023-01-26 09:06:32

注意:本文翻译自Google Android 官方文档。由于自己对Android Activity的生命周期的理解比较模糊,于是自己决定把官方文档看完理解,再用自己的话写出来。这篇翻译还存在很多不如意的地方,如各位有看法和建议,欢迎吐槽。Android 官方文档地址:http://developer.android.com/guide/components/activities.html。


通过实现 Activity 的回调方法来管理 Activity 的生命周期,这对构建一个健壮灵活的 App 至关重要。一个 Activity 的生命周期会受到与它关联的其他 Activity 、它的 task 以及 back stack 影响。

一个Activity只会存在于一下三种状态:

Resumed

处于这个状态下的Activity A处于屏幕的最前端,并获取的用户的焦点。(这个状态有时也可以叫做“running”。)

Paused

另一个Activity B现在处于屏幕的最前端同时也获取了焦点,同时Activity A还可见。也就是说,Activity B现在可见并处于Activity A的上方。所以Activity B是的部分透明或者没有覆盖到整个屏幕。此时我们便可以称Activity A的状态为Paused。处于paused状态的Activity是属于活动的(即这个Activity现在还在内存中,它还保存着Activity的状态信息和成员信息,同时还依附在window manager上面),但当系统内存紧张时可能会被kill掉。

Stopped

处于Stopped状态的Activity A已经完全被新的Activity B的覆盖了(现在Activity A位于后台)。处于Stopped状态的Activity是属于活动的(即这个Activity现在还在内存中,它还保存着Activity的状态信息和成员信息,但是与处于Paused状态的Activity不同时是,处于Stopped状态的Activity已经没有依附在window manager上面了),但已经完全不可见了。当其他App需要内存时处于Stopped状态的Activity会被系统kill掉。

如果一个Activity处于PausedStopped状态时,系统会通过请求Activity本身(调用它自己的finish()方法)或者kill掉它的进程将它从内存中清除掉。之后,当Activity(被系统从内存中清除掉之后)被重新打开,Activity会从头开始创建。

实现Activity的生命周期回调函数

当一个Activity在上面提出的三种状态中转换时,它会调用对于的回调函数。这些回调函数与Activity的状态转换相关联,当你的Activity状态更改时,你可以通过重写这些函数来完成相关工作。下面的代码包含基本的生命周期函数:

public class ExampleActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Activity 在被创建中。
}
@Override
protected void onStart() {
super.onStart();
// Activity将要可见。
}
@Override
protected void onResume() {
super.onResume();
// Activity变成可见 (现在的状态时 "resumed").
}
@Override
protected void onPause() {
super.onPause();
// 另一个Activity获取了用户的交互焦点 (Activity将要处于"paused"状态).
}
@Override
protected void onStop() {
super.onStop();
// Activity不开可见 (现在是 "stopped"状态)
}
@Override
protected void onDestroy() {
super.onDestroy();
// Activity将要被 destroyed。
}
}


注意: 在实现这些回调函数时,你必须先要调用超类的方法,然后再实现自己的一些代码。系统本身需要通过这些超类完成一些准备工作。

总之,这些方法定义了一个Activity整个生命周期。通过实现这些方法,你可以在Activity的生命周期里监测3个内置的循环:

  •  Activity的entire lifetime 出现在调用 onCreate()和调用 onDestroy()之间的这段时间。 你的Activity应该在 onCreate()里面定义全局状态(比如定义Activity的布局),然后在onDestroy() 里面释放app保留的系统资源。例如,你的Activity在后台运行一个线程从网上下载数据,那么你就就可能需要在  onCreate() 里面初始化线程,在 onDestroy()里面停掉线程。
  •  Activity的 visible lifetime 出现在调用 onStart() 和调用 onStop()之间的这段时间。在这段时间里,用户可以看到Activity已经出现在屏幕上并且可以进行交互。例如,onStop() 在一个新的Activity启动时被调用,之前的Activity就不再可见。在这两个方法之间,你可以维系需要展示给用户的系统资源。比如,你可以在onStart() 里注册一个 BroadcastReceiver 用来监测那些对你UI有影响的动静,然后在onStop() 里释放掉,因为此时用户已经看不到这个Activity的界面显示了。在 visible lifetime 里面,系统可能多次调用 onStart() 和 onStop() ,因为Activity可能会多次出现然后又被覆盖掉了。
  • Activity的 foreground lifetime 出现在调用 onResume() 和调用 onPause(). 在这段时间里,处于当前屏幕最顶端的Activity拥有用户的输入焦点。一个Activity可能经常进入或跳出屏幕的前台。比如,当手机今日休眠或者一个dialog出现的时候,  onPause()就会被调用。因为出于这个状态时会经常转化,所以处于这两个方法中的代码应该相当轻量级,这样可以避免用户在界面转换时等待时间过长。

1 指明了这些循环以及一个Activity在这些状态中转换时可能走的路径。长方形代表回调函数。

1. Activity生命周期图.

同时表1也将生命周期里面的回调方法列举出来了。每个方法都进行了更详细的描述,同时还包含了在调用这些回调方法后,Activity是否能被系统kill掉的描述。

1. Activity生命周期回调方法总结.


方法名

方法描述

Killable after?

下一个方法

onCreate()

Activity第一次被创建的时候调用。你应该在这个方法里面做一些常见的静态初始化——创建视图,绑定数据等等。这个方法会被系统传一个包含Activity之前的状态信息的 Bundle 对象(前提是这个状态之前被保存了)。在它之后运行的方法就是 onStart()

No

onStart()

 

onRestart()

Activitystop了之后调用,在Activity start之前调用,接着它运行的方法是 onStart()

No

onStart()

onStart()

Activity对用户可见之前调用。如果这个Activity进入最前台,那么接着调用 onResume() 方法,如果Activity又被隐藏了,那么调用 onStop() 方法。

No

onResume()
or
onStop()

 

onResume()

Activity可以开始和用户进行交互的时候调用。此时,Activity处于Activity栈的顶端。用户可以对Activity进行输入。在它之后运行的是 onPause()方法

No

onPause()

onPause()

当系统启动其他Activity的时候会调用这个方法。这个方法一般用来将没有保存的更改提交到持久化的对象,停止动画以及其他消耗CPU的操作。而且这个方法里面的操作应该尽可能的快,因为下一个Activity只有在上个Activity处理完onPause()方法里面的事情时候才会出现。如果Activity重新回到前台,那么在它之后的方法是 onResume() ,如果Activity对用户不可见了,那么在它之后的方法是 onStop() 

Yes

onResume()
or
onStop()

onStop()

Activity对用户不可见时调用此方法。当Activitydestroy或者另一个Activity已经跑到前台而且完全覆盖了它的时候会激发这个方法的调用。如果Activity重新回到前台和用户进行交互,那么在它之后的方法是 onRestart() ,如果Activity消失了,那么在它之后的方法是 byonDestroy() 

Yes

onRestart()
or
onDestroy()

onDestroy()

Activitydestroy前会调用这个方法。这是Activity最后调用的防范。在Activity即将被结束(有人调用了 finish() )或者系统了腾出内存空间临时destroy这个Activity的时候,这个方法就会被调用。这两个场景你可以通过 isFinishing() 方法来判断。

Yes

nothing

第三列(Killable after)标示了此方法调用返回后,不再执行Activity接下来的代码,系统是否可以kill包含这个Activity的进程。有三个方法被注明 "yes":(onPause()onStop(), onDestroy()).因为 onPause() 是这三个方法中的第一个,一旦Activity被创建, onPause() 方法是在Activity对于的进程被kill掉之前保证会被调用的最后一个方法——如果系统需要紧急增加可用内存,那么 onStop()  onDestroy() 可能不会被调用。因此,你应该使用 onPause() 来保存关键数据(比如用户的编辑)然而,你应该选择性的在 onPause() 里面保存这些数据因为这个方法的任何阻塞都会影响跳转至下一个Activity的转换,延长了用户的等待。

而后面标示 "No" 对应的方法从它们被调用开始起就会保护加载这个Activity的进程不让系统kill。因此,当Activity处于 onPause() 返回到 onResume() 方法被调用这段时间是可以被系统kill的。然后,当Activity onPause() 再次被调用返回时,它又可以被系统kill了。

注意: 一个Activity可不可以被kill不是按照表1里面定义那样,它还可能被系统kill——但这种情况只发生在极端的环境下(没有可用的资源)。

保存Activity状态

上面有提到当一个Activity处于Paused或者Stopped时,它的状态会被保存下来。因为此时的Activity仍然处于内存当中,关于它的状态和成员信息都是被储存下来了。因为保存这些用户的更改可以让Activity再次回到前台时保持原来的样子。

然而,当系统为了增加可用内存destroy一个Activity时,这个Activity对象就被destroy掉了,系统不能简单的恢复它的完整状态。这时如果用户进行了返回导航操作,系统会重新创建这个Activity对象。但是,用户是不知道系统已经destroy了这个Activity然后再重新创建了它。而且,用户还以为这个Activity会是之前的那个样子。在这种情况下,你就可以使用onSaveInstanceState() 来保存Activity重要的状态信息。

系统在destroy的时候会调用 onSaveInstanceState() 。系统向这个方法传入了一个 Bundle (你可以使用 putString() and putInt() 之类的防范Activity状态信息以键值对的形式保存到这个Bundle里面)。这时如果系统kill了你的app进程同时用户又重新返回到这个Activity,那么系统会重新创建这个Activity并把这个 Bundle 传入到 onCreate()  onRestoreInstanceState()方法。使用这两个方法中的一个便可以从 Bundle 中提取出之前保存的Activity状态信息 ,然后恢复整个Activity。如果这个Activity没有状态信息需要保存,那么传给 onCreate()  onRestoreInstanceState() Bundle为空 (Activity第一次被创建的时候就是这种情况).

2. 上图说明两种Activity重新获取用户交互焦点时返回的状态信息的方式:要么是Activitydestroy了,然后重新创建,此时这个Activity一定会恢复之前保存的状态信息;或者Activitystop了,然后再resume的时候Activity会恢复之前保存的状态信息。

注意: There's no guarantee that onSaveInstanceState() 方法在Activitydestroy之前并不一定会被调用,因为碰到有些情况就不会了(比如用户使用返回按钮跳出Activity,这表明用户明确要关掉这个Activity)。如果系统调用 onSaveInstanceState()的话, 它一般在  onStop() 之前,可能也会在 onPause()方法之前调用。

有趣的是,即使你不去实现 onSaveInstanceState()Activity的一些状态信息还是会被Activity类里面一些默认实现保存。Activity类里面这些默认实现会为布局里面的每一个视图去调用相关的 onSaveInstanceState() ,这为让每一个视图保存它的重要信息提供了方便。基本上Android framework里面的所有视图都相应的实现了这个方法,比如所有对UI可见的更改都会自动保存,在Activity被重新创建的时候恢复这些更改。  EditText 会保存用户任何已经输入的文本, CheckBox 会保存它是否被勾选。如果想让系统自动做到这些,你唯一要做的就是为这些控件提供一个唯一的ID(即设置控件的 android:id 属性)。对于那些没有设置ID的控件,系统是不会自动保存它的状态的。

如果你设置了控件的ID,但你不想让系统自动保存它的状态,你可以通过设置 android:saveEnabled 属性值为  "false" 或者调用 setSaveEnabled() 方法。

尽管 onSaveInstanceState() 的默认实现能够保存ActivityUI信息,但是你可能仍然需要重写它来完成一些特定的任务。比如,你可能需要保存在Activity生命周期中成员变量的改变(这可能和保存在UI里面的某些属性值相关,但是系统默认是不会保存这些成员变量的)。

因为 onSaveInstanceState() 默认的实现能够帮助系统保存 UI 的状态,如果你为了一些特定的需求重写这个方法,你应该首先调用超类关于 onSaveInstanceState() 的实现,然后在完成你自己的需求。同理,当你重写 onRestoreInstanceState() 方法是,需要先调用超类的 onRestoreInstanceState() 方法,保证默认的实现恢复视图的状态。

注意: 因为 onSaveInstanceState() 方法不保证一定被执行,所以你最好只使用它来记录短暂的状态信息——不要使用它来保存持久化的数据。当用户跳出某个Activity的时候你应该使用 onPause() 来保持持久化数据(比如那些要写入数据库的数据)。

旋转你的手机,你手机的orientation就改变了,可以利用这个来测试你的app恢复自身状态能力。当屏幕的 orientation 改变时,系统为了为这个新的orientation加载可用的资源,会destroy这个Activity,然后重建它。就因为这个原因,当你旋转手机时,系统重建这个Activity后,恢复这个Activity的状态信息很重要。

处理配置更改

某些设备的配置会在运行时被更改(比如旋转屏幕,设置键盘可用性和语言等)。当这样的一个更改出现时,Android会重新创建这个当前运行的Activity(系统首先调用 onDestroy() ,然后直接调用 onCreate()。设计这种做法是为了方便你的app通过自动重新加载你已经提供的相应可用资源来适应新的配置(比如为不同的屏幕orientation和大小设置不同的布局)。

处理这类情况的最好办法就是使用 onSaveInstanceState()  onRestoreInstanceState() (或者 onCreate())来保存和恢复Activity的状态信息。

Activity之间的协作

当一个Activity A启动另一个ActivityB的时候,它们都会经历生命周期的转换。首先,Activity Apause stop(当然,如果A还可见的话就不会stop),此时B开始被create。如果共享着一些保存在disc或者其他地方的一些数据,我们需要知道在Bcreate之后,A还没有完全stopB进程的开始和A进程的结束是相互进行。系统已经很好的定义了Activity的生命周期回调方法的顺序,特别是当两个Activity在同一个进程中的时候,一个启动另一个。下面就是当Activity A启动Activity B的时候对于的操作顺序:,

  1. Activity A 的 onPause() 方法执行。
  2. Activity B 的 onCreate()onStart(), 和 onResume() 方法依次执行。 (Activity B 拥有了用户焦点。)
  3. 接着,如果 Activity A 在屏幕上不再可见,那么它的 onStop() 方法执行。

这个生命周期回调函数执行顺序的预测可以让你管理一个Activity到另一个 Activity的转换信息。比如,你必须在第一个 Activity stop的时候将更改写入数据库,这样才能保证下一个Activity能够获取最新的信息,而且你需要在 onPause() 方法(而不是 onStop() 方法)中将更改写入数据库。