Quickview
- An activity provides a user interface for a single screen in your application
- Activities can move into the background and then be resumed with their state restored
In this document
Key classes
See also
Activity
是这样一个程序组件,它为用户提供一个用于任务交互的画面。例如,拨打电话,拍照,发邮件。或者查看地图。每一个activity都被分配一个窗口。在这个窗口里,你可以绘制用户交互的内容。
这个窗口通常占满屏幕,但也有可能比屏幕小,并且浮在其它窗口的上面。
一个应用程序通常由多个activity组成,它们彼此保持弱的绑定状态。典型的,当一个activity在一个应用程序内被指定为主activity, 那么当程序第一次启动时,它将第一个展现在用户面前。为了展现不同的内容,每一个activity可以启动另外一个。 每当一个新的activity被启动,那么之前的将被停止。但系统将会把它压入一个栈(“back stack”即后退栈),当一个新的activity启动,它将被 放到栈顶并获得用户焦点。后台栈遵循后进先出的栈机制。所以当用户完成当前页面并按下返回按钮时,它将被pop出栈(并销毁),之前的activity将被恢复。 (关于后退栈的更多讨论在任务和后退栈)
当一个activity因为另一个activity的启动而被停止,那么其生命周期中的回调方法,将会以状态改变的形式被调用。 activity通过它自身状态的改变可以收到多个回调方法。当系统创建,停止,恢复,销毁它的时候。并且每个回调方法都给你做相应处理工作的机会。 例如,当停止的时候,你的activity应当释放比较大的对象,例如网络连接,数据连接。当你的activity恢复时,你可以请求必须的资源并恢复一些被打断的动作。 这些状态事务的处理就构成了activity的生命周期。
接下来将讨论如何搭建和使用activity,完整讨论activity的生命周期是怎么工作的,这样你就可以合理地管理不同activity状态间的事务处理。
创建一个Activity
要创建一个activity,你必须创建一个Activity
(或者它存在的子类)的子类。
在你的子类里,你需要实现系统调用的回调方法,这些方法用于activity在生命周期中进行事务处理。例如创建,停止,恢复,销毁。其中两个最重要的回调方法分别为:
onCreate()
-
你必须实现这个方法。系统会在创建activity的时候调用这个方法。
在实现这个方法的同时,你需要实现你activity的重要组件。
最重要的是,你必须在这里调用
setContentView()
来定义你activity用于用户交互的布局。 onPause()
- 系统将会调用这个方法作为用户离开activity的首先提示(虽然这并不意味着activity正在被销毁)。这通常是你应该在用户会话之前提交并保存任何更改的时机。 (因为用户可能不会再回到这个activity).
你还应该会用到一些其他的生命周期回调方法,它们将帮助你在activity和可能导致你的activity停止甚至销毁之间保持流畅的用户体验。 所有的生命周期回调方法都将在后面讨论。详细请看管理Activity的生命周期.
实现一个用户交互界面
activity的用户接口由一些View
的派生类组成的层级结构提供。
每一个view控制acitivity所在window的一个特殊的矩形空间。并且可以响应用户的交互。
例如,一个view可能是一个按钮,当用户碰触的时候将发起动作。
"Layouts"是一组继承了ViewGroup
的布局。它们为子视图提供了唯一的布局模型。
例如线性布局,表格布局,相对布局。你也可以继承View
和ViewGroup
(或它们的子类)去创建你自己的组件或布局,并用它们组成activity布局。
定义布局最常用的方式是使用XML布局文件,它保存在你程序的资源中。这种方式可以保证你的业务逻辑代码和用户交互界面分开。你可以通过setContentView()
传递布局文件的ID来设置程序UI。
当然,你也可以在activity代码里自己新建View
,并通过插入子View
到ViewGroup
。
然后把这些视图的根视图传入到setContentView()
。
更多用户界面创建请参照User Interface 文档。
在配置文件中声明activity
为了可以访问activity,你必须把它配置到配置文件中。
首先打开配置文件,在<application>
中增加一个<activity>
元素。例如:
<manifest ... > <application ... > <activity android:name=".ExampleActivity" /> ... </application ... > ... </manifest >
你可以给这个元素加入很多其他的属性。
例如名称,图标,或者activity的主题风格。
android:name
属性是唯一用来指定acitivity名称的属性。
一旦你发布了程序,就不能改变它的名字,否则将破坏一些功能,例如程序图标。
(阅读博文查看你不能改变的属性
查阅 <activity>
来获得更多关于如何配置activity
使用filter
<activity>
也可以用很多<intent-filter>
来指定其他的组件怎样激活它。
当你使用Android SDK tools来创建一个程序,主activity将会自动包含一个被分类为"launcher"的intent filter,如下:
<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
<action>
元素指定程序的入口。 <category>
指出该activity应该被列如系统的启动器(launcher)(允许用户启动它)
如果你想要你的程序更加独立,并不想让其他程序访问你的activity,那么你就不必声明intent filter,只有一个activity 应该有"main"action和"launcher"分类,例如上述例子。你不想公开的activity应该不包含任何intent filter.但你可以使用明确 的intent来启动它们。(下文将详述)。
然而,如果你想要你的activity响应其他程序(或当前程序)的隐式intent,你必须为activity定义额外的intent filter。
每一个你想响应的intent,都必须包含一个 <intent-filter>
,并包含一个
<action>
元素,另外,可以包含一个 <category>
也可以包含一个 <data>
元素。
这些元素指定了intent 的类型。
关于响应intent的更多方式,请查阅 Intents 和 Intent Filter
启动一个Activity
你可以启动一个其他的activity通过调用startActivity()
,
并传递一个 Intent
,
它用于描述acitity。
intent指定了你想要启动的activity,或者指定了你想展现的动作(系统帮你选择合适的activity,它可能来自于其他的程序)。
intent也可以携带比较小量的数据,用于启动acitivity。
在你自己的应用中,你经常会简单地启动一个已知的activity, 通过创建一个明确的intent。这个intent指定了activity的类名。
例如下面演示了如何启动一个叫SignInActivity
的activity:
Intent intent = new Intent(this, SignInActivity.class); startActivity(intent);
然而,你的程序可能想要展示某些动作,例如发邮件,短信,微博,或者使用你activity中的数据。 这时候,你就不应该使用自己的activity来做这些工作。你应该调用系统中其他程序提供的响应功能。 这是intent真正体现其价值的地方。你可以创建一个描述了响应动作的intent,然后系统来为你挑选完成任务的程序。 如果有多个选择,系统会提示用户进行选择。例如你想让用户发邮件,你可以创建下面的intent:
Intent intent = new Intent(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_EMAIL, recipientArray); startActivity(intent);
EXTRA_EMAIL
是一个邮件intent中添加的额外字符串数组,它指定了邮件该发给哪些邮件地址。当一个邮件程序响应了这个intent,
它将读取这些地址,并把他们放置到邮件表单的被发送人栏。这时,邮件程序被启动。当用户完成了发送操作,你的activity会被恢复。
启动一个带返回结果的activity
有时候,你想要启动一个activity,并从这个activty获得一个结果。
这时,要通过 startActivityForResult()
(取代startActivity()
)
来启动activity。
然后通过实现onActivityResult()
回调方法来获得返回后的结果。
当这个后续的activity被关闭,它将发送一个 Intent
给 onActivityResult()
方法。
例如,你可能想要取一个联系人的信息。下面介绍怎么创建intent并处理结果:
private void pickContact() { // Create an intent to "pick" a contact, as defined by the content provider URI Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI); startActivityForResult(intent, PICK_CONTACT_REQUEST); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // If the request went well (OK) and the request was PICK_CONTACT_REQUEST if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) { // Perform a query to the contact's content provider for the contact's name Cursor cursor = getContentResolver().query(data.getData(), new String[] {Contacts.DISPLAY_NAME}, null, null, null); if (cursor.moveToFirst()) { // True if the cursor is not empty int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME); String name = cursor.getString(columnIndex); // Do something with the selected contact's name... } } }
这个例子展示了使用onActivityResult()
来获取结果的基本方法。
第一步要判断请求是否被成功响应,通过判断resultCode
是不是RESULT_OK
—,
然后判断这个响应是不是针对相应的请求—
,此时只要判断requestCode
和发送时提供的第二个参数 startActivityForResult()
是否相匹配。
最后,查询 Intent
中的data信息。 (data
参数)。
这个过程中,ContentResolver
开启了一个查询而不是content provider, 它返回一个
Cursor
,这将允许数据被读取。更多content provider相关信息,请查阅Content Providers 文档。
关于intent的更多信息, 查看 Intents and Intent Filters 文档。
关闭Activity
你可以通过调用finish()
来终止activity。
你也可以调用finishActivity()
来终止你之前启动了的一个独立activity。
注意: 多数情况下,你不应该明确地通过这些方式来关闭acitivity。 就像下面要讨论的activity的生命周期。系统会为你管理。所以你不必关闭他们。 调用这些方法将有悖于用户体验。它们仅用于你绝对不想让用户再返回这个activity的实例。
管理Activity的生命周期
创建Activity
要创建activity,必须创建一个Activity 的子类(或一个已有Activity的子类)。 在你的子类中,你需要实现一些回调方法。 当activity在生命周期各个状态间转换时,系统会调用这些方法,比如activity被创建、停止、恢复或者销毁时。 两个最重要的回调方法是: onCreate()
- 这是必须实现的方法。系统会在创建activity时调用它。 在实现过程中,应该初始化一些你的activity所必需的组件。 最重要的是,必须在这里调用setContentView() 来指定activity用户界面的布局layout。
- 当用户一旦有要离开activity的迹象时,系统就会调用本方法(尽管这时并不总是意味着activity要被销毁了)。 通常这里应该提交所有要保存的改动,这些改动是在当前用户会话之外也需要维持的(因为用户可能不会回来了)。
为了能在多个activity间提供流畅的用户体验,或为了处理那些导致activity关闭甚至销毁的意外中断情况,你应该要用到很多其它的生命周期回调方法。 所有这些activity生命周期回调方法都将在后面的管理Activity的生命周期部分进行论述。
实现用户界面
activity的用户界面是由多个view构成的层次结构来提供支持的——派生自 View类的对象。 每个view都对应控制着activity窗口中的某部分矩形区域,并可以响应用户的交互。 例如,view可以是个按钮,用户触摸它时将启动一个action。
Android提供了一些现成的view,你可以用它们来设计并组织你的布局layout。 “Widgets”是提供可视化(且可交互)屏幕部件的view,比如按钮、文本框、多选框或者一个图像。 “Layouts”是派生自ViewGroup 的view,用于向它的子view提供一种layout模式,比如线性布局linear layout、网格布局grid layout或是相对布局relative layout。 你也可以自建View 和ViewGroup 的子类,来创建你自己的widget和layout并用于自己的activity layout。
最常见的定义布局的方法是在存放应用程序资源的XML layout文件里使用view。 这样,就可以把用户界面的设计与定义activity行为的源代码分离开来。 可以用setContentView() 方法来将layout设定为activity的UI,调用时把layout的资源ID传入即可。 当然,也可以在activity代码中创建一个新的View, 并通过将其插入ViewGroup 来建立一个view的层次结构,然后通过把根ViewGroup 传递给setContentView() 来使用此layout。
关于创建用户界面的详细信息,请参阅用户界面文档。
在manifest中声明activity
为了能让系统访问到你的activity,必须在manifest文件里对其进行声明。 要声明activity,请打开你的mainifest文件并添加一个 <activity> 元素,它必须是<application> 元素的子元素。例如:
<manifest ... > <application ... > <activity android:name=".ExampleActivity" /> ... </application ... > ... </manifest >
该元素中还可以包含很多其它的属性,用于定义诸如activity的label、activity的图标、activity UI的外观theme之类。 android:name 属性是唯一必需的属性——它定义了activity的类名。应用程序一经发布,你就不得修改此名称了。 假如修改了名称,就可能破坏了某些功能,比如应用程序的快捷方式 (参阅博文不能改动的东西)。
关于在manifest文件中声明activity的详情,请参阅 <activity> 元素参考手册。
使用intent过滤器
<activity> 元素还可以定义多种intent过滤器——利用<intent-filter>元素——用于对如何被其它应用程序组件激活而进行声明。
当用Android SDK工具新建了一个应用程序时,自动创建好的activity元素就包含了一个intent过滤器, 此过滤器指明了activity将响应“main”action并应该是被放置在“launcher”category中。 此intent过滤器应是类似如下的形式:
<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
<action> 元素指明这是应用程序的“main”入口点。 <category> 元素指明了此activity应该能让系统启动应用程序(允许用户启动此activity)。
如果你希望应用程序是封闭运行的而且不允许其它应用程序激活它的activity, 那么你就不需要任何其它intent过滤器了。 应该只能有一个activity会有“main”action和“launcher”category,就像上面的例子那样。 你不想对其它应用程序开放的activity应该就没有intent过滤器,并且你的应用程序自身也只能用显式的intent来启动它们(如下所述)。
不过,如果期望你的activity能够响应其它应用程序(包括你的应用自己)发送过来的隐式intent, 则必须为你的activity定义更多的intent filter。 针对每种需要响应的intent类型,都必须包含一个内含 <action> 元素和可选的 <category> 元素与/或 <data> 元素的 <intent-filter> 。这些元素指定了你的activity可以响应的 intent的类型。
关于activity如何响应intent的详细信息,请参阅文章Intent和Intent过滤器。
启动activity
可以通过调用 startActivity() 来启动另一个activity,调用时传递一个描述了所要启动activity的 Intent 。这个intent或是精确指定了所要启动的activity,或是指明了需要执行的action类型 (然后系统会为你选择一个合适的activity,甚至可以是其它应用程序中的activity)。 intent还可以携带少量的数据,这些数据可被所启动的activity使用。
当应用程序运行时,经常会需要能够便捷地启动其它已知的activity。 这只要通过创建一个显式的intent即可,这个intent用类名明确指定了你想要启动的activity。 例如,下面是一个activity如何启动另一个名为SignInActivity的activity:
Intent intent = new Intent(this, SignInActivity.class); startActivity(intent);
不过,你的应用程序也许还需要执行一些其它的action,比如发送一个email、文本信息或者状态更新信息之类,而这些action又需要用到你的activity中的数据。 这种情况下,你的应用程序本身可能不存在执行这些action的activity,所以你可以 利用本设备上其它应用提供的activity来为你执行这些动作。 这就是intent真正有价值的地方——你可以创建一个说明了你要执行action的intent, 而系统会从其它应用程序中启动一个合适的activity。 如果存在多个activity都能够处理此intent,那么用户可以自己选择一个来执行。 例如,如果你想要允许用户发送一个email信息,可创建如下的intent:
Intent intent = new Intent(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_EMAIL, recipientArray); startActivity(intent);
附加在intent的extra部分中的EXTRA_EMAIL信息是一个有关email目标地址的字符串数组。 当email应用程序响应这个intent时, 它会读取extra部分中的字符串数组并将它们填入撰写email表单中的“to”字段。 在这种情况下,email应用程序的activity将会被启动。并且当用户完成发送后,你的activity将会恢复运行。
启动activity并返回结果
有时你可能需要从你启动的activity里返回一个结果。 这种情况下,请通过调用 startActivityForResult() 来启动一个activity(而不是 startActivity() )。然后,要想从被启动的activity里接收到结果,请实现 onActivityResult() 回调方法。当该activity完成操作后,它会把一个包含结果的 Intent 返回到你的 onActivityResult() 中。
比如,也许你需要用户选取一个联系人,以便于你的activity能够根据联系人信息执行一些操作。下面就是创建intent并处理结果的示例:
private void pickContact() { // Create an intent to "pick" a contact, as defined by the content provider URI Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI); startActivityForResult(intent, PICK_CONTACT_REQUEST); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // If the request went well (OK) and the request was PICK_CONTACT_REQUEST if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) { // Perform a query to the contact's content provider for the contact's name Cursor cursor = getContentResolver().query(data.getData(), new String[] {Contacts.DISPLAY_NAME}, null, null, null); if (cursor.moveToFirst()) { // True if the cursor is not empty int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME); String name = cursor.getString(columnIndex); // Do something with the selected contact's name... } } }
以上例子展示了使用 onActivityResult() 方法来处理activity返回结果的基本逻辑。 第一个判断条件是检查请求是否成功——如果成功了resultCode 应该是RESULT_OK ,以及要求响应的请求是否是可识别的——在这种情况下,requestCode会与传入 startActivityForResult() 的第二个参数相比较。 接下来,代码通过查询Intent 返回的数据(data参数)来处理activity的返回结果。
接下来,ContentResolver 通过content provider执行了一个查询,查询返回了一个包含查到数据以供读取的 Cursor 。详情请参阅Content Providers文档。
关于使用intent的更多信息,请详阅 Intent和Intent过滤器文档。
关闭activity
可以调用activity的 finish() 方法来关闭它。也可以用 finishActivity() 方法来关闭一个你先前已经启动的单个activity。
注意: 在大多数的情况下,不应该使用这些方法来显式地关闭一个activity。 正如以下关于activity生命周期的部分所述,Android系统会替你管理activity的生命周期,所以你不需要关闭你的activity。 调用这些方法可能会对预期的用户体验产生不利的影响,仅当你确实不想让用户再返回到这个activity的实例时才会用到它们。
管理activity的生命周期
通过实现回调方法来管理你的activity的生命周期,对于开发一个健壮而又灵活的应用程序而言是至关重要的。 与其它activity的关联性、自身的任务和back stack直接影响着一个activity的生命周期。
activity可能处于三种基本的状态:
- Resumed
- activity在屏幕的前台并且拥有用户的焦点。(这个状态有时也被叫做“running”。)
- Paused
- 另一个activity在前台并拥有焦点,但是本activity还是可见的。 也就是说,另外一个activity覆盖在本activity的上面,并且那个activity是部分透明的或没有覆盖整个屏幕。 一个paused的activity是完全存活的(Activity 对象仍然保留在内存里,它保持着所有的状态和成员信息,并且保持与window manager的联接),但在系统内存严重不足的情况下它能被杀死。
- Stopped
- 本activity被其它的activity完全遮挡住了(本activity目前在后台)。 一个stopped的activity也仍然是存活的(Activity 对象仍然保留在内存中,它保持着所有的状态和成员信息,但是不再与window manager联接了)。 但是,对于用户而言它已经不再可见了,并且当其它地方需要内存时它将会被杀死。
如果activity被paused或stopped了,则系统可以从内存中删除它,通过请求finish(调用它的 finish() 方法)或者直接杀死它的进程。 当这个activity被再次启动时(在被finish或者kill后),它必须被完全重建。
实现生命周期回调方法
当一个activity在上述描述的状态之间转换时,它将通过各种回调方法来获得通知。 所有的回调方法都是钩子(hook),当activity状态发生改变时你都可以 重写这些方法来执行对应的工作。 以下的activity提纲包含了所有基本的生命周期方法:
public class ExampleActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // The activity is being created. } @Override protected void onStart() { super.onStart(); // The activity is about to become visible. } @Override protected void onResume() { super.onResume(); // The activity has become visible (it is now "resumed"). } @Override protected void onPause() { super.onPause(); // Another activity is taking focus (this activity is about to be "paused"). } @Override protected void onStop() { super.onStop(); // The activity is no longer visible (it is now "stopped") } @Override protected void onDestroy() { super.onDestroy(); // The activity is about to be destroyed. } }
- 注意:实现这些生命周期方法时,必须保证在其它代码之前首先调用一下父类的方法,如上例所示。
总体来讲,这些方法定义了一个activity的完整的生命周期。 通过实现这些方法,你可以监控activity生命周期中三个嵌套的循环:
- activity的完整生存期会在 onCreate() 调用和 onDestroy() 调用之间发生。 你的activity应该在 onCreate() 方法里完成所有“全局global”状态的设置(比如定义layout), 而在onDestroy() 方法里释放所有占用的资源。 例如,如果你的activity有一个后台运行的线程,用于从网络下载数据,那么你应该在 onCreate() 方法里创建这个线程并且在 onDestroy() 方法里停止这个线程。
- activity的可见生存期会在 onStart() 调用和 onStop() 调用之间发生。在这期间,用户可在屏幕上看见这个activity并可与之交互。 例如,当一个新的activity启动后调用了 onStop() 方法,则这个activity就无法被看见了。 在这两个方法之间,你可以管理那些显示activity所需的资源。例如,你可以在 onStart() 方法里注册一个 BroadcastReceiver 用于监控影响用户界面的改动。并且当用户不再看到你的显示内容时,在 onStop() 方法里注销掉它。 系统会在activity的整个生存期内多次调用 onStart() 和onStop(), 因为activity可能会在显示和隐藏之间不断地来回切换。
- activity的前台生存期会在 onResume() 调用和 onPause() 之间发生。在这期间,activity是位于屏幕上所有其它的activity之前,并且拥有用户的输入焦点。 activity可以频繁地进入和退出前台——例如, 当设备进入休眠时或者弹出一个对话框时, onPause() 就会被调用。因为这个状态可能会经常发生转换,为了避免切换迟缓引起的用户等待,这两个方法中的代码应该相当地轻量化。
图1说明了activity在状态之间可能行走的这些循环和路径。矩形代表了你可以实现的回调方法,用于activity状态转换时执行相应操作。
- 图 1.activity生命周期
同样的生命周期回调方法已经在表1中列出了,该表更详细地描述了每个回调方法,并且指明了每个方法在activity的全生命周期中的位置, 包括回调方法完成后系统是否会杀死这个activity。
- 表 1.activity生命周期回调方法汇总
方法 | 描述 | 之后可否被杀死? | 下一个方法 |
---|---|---|---|
onCreate() | activity第一次被创建时调用。在这里你应该完成所有常见的静态设置工作——创建view、绑定list数据等等。 本方法传入一个包含了该activity前一个状态的Bundle对象(如果之前已捕获了状态的话,详见后面的保存Activity状态)。
下一个回调方法总是onStart()。 |
否 | onStart() |
onRestart() | activity被停止后、又再次被启动之前调用。
下一个回调方法总是onStart() |
否 | onStart() |
onStart() | activity要显示给用户之前调用。
如果activity进入前台,则下一个回调方法是onResume();如果进入隐藏状态,则下一个回调方法是onStop()。 |
否 | onResume() 或 onStop() |
onResume() | activity开始与用户交互之前调用。这时activity是在activity栈的顶端,用户可以向其中输入。
下一个回调方法总是onPause()。 |
否 | onPause() |
onPause() | 当系统准备启动另一个正在恢复的activity时调用。这个方法通常用于把未保存的改动提交为永久数据、停止动画播放、以及其它可能消耗CPU的工作等等。 它应该非常迅速地完成工作,因为下一个activity在本方法返回前是不会被恢复运行的。
如果activity返回前台,则下一个回调方法是onResume();如果进入用户不可见状态,则下一个是onStop() |
可以 | onResume() 或 onStop() |
onStop() | 当activity不再对用户可见时调用。原因可能是它即将被销毁、或者其它activity(已有或新建的)被恢复运行并要覆盖本activity。
如果activity还会回来与用户交互,则下一个回调方法是onRestart();如果这个activity即将消失,则下一个回调方法是onDestroy() |
可以 | onRestart() 或 onDestroy() |
onDestroy() | 在本activity被销毁前调用。这是activity收到的最后一个调用。 可能是因为activity完成了工作(有些人在这里调用finish()), 也可能是因为系统为了腾出空间而临时销毁activity的本实例。 可以利用isFinishing() 方法来区分这两种情况。 | 可以 | 无 |
标为“之后可否被杀死?”的列指明了系统是否可以在这个方法返回之后的任意时刻杀掉这个activity的宿主进程, 而不再执行其它流程上的activity代码。 有三个方法是标为“可以”:( onPause()、 onStop()、 和onDestroy())。 因为onPause()是三个方法中的第一个, 一旦activity被创建, onPause() 就是进程可以被杀死之前最后一个能确保被调用的方法 ——如果系统在某种紧急情况下必须回收内存,则 onStop() 和onDestroy() 可能就不会被调用了。因此,你应该使用 onPause() 来把至关重要的需长期保存的数据写入存储器(比如用户所编辑的内容)。 不过,应该对必须通过 onPause() 方法进行保存的信息有所选择,因为该方法中所有的阻塞操作都会让切换到下一个activity的停滞,并使用户感觉到迟缓。
“之后可否被杀死?”列中标为“否”的方法,在它们被调用时的那一刻起,就会保护本activity的宿主进程不被杀掉。 因此,只有在 onPause() 方法返回时至 onResume() 方法被调用时之间,activity才会被杀掉。直到 onPause() 再次被调用并返回时,activity都不会再次允许被杀死。
Note:表1中标明的技术上不“可杀”的activity仍然有可能会被系统杀死——但那只有在没有任何资源的极端情况下才会发生。 什么时候activity会被杀掉,已在文档进程和线程里详细说明了。
保存activity的状态
管理Activity生命周期一节中已简单提到,当一个activity被paused或者stopped时,activity的状态可以被保存。 的确如此,因为 Activity 对象在paused或者stopped时仍然被保留在内存之中——它所有的成员信息和当前状态都仍然存活。 这样用户在activity里所作的改动全都还保存着,所以当activity返回到前台时(当它“resume“),那些改动仍然有效。
不过,如果系统是为了回收内存而销毁activity,则这个 Activity 对象就会被销毁,这样系统就无法简单地resume一下就能还原完整状态的activity。 如果用户要返回到这个activity的话,系统必须重新创建这个Activity 对象。可是用户并不知道系统是先销毁activity再重新创建了它的,所以,他很可能希望activity完全保持原样。 这种情况下,你可以保证activity状态的相关重要信息都由另一个回调方法保存下来了,此方法让你能保存activity状态的相关信息: onSaveInstanceState()。
在activity变得很容易被销毁之前,系统会调用 onSaveInstanceState()方法。 调用时系统会传入一个Bundle对象, 你可以利用 putString() 之类的方法,以键值对的方式来把activity状态信息保存到该Bundle对象中。 然后,如果系统杀掉了你的application进程并且用户又返回到你的activity,系统就会重建activity并将这个 Bundle 传入onCreate() 和onRestoreInstanceState() 中,你就可以从 Bundle 中解析出已保存信息并恢复activity状态。如果没有储存状态信息,那么传入的 Bundle 将为null(当activity第一次被创建时就是如此)。
图 2. activity状态完整地返回给用户的两种方式:被销毁destroyed后再被重建,而且必须恢复了之前保存的状态;或是被停止stopped后再被恢复resumed,状态都完整保留着。
注意: activity被销毁之前,并不能确保每次都会调用 onSaveInstanceState() ,因为存在那些不必保存状态的情况(比如用户使用BACK键离开了你的activity,因为用户明显是关了这个activity)。 如果系统要调用 onSaveInstanceState() 方法,那么它通常会在 onStop() 方法之前并且可能是在 onPause() 之前调用。
不过,即使你没有实现 onSaveInstanceState() 方法,有些activity状态还是会通过 Activity 类缺省实现的onSaveInstanceState() 方法保存下来。特别的是,缺省为layout中的每个 View 实现了调用相应的onSaveInstanceState() 方法,这允许每一个view提供自己需被保存的信息。 几乎Android框架下所有的widget都会在适当的时候实现该方法,这样,任何UI上可见的变化都会自动保存下来,并在activity重建后自动恢复。 例如,EditText widget会保存所有用户已经输入的文本, CheckBoxwidget 也会保存是否被选中。你所要做的工作仅仅是为每一个你想要保存其状态的widget提供一个唯一的ID(就是 android:id 属性)。如果这个widget没有ID的话,系统是无法保存它们的状态的。
通过把android:saveEnabled 设置为"false",或者调用 setSaveEnabled() 方法,你也可以显式地阻止layout中的某个view保存状态。 通常不应该禁用保存,不过假如你需要恢复activity UI的各个不同的状态,也许可以这么做。
尽管缺省实现的 onSaveInstanceState() 方法会保存activity UI的有用信息,你仍然需要覆盖它来存入更多的信息。 例如,你可能需要保存在activity生命周期中改变的成员变量值(可能是关于UI恢复的值,但是默认情况下,存放这些UI状态的成员变量值是不会被恢复的)。
因为默认实现的 onSaveInstanceState() 方法已经帮你保存了一些UI的状态,所以如果你重写此方法是为了保存更多的状态信息,那么在执行自己的代码之前应该确保先调用一次父类的 onSaveInstanceState() 方法。同理,如果重写 onRestoreInstanceState() 的话,也应该调用一次父类的该方法,这样缺省的代码就能正常恢复view的状态了。
注意:因为 onSaveInstanceState() 并不保证每次都会被调用,所以你应该只用它来记录activity的一些临时状态信息(UI的状态)——千万不要用它来保存那些需要长久保存的数据。 替代方案是,你应该在用户离开activity的时候利用 onPause() 来保存永久性数据(比如那些需要存入数据库里的数据)。
一个检测应用程序状态恢复能力的好方法就是旋转设备,使得屏幕方向发生改变。 当屏幕的方向改变时,因为要换用符合实际屏幕参数的资源,系统会销毁并重建这个activity。 正因如此,你的activity能够在被重建时完整地恢复状态是非常重要的,因为用户会在使用应用程序时会频繁地旋转屏幕。
配置改动后的处理
设备的某些配置可能会在运行时发生变化(比如屏幕方向、键盘可用性以及语言)。 当发生这些变化时,Android会重建这个运行中的activity(系统会调用 onDestroy() ,然后再马上调用 onCreate() )。这种设计有助于应用程序适用新的参数配置,通过把你预置的可替换资源(比如对应各种屏幕方向和尺寸的layout)自动重新装载进入应用程序的方式来实现。
如果你采取了适当的设计,让activity能够正确地处理这些因为屏幕方向而引起的重启,并能如上所述地恢复activity状态, 那么你的应用程序将对生命周期中其它的意外事件更具适应能力。
处理这类重启的最佳方式,就是利用 onSaveInstanceState() 和onRestoreInstanceState() (或者 onCreate() )进行状态的保存和恢复,如上节所述。
有关运行时配置的改变及其相应处理的详情,请参阅指南处理运行时的变动
多activity的合作
当activity启动另一个activity时,它俩生命周期的状态都会发生转换。 第一个activity paused并stopped(尽管它也可能不会被stopped,如果它仍然后台可见的话),而另一个activity是被created。 如果这两个activity共用了保存在磁盘或其它地方的数据,那么请明白:在第二个activity被created之前,第一个activity还没有完全被stopped,这点非常重要。 或多或少,第二个activity的启动进程与第一个activity的关闭进程在时间上会发生重叠。
生命周期回调方法的顺序是很明确的,特别是两个activity位于同一个进程中、一个启动另一个的时候。 下面就是Aactivity A启动Activity B时的操作顺序:
- Activity A的 onPause()方法,如果活动后台不可见的话,onStop()方法同样运行,否则不运行。
- Activity B的 onCreate() ,onStart() 和onResume() 方法依次运行。(Activity B现在获得用户焦点。)
以上预设的生命周期回调方法顺序使你能够对一个activity启动另一个activity时的转换信息进行管理。 例如,如果第一个activity停止时你须写入数据库以便后续的activity可以读取数据,那么你应该在 onPause() 方法而不是 onStop() 方法里写入数据库。
下面是部分原文翻译,可选择阅读:Managing the lifecycle of your activities by implementing callback methods is crucial to developing a strong and flexible application. The lifecycle of an activity is directly affected by its association with other activities, its task and back stack.
An activity can exist in essentially three states:
- Resumed
- The activity is in the foreground of the screen and has user focus. (This state is also sometimes referred to as "running".)
- Paused
- Another activity is in the foreground and has focus, but this one is still visible. That is,
another activity is visible on top of this one and that activity is partially transparent or doesn't
cover the entire screen. A paused activity is completely alive (the
Activity
object is retained in memory, it maintains all state and member information, and remains attached to the window manager), but can be killed by the system in extremely low memory situations. - Stopped
- The activity is completely obscured by another activity (the activity is now in the
"background"). A stopped activity is also still alive (the
Activity
object is retained in memory, it maintains all state and member information, but is not attached to the window manager). However, it is no longer visible to the user and it can be killed by the system when memory is needed elsewhere.
If an activity is paused or stopped, the system can drop it from memory either by asking it to
finish (calling its finish()
method), or simply killing its
process. When the activity is opened again (after being finished or killed), it must be created all
over.
Implementing the lifecycle callbacks
When an activity transitions into and out of the different states described above, it is notified through various callback methods. All of the callback methods are hooks that you can override to do appropriate work when the state of your activity changes. The following skeleton activity includes each of the fundamental lifecycle methods:
public class ExampleActivity extends Activity { @Override public voidonCreate
(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // The activity is being created. } @Override protected voidonStart()
{ super.onStart(); // The activity is about to become visible. } @Override protected voidonResume()
{ super.onResume(); // The activity has become visible (it is now "resumed"). } @Override protected voidonPause()
{ super.onPause(); // Another activity is taking focus (this activity is about to be "paused"). } @Override protected voidonStop()
{ super.onStop(); // The activity is no longer visible (it is now "stopped") } @Override protected voidonDestroy()
{ super.onDestroy(); // The activity is about to be destroyed. } }
Note: Your implementation of these lifecycle methods must always call the superclass implementation before doing any work, as shown in the examples above.
Taken together, these methods define the entire lifecycle of an activity. By implementing these methods, you can monitor three nested loops in the activity lifecycle:
- The entire lifetime of an activity happens between the call to
onCreate()
and the call toonDestroy()
. Your activity should perform setup of "global" state (such as defining layout) inonCreate()
, and release all remaining resources inonDestroy()
. For example, if your activity has a thread running in the background to download data from the network, it might create that thread inonCreate()
and then stop the thread inonDestroy()
. The visible lifetime of an activity happens between the call to
onStart()
and the call toonStop()
. During this time, the user can see the activity on-screen and interact with it. For example,onStop()
is called when a new activity starts and this one is no longer visible. Between these two methods, you can maintain resources that are needed to show the activity to the user. For example, you can register aBroadcastReceiver
inonStart()
to monitor changes that impact your UI, and unregister it inonStop()
when the user can no longer see what you are displaying. The system might callonStart()
andonStop()
multiple times during the entire lifetime of the activity, as the activity alternates between being visible and hidden to the user.The foreground lifetime of an activity happens between the call to
onResume()
and the call toonPause()
. During this time, the activity is in front of all other activities on screen and has user input focus. An activity can frequently transition in and out of the foreground—for example,onPause()
is called when the device goes to sleep or when a dialog appears. Because this state can transition often, the code in these two methods should be fairly lightweight in order to avoid slow transitions that make the user wait.
Figure 1 illustrates these loops and the paths an activity might take between states. The rectangles represent the callback methods you can implement to perform operations when the activity transitions between states.
The same lifecycle callback methods are listed in table 1, which describes each of the callback methods in more detail and locates each one within the activity's overall lifecycle, including whether the system can kill the activity after the callback method completes.
Method | Description | Killable after? | 后一个 | ||
---|---|---|---|---|---|
|
Called when the activity is first created.
This is where you should do all of your normal static set up —
create views, bind data to lists, and so on. This method is passed
a Bundle object containing the activity's previous state, if that
state was captured (see Saving Activity State,
later).
Always followed by |
No | onStart() |
||
|
Called after the activity has been stopped, just prior to it being
started again.
Always followed by |
No | onStart() |
||
|
Called just before the activity becomes visible to the user.
Followed by |
No | onResume() or onStop() |
||
|
Called just before the activity starts
interacting with the user. At this point the activity is at
the top of the activity stack, with user input going to it.
Always followed by |
No | onPause() |
||
|
Called when the system is about to start resuming another
activity. This method is typically used to commit unsaved changes to
persistent data, stop animations and other things that may be consuming
CPU, and so on. It should do whatever it does very quickly, because
the next activity will not be resumed until it returns.
Followed either by |
Yes | onResume() or onStop() |
||
|
Called when the activity is no longer visible to the user. This
may happen because it is being destroyed, or because another activity
(either an existing one or a new one) has been resumed and is covering it.
Followed either by |
Yes | onRestart() or onDestroy() |
||
|
Called before the activity is destroyed. This is the final call
that the activity will receive. It could be called either because the
activity is finishing (someone called on it), or because the system is temporarily destroying this
instance of the activity to save space. You can distinguish
between these two scenarios with the method. |
Yes | nothing |
The column labeled "Killable after?" indicates whether or not the system can
kill the process hosting the activity at any time after the method returns, without
executing another line of the activity's code. Three methods are marked "yes": (onPause()
, onStop()
, and onDestroy()
). Because onPause()
is the first
of the three, once the activity is created, onPause()
is the
last method that's guaranteed to be called before the process can be killed—if
the system must recover memory in an emergency, then onStop()
and onDestroy()
might
not be called. Therefore, you should use onPause()
to write
crucial persistent data (such as user edits) to storage. However, you should be selective about
what information must be retained during onPause()
, because any
blocking procedures in this method block the transition to the next activity and slow the user
experience.
Methods that are marked "No" in the Killable column protect the process hosting the
activity from being killed from the moment they are called. Thus, an activity is killable
from the time onPause()
returns to the time
onResume()
is called. It will not again be killable until
onPause()
is again called and returns.
Note: An activity that's not technically "killable" by this definition in table 1 might still be killed by the system—but that would happen only in extreme circumstances when there is no other recourse. When an activity might be killed is discussed more in the Processes and Threading document.
Saving activity state
The introduction to Managing the Activity Lifecycle briefly mentions
that
when an activity is paused or stopped, the state of the activity is retained. This is true because
the Activity
object is still held in memory when it is paused or
stopped—all information about its members and current state is still alive. Thus, any changes
the user made within the activity are retained so that when the activity returns to the
foreground (when it "resumes"), those changes are still there.
However, when the system destroys an activity in order to recover memory, the Activity
object is destroyed, so the system cannot simply resume it with its state
intact. Instead, the system must recreate the Activity
object if the user
navigates back to it. Yet, the user is unaware
that the system destroyed the activity and recreated it and, thus, probably
expects the activity to be exactly as it was. In this situation, you can ensure that
important information about the activity state is preserved by implementing an additional
callback method that allows you to save information about the state of your activity: onSaveInstanceState()
.
The system calls onSaveInstanceState()
before making the activity vulnerable to destruction. The system passes this method
a Bundle
in which you can save
state information about the activity as name-value pairs, using methods such as putString()
and putInt()
. Then, if the system kills your application
process and the user navigates back to your activity, the system recreates the activity and passes
the Bundle
to both onCreate()
and onRestoreInstanceState()
. Using either of these
methods, you can extract your saved state from the Bundle
and restore the
activity state. If there is no state information to restore, then the Bundle
passed to you is null (which is the case when the activity is created for
the first time).
Note: There's no guarantee that onSaveInstanceState()
will be called before your
activity is destroyed, because there are cases in which it won't be necessary to save the state
(such as when the user leaves your activity using the Back button, because the user is
explicitly
closing the activity). If the system calls onSaveInstanceState()
, it does so before onStop()
and possibly before onPause()
.
However, even if you do nothing and do not implement onSaveInstanceState()
, some of the activity state is
restored by the Activity
class's default implementation of onSaveInstanceState()
. Specifically, the default
implementation calls the corresponding onSaveInstanceState()
method for every View
in the layout, which allows each view to provide information about itself
that should be saved. Almost every widget in the Android framework implements this method as
appropriate, such that any visible changes to the UI are automatically saved and restored when your
activity is recreated. For example, the EditText
widget saves any text
entered by the user and the CheckBox
widget saves whether it's checked or
not. The only work required by you is to provide a unique ID (with the android:id
attribute) for each widget you want to save its state. If a widget does not have an ID, then the
system cannot save its state.
You can also explicitly stop a view in your layout from saving its state by setting the
android:saveEnabled
attribute to "false"
or by calling
the setSaveEnabled()
method. Usually, you should not
disable this, but you might if you want to restore the state of the activity UI differently.
Although the default implementation of onSaveInstanceState()
saves useful information about
your activity's UI, you still might need to override it to save additional information.
For example, you might need to save member values that changed during the activity's life (which
might correlate to values restored in the UI, but the members that hold those UI values are not
restored, by default).
Because the default implementation of onSaveInstanceState()
helps save the state of the UI, if
you override the method in order to save additional state information, you should always call the
superclass implementation of onSaveInstanceState()
before doing any work. Likewise, you should also call the supercall implementation of onRestoreInstanceState()
if you override it, so the
default implementation can restore view states.
Note: Because onSaveInstanceState()
is not guaranteed
to be called, you should use it only to record the transient state of the activity (the state of
the UI)—you should never use it to store persistent data. Instead, you should use onPause()
to store persistent data (such as data that should be saved
to a database) when the user leaves the activity.
A good way to test your application's ability to restore its state is to simply rotate the device so that the screen orientation changes. When the screen orientation changes, the system destroys and recreates the activity in order to apply alternative resources that might be available for the new screen configuration. For this reason alone, it's very important that your activity completely restores its state when it is recreated, because users regularly rotate the screen while using applications.
Handling configuration changes
Some device configurations can change during runtime (such as screen orientation, keyboard
availability, and language). When such a change occurs, Android recreates the running activity
(the system calls onDestroy()
, then immediately calls onCreate()
). This behavior is
designed to help your application adapt to new configurations by automatically reloading your
application with alternative resources that you've provided (such as different layouts for
different screen orientations and sizes).
If you properly design your activity to handle a restart due to a screen orientation change and restore the activity state as described above, your application will be more resilient to other unexpected events in the activity lifecycle.
The best way to handle such a restart is
to save and restore the state of your activity using onSaveInstanceState()
and onRestoreInstanceState()
(or onCreate()
), as discussed in the previous section.
For more information about configuration changes that happen at runtime and how you can handle them, read the guide to Handling Runtime Changes.
Coordinating activities
When one activity starts another, they both experience lifecycle transitions. The first activity pauses and stops (though, it won't stop if it's still visible in the background), while the other activity is created. In case these activities share data saved to disc or elsewhere, it's important to understand that the first activity is not completely stopped before the second one is created. Rather, the process of starting the second one overlaps with the process of stopping the first one.
The order of lifecycle callbacks is well defined, particularly when the two activities are in the same process and one is starting the other. Here's the order of operations that occur when Activity A starts Acivity B:
- Activity A's
onPause()
method executes. - Activity B's
onCreate()
,onStart()
, andonResume()
methods execute in sequence. (Activity B now has user focus.) - Then, if Activity A is no longer visible on screen, its
onStop()
method executes.
This predictable sequence of lifecycle callbacks allows you to manage the transition of
information from one activity to another. For example, if you must write to a database when the
first activity stops so that the following activity can read it, then you should write to the
database during onPause()
instead of during onStop()
.