Android开发-API指南-Activity

Activity

英文原文:http://developer.android.com/intl/zh-cn/guide/components/activities.html
采集日期:2014-4-16
搬迁自原博客:http://blog.sina.com.cn/s/blog_48d491300101h236.html

快速查看

  • Activity 作为应用程序中的一个屏幕窗口,向用户提供操作的界面。
  • Activity 可以转入后台运行,然后再被恢复运行,连同运行状态也一并恢复。

在本文中

  1. 创建一个 Activity
    1. 实现用户界面
    2. 在 manifest 文件中声明 Activity
  2. 启动 Activity
    1. 启动 Activity 并返回结果
  3. 关闭 Activity
  4. 管理 Activity 的生命周期
    1. 实现生命周期回调方法
    2. 保存 Activity 状态
    3. 应对配置的变化
    4. 多个 Activity 的合作

关键类

  1. Activity

参阅

  1. 任务和回退栈

Activity 是一种应用程序组件,它向用户提供了一个屏幕,用户可以与之互动完成某些操作,比如拨打电话、拍照、发送email或者查看地图。 每个 Activity 都有一个窗口用于绘制用户界面。 这个窗口通常会填满整个屏幕,但有时也会小于屏幕并浮在其他窗口的顶端。

一个应用程序通常是由多个关联度比较松散的 Activity 组成的。 典型情况下,一个应用中会指定一个 Activity 为“main” Activity ,这个 Activity 会在第一次启动应用程序时呈现给用户。 每个 Activity 可以再启动其他 Activity 来执行各种 Action。 每当启动一个新的 Activity 时,前一个 Activity 将会被停止,不过系统会把它保存在一个栈里("Back Stack")。 当一个新的 Activity 启动时,它会被压入 Back Stack 栈顶并获得用户焦点。 Back Stack 遵循基本的“后进先出”堆栈机制,因此,当用户用完当前 Activity 并按下了 BACK 键时, 当前 Activity 会被弹出栈(并被销毁),然后前一个 Activity 会恢复运行。 (Back Stack 将在任务和 Back Stack中详细论述。)

当 Activity 由于启动另一个新 Activity 而被停止时,它会通过 Activity 的生命周期回调方法来获得状态改变的通知。 Activity 可能会收到多个回调方法,这取决于其状态的变化——系统正在创建、停止、恢复还是销毁它—— 每次回调都是一次机会,让你能根据状态变化执行特定的任务。 例如,当被停止时,你的 Activity 应该释放掉所有大对象,如网络或数据库连接。 当 Activity 恢复运行时,你可以重新申请必要的资源并恢复被中断的工作。 这些状态的转换就是 Activity 生命周期的一部分。

本文还讨论了创建并使用 Activity 的要点,包括对 Activity 生命周期如何运作的完整叙述, 这样你就能够正确地处理好 Activity 各个状态间的转换了。

创建 Activity

要创建 Activity ,必须创建一个Activity 对象(或一个 Activity 已有子类)的子类。 在你自己的子类中,你需要实现一些回调方法。 当 Activity 在生命周期的各个状态间转换时,比如 Activity 被创建、停止、恢复或销毁时,系统将会调用这些方法。 最重要的两个回调方法是:

onCreate()
你必须实现该方法。系统会在创建你的 Activity 时调用它。 在实现代码里,你应该初始化 Activity 必需的那些组件。 最重要的是,你必须在这里调用setContentView() 来指定 Activity 用户界面的布局(Layout)。
onPause()
当用户要离开 Activity 时(尽管这时并不总是意味着 Activity 要被销毁了),系统将会首先调用本方法。 通常,你应该在这里提交所有在当前用户会话之外也需要记住的改动(因为用户可能不会再回来了)。

为了能在多个 Activity 间提供流畅的用户体验,或为了处理那些导致 Activity 关闭甚至销毁的意外中断情况,你应该要使用更多其他的生命周期回调方法。 所有这些 Activity 生命周期回调方法都将在后面的管理 Activity 的生命周期一节中进行讨论。

实现用户界面

Activity 的用户界面由多个 View 构成的层次结构来提供,View 是派生自 View类的对象。 每个 View 都对应控制着 Activity 窗口中的某部分矩形区域,并可以对用户的交互做出响应。 例如,View 可能是个按钮,用户触摸它时将会启动一个 Action。

Android提供了一些现成(ready-made)的 View,你可以用它们来设计并组织你的 Layout。 “Widgets”是提供可视化(且可交互)屏幕元素的 View,比如按钮、文本框、多选框或者就是一个图片。 “Layouts”是派生自ViewGroup 的 View,用于为它内部的子 View 提供一种布局模式,比如线性布局(linear layout)、网格布局(grid layout)或是相对布局(relative layout)。 你也可以自建ViewViewGroup 的子类,以创建自己的 Widget 和 Layout 并用于自己的 Activity Layout 中。

最常见的用 View 定义 Layout 的方法是利用 XML Layout文件,该文件存放在应用程序的资源目录中。 这样,你就可以把用户界面的设计从定义 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 的标题、Activity 的图标、Activity UI 的主题之类。 android:name 是唯一必需的属性—它指定了 Activity 的类名。应用程序一经发布,你就不允许修改此名称了。 因为假如修改了名称,就可能破坏了某些功能,比如应用程序的快捷方式 (请参阅博文不能改动的东西)。

关于在 manifest 文件中声明 Activity 的详情,请参阅 <Activity> 元素参考手册。

使用 Intent 过滤器

<Activity> 元素还可以定义多种intent过滤器——利用 <intent-filter> 元素——声明被其他应用程序组件激活的方式。

当用 Android SDK 工具软件新建了一个应用程序时,自动创建的主 Activity 元素就包含了一个 Intent 过滤器, 此过滤器指明了 Activity 将响应“main” Action 并且应该被放置在“launcher”类型中。 此 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> 元素指明这是应用程序的“主”入口点。 <category> 元素指明此 Activity 应该纳入系统的应用程序启动器列表中(允许用户启动此 Activity)。

如果你希望应用程序是自给自足的,并且不允许其它应用程序启动它的 Activity, 那么你就不需要任何其它 Intent 过滤器了。 只能有一个 Activity 带有“main” Action 和“launcher” 类型,如上所示。 不想对其他应用程序开放的 Activity 就不应该带有 Intent 过滤器,并且你的应用程序自身也只能用显式的 Intent(在后续章节讨论)来启动它们。

然而,如果你想让 Activity 能够响应其他应用程序(包括你的应用程序自身)发送过来的隐式 Intent, 那么就必须为你的 Activity 定义更多的 Intent 过滤器。 针对每种需要响应的 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:

1 Intent intent = new Intent(this, SignInActivity.class);
2 startActivity(intent);

不过,你的应用程序也许还需要执行其他一些操作,比如发送 email、短信或者更新状态等,而这些操作又需要用到你的 Activity 中的数据。 在这种情况下,你的应用程序自身可能不存在执行这些操作的 Activity ,所以你可以利用设备上其他应用程序提供的 Activity 来为你执行这些操作。 这就是 Intent 真正有价值的地方——你可以创建一个 Intent,其中声明了你要执行的操作,系统会从其他应用程序中启动一个合适的 Activity。 如果能处理此 Intent 的 Activity 不止一个,那么用户可以选择一个来使用。 例如,如果你想要让用户发送一个 email 信息,可创建如下的 Intent:

1 Intent intent = new Intent(Intent.ACTION_SEND);
2 intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
3 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并处理结果的示例:

 1 private void pickContact() {
 2     // Create an intent to "pick" a contact, as defined by the content provider URI
 3     Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
 4     startActivityForResult(intent, PICK_CONTACT_REQUEST);
 5 }
 6 
 7 @Override
 8 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 9     // If the request went well (OK) and the request was PICK_CONTACT_REQUEST
10     if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) {
11         // Perform a query to the contact's content provider for the contact's name
12         Cursor cursor = getContentResolver().query(data.getData(),
13         new String[] {Contacts.DISPLAY_NAME}, null, null, null);
14         if (cursor.moveToFirst()) { // True if the cursor is not empty
15             int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
16             String name = cursor.getString(columnIndex);
17             // Do something with the selected contact's name...
18         }
19     }
20 }

以上例子展示了使用 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 的联系、自身的 Task 和 Back 栈直接影响着 Activity 的生命周期。

Activity 可能处于三种基本状态:

Resumed
Activity 位于屏幕前台并且拥有用户焦点。(这个状态有时也被叫做“running”。)
Paused
另一个 Activity 位于前台并拥有焦点,但是本 Activity 还是可见的。 也就是说,另一个 Activity 覆盖在本 Activity 的上面,且部分透明或没有填满整个屏幕。 一个 Paused 的 Activity 是完全存活的(Activity 对象仍然保留在内存中,它保持着所有的状态和成员信息,并且维持与窗口管理器的关联),但在系统内存严重不足时可能会被杀死。
Stopped
此 Activity 完全被其他 Activity 盖住了(此 Activity 目前处于“后台”)。 一个被停止的 Activity 也仍然是存活的(Activity 对象仍然保留在内存中,它保持着所有的状态和成员信息,但是不再与窗口管理器联接了)。 但是,用户已经看不到它了,并且只要有其他内存需求它就会被系统杀死。

如果 Activity 被 pause 或 stop 了,系统就可以把它从内存中清理出去,这是通过请求终止(调用它的 finish() 方法)或者直接杀死进程。 当 Activity 被再次启动时(在被终止或者杀死后),它必须被完全重建。

实现生命周期回调方法

当 Activity 在上述状态间进行转换时,它能够通过各种回调方法来获得通知。 所有的回调方法都是钩子函数(hook),你可以在 Activity 状态发生改变时重写这些方法来执行一定的操作。 以下的 Activity 简例包含了全部生命周期方法架构:

 1 public class ExampleActivity extends Activity {
 2     @Override
 3     public void onCreate(Bundle savedInstanceState) {
 4         super.onCreate(savedInstanceState);
 5         // The activity is being created.
 6     }
 7     @Override
 8     protected void onStart() {
 9         super.onStart();
10         // The activity is about to become visible.
11     }
12     @Override
13     protected void onResume() {
14         super.onResume();
15         // The activity has become visible (it is now "resumed").
16     }
17     @Override
18     protected void onPause() {
19         super.onPause();
20         // Another activity is taking focus (this activity is about to be "paused").
21     }
22     @Override
23     protected void onStop() {
24         super.onStop();
25         // The activity is no longer visible (it is now "stopped")
26     }
27     @Override
28     protected void onDestroy() {
29         super.onDestroy();
30         // The activity is about to be destroyed.
31     }
32 }

注意:在实现这些生命周期方法时,必须保证在其他操作之前,首先调用一下父类的同名方法,如上例所示。

总之,这些方法定义了 Activity 完整的生命周期。通过实现这些方法,你可以监控 Activity 生命周期中三个嵌套的循环:

  • Activity 的完整生存期是在 onCreate() 调用和 onDestroy() 调用之间进行。 你的 Activity 应该在 onCreate() 方法里完成所有“全局性”状态的设置(比如定义 Layout), 并且在onDestroy() 方法里释放所有所占用的资源。 例如,假定你的 Activity 有一个后台运行的线程,用于从网络下载数据,那么你应该在 onCreate() 方法里创建这个线程并且在 onDestroy() 方法里停止这个线程。
  • Activity 的可见生存期会在 onStart() 调用和 onStop() 调用之间发生。在这期间,用户可在屏幕上看见这个 Activity 并可与之进行交互。 例如,当新启动一个 Activity 后又调用了 onStop() 方法,则这个 Activity 就看不见了。 在这两个方法之间,你可以保存那些显示 Activity 所需的资源。比如,你可以在 onStart() 方法里注册一个 BroadcastReceiver 用于监控影响用户界面的改动,并且当用户看不见显示内容时在 onStop() 方法里注销掉它。 因为 Activity 会在可见和隐藏状态之间来回切换,所以系统可能会在 Activity 的整个生存期内进行多次 onStart()onStop()调用。

  • Activity 的前台生存期将在 onResume() 调用和 onPause() 调用之间发生。在这段时间内,该 Activity 位于屏幕上所有其他 Activity 之前,并且拥有用户的输入焦点。 Activity 可以频繁地进入和退出前台——例如,当设备进入休眠时或者出现一个对话框时, onPause() 就会被调用。因为状态可能经常会发生切换,为了避免切换迟缓引起的用户等待,这两个方法中的代码应该非常轻量化。

图1标明了 Activity 在各个状态之间可能的循环和执行路径。矩形框代表你可以实现的回调方法,用于 Activity 状态转换时执行某些操作。

图 1. Activity 的生命周期

表1中也同时列出了这些生命周期回调方法,该表更详细地描述了每个回调方法,并且指明了每个方法在整个 Activity 生命周期中的位置, 包括回调方法完成后系统是否会杀死这个 Activity 。

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

方法描述之后可否被杀死?下一个调用
onCreate() Activity 第一次被创建时将会被调用。在这里你应该完成所有的常用静态设置工作—创建view、绑定 list 里的数据等等。 本方法将会传入一个 Bundle 对象。如果之前已抓取了该 Activity 的状态信息(详见后面的保存 Activity 状态),则此 Bundle 中就包含了前一个状态的信息。

下一个回调方法一定是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 都不再可被杀死。

注意: 表1中标明的技术上不“可杀”的 Activity 仍然有可能会被系统杀死—但这只有在没有其他资源可用的极端情况下才会发生。 什么时候 Activity 可能会被杀掉,已在文档进程和线程里进行了更为详细的讨论。

保存 Activity 状态

管理 Activity 生命周期一节中已简单提到,当一个 Activity 被暂停或停止时,Activity 的状态仍然保留着。 的确如此,因为 Activity 对象在被暂停或停止时仍然被保留在内存之中—所有的成员信息和当前状态都仍然存活。 这样用户在 Activity 里所作的改动全都还保留着,所以当 Activity 返回到前台时(当它“resume“),这些改动仍然有效。

但是,一旦系统为了回收内存而销毁 Activity ,则 Activity 对象就会被销毁,这样系统就无法简单地恢复状态完整的 Activity 了。 如果用户要返回到这个 Activity 的话,系统必须重新创建Activity 对象。可是用户并不知道系统是先销毁 Activity 再重新创建了的,所以,他很可能希望 Activity 完全保持原样。 在这种情况下,你可以通过实现另一个回调方法 onSaveInstanceState() ,以确保将 Activity 状态的相关重要信息都保存下来。

在 Activity 即将被销毁之前,系统会调用 onSaveInstanceState()方法。 调用时系统会传入一个Bundle对象, 你可以利用 putString() 之类的方法,以键值对的方式把 Activity 状态信息保存到该Bundle对象中。 然后,如果系统杀掉了你的应用程序进程而用户又返回你的 Activity ,系统就会重建 Activity 并将这个 Bundle 传给onCreate()onRestoreInstanceState() ,你就可以从 Bundle 中解析出已保存的信息并恢复 Activity 状态。如果没有储存状态信息,那么传入的 Bundle 将为null(当第一次创建 Activity 时就是如此)。

图 2. 把带有完整状态信息的 Activity 展现给用户的两种方式:销毁后再被重建,且须恢复之前保存的状态;或者被停止后再被恢复运行,状态都完整保留着。

注意: Activity 被销毁之前,并不能确保每次都会调用 onSaveInstanceState() ,因为存在那些不需要保存状态的情况(比如用户使用 BACK 键离开了你的 Activity ,显然他确实是要关闭此 Activity )。 如果系统要调用 onSaveInstanceState() 方法,那么通常会在 onStop() 方法之前并且可能是在 onPause() 之前调用。

不过,即使你没有实现 onSaveInstanceState() 方法,有些 Activity 状态还是会通过 Activity 类缺省实现的onSaveInstanceState() 方法保存下来。比较典型的是,缺省为 Layout 中的每个 View 实现了调用相应的onSaveInstanceState() 方法,这使得每一个 View 都能给出自己需被保存的信息。 Android 框架中几乎所有的 Widget 都会适时实现此方法,这样,任何用户界面中可见的变化都会被自动保存下来,并在 Activity 重建后自动恢复。 例如,EditText Widget 会保存所有用户已经输入的文本, CheckBox Widget 也会保存是否被选中。你所要做的事情仅仅是为每个需要保存状态的 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 状态, 那么你的应用程序将对 Activity 生命周期中其它的意外事件更具恢复能力。

处理这类重启的最佳方式,就是利用 onSaveInstanceState()onRestoreInstanceState() (或者 onCreate() )进行状态的保存和恢复,如上节所述。

有关运行时配置的改变及相应处理方法的详情,请参阅指南 处理运行时的变动

多个 Activity 的合作

当某 Activity 启动另一个 Activity 时,它俩的生命周期状态都会发生切换。 第一个 Activity 将被暂停并停止(尽管它也可能不会被停止,如果它仍然存活于后台的话),而另一个 Activity 是被创建。 如果这两个 Activity 共用了保存在磁盘或其他地方的数据,那么请明白:在第二个 Activity 被创建之前,第一个 Activity 还没有完全被停止,这点非常重要。 或多或少,第二个 Activity 的启动过程与第一个 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 可以读取数据,那么你就应该在 onPause() 方法而不是 onStop() 方法里写入数据库。

posted on 2014-12-19 16:16  呆呆大虾  阅读(1374)  评论(0编辑  收藏  举报

导航