Android doc |Getting Started|部分 转载 --管理Activity生命周期

来源:互联网 发布:淘宝上怎么免费开店 编辑:程序博客网 时间:2024/05/21 07:00

原文
https://developer.android.com/training/basics/activity-lifecycle/index.html
原文被部分改动

管理Activity生命周期

当用户导航、退出和返回您的应用时,应用中的 Activity 实例将在其生命周期中转换不同状态。 例如,当您的Activity初次开始时,它将出现在系统前台并接收用户焦点。 在这个过程中,Android 系统会对Activity调用一系列生命周期方法,通过这些方法,您可以设置用户界面和其他组件。 如果用户执行开始另一Activity或切换至另一应用的操作,当其进入后台(在其中Activity不再可见,但实例及其状态完整保留),系统会对您的Activity调用另外一系列生命周期方法。

在生命周期回调方法内,您可以声明 用户离开和再次进入Activity时的Activity行为。比如,如果您正构建流视频播放器,当用户切换至另一应用时,您可能要暂停视频或终止网络连接。当用户返回时,您可以重新连接网络并允许用户从同一位置继续播放视频。

本课讲述每个 Activity 实例接收的重要生命周期回调方法以及您如何使用这些方法以使您的Activity按照用户预期进行并且当您的Activity不需要它们时不会消耗系统资源。

开始Activity

不同于使用 main() 方法启动应用的其他编程范例,Android 系统会通过调用对应于其生命周期中特定阶段的特定回调方法在 Activity 实例中启动代码。 有一系列可启动Activity的回调方法,以及一系列可分解Activity的回调方法。

本课程概述了最重要的生命周期方法,并向您展示如何处理创建Activity新实例的第一个生命周期回调。
了解生命周期回调
在Activity的生命周期中,系统会按类似于阶梯金字塔的顺序调用一组核心的生命周期方法。 也就是说,Activity生命周期的每个阶段就是金字塔上的一阶。 当系统创建新Activity实例时,每个回调方法会将Activity状态向顶端移动一阶。 金字塔的顶端是Activity在前台运行并且用户可以与其交互的时间点。

当用户开始离开Activity时,系统会调用其他方法在金字塔中将Activity状态下移,从而销毁Activity。 在有些情况下,Activity将只在金字塔中部分下移并等待(比如,当用户切换到其他应用时),Activity可从该点开始移回顶端(如果用户返回到该Activity),并在用户停止的位置继续。
Activity生命周期
简化的Activity生命周期图示,以阶梯金字塔表示。 此图示显示,对于用于将Activity朝顶端的“继续”状态移动一阶的每个回调,有一种将Activity下移一阶的回调方法。 Activity还可以从“暂停”和“停止”状态回到继续状态。

根据Activity的复杂程度,您可能不需要实现所有生命周期方法。 但是,了解每个方法并实现确保您的应用按照用户期望的方式运行的方法非常重要。 正确实现您的Activity生命周期方法可确保您的应用按照以下几种方式良好运行,包括:

  • 如果用户在使用您的应用时接听来电或切换到另一个应用,它不会崩溃。
  • 在用户未主动使用它时不会消耗宝贵的系统资源。
  • 如果用户离开您的应用并稍后返回,不会丢失用户的进度。
  • 当屏幕在横向和纵向之间旋转时,不会崩溃或丢失用户的进度。

正如您将要在以下课程中要学习的,有Activity会在上图所示不同状态之间过渡的几种情况。 但是,这些状态中只有三种可以是静态。 也就是说,Activity只能在三种状态之一下存在很长时间。

继续(Resumed)
在这种状态下,Activity处于前台,且用户可以与其交互。(有时也称为“运行”状态。)
暂停(Paused)
在这种状态下,Activity被在前台中处于半透明状态或者未覆盖整个屏幕的另一个Activity—部分阻挡。 暂停的Activity不会接收用户输入并且无法执行任何代码。
停止(Stopped)
在这种状态下,Activity被完全隐藏并且对用户不可见;它被视为处于后台。 停止时,Activity实例及其诸如成员变量等所有状态信息将保留,但它无法执行任何代码。
其他状态(“创建”和“开始”)是瞬态,系统会通过调用下一个生命周期回调方法从这些状态快速移到下一个状态。 也就是说,在系统调用 onCreate() 之后,它会快速调用 onStart(),紧接着快速调用 onResume()。

基本生命周期部分到此为止。现在,您将开始学习特定生命周期行为的一些知识。

指定您的应用的启动器Activity
当用户从主屏幕选择您的应用图标时,系统会为您已声明为“启动器”( 或“主要”main)Activity的应用中的 Activity 调用 onCreate() 方法。 这是作为 您的应用的用户界面主入口的Activity。

您可以在 Android 宣示说明文件中 AndroidManifest.xml 定义哪个Activity用作主Activity(mainActivity),该说明文件位于您项目目录的根目录中。

您的应用的主Activity必须使用 <intent-filter>(包括 MAIN 操作和 LAUNCHER 类别)在宣示说明中声明。声明mainActivity的例子:

<activity android:name=".MainActivity" android:label="@string/app_name">    <intent-filter>        <action android:name="android.intent.action.MAIN" />        <category android:name="android.intent.category.LAUNCHER" />    </intent-filter></activity>

注意:当您使用 Android SDK工具创建新 Android 项目时,默认的项目文件已经包括上面所述的使用过滤器和category属性的Activity 类。

如果未对您的Activity之一声明 MAIN 操作或 LAUNCHER 类别,那么您的应用图标将不会出现在应用的主屏幕列表中。

创建一个新实例
大多数应用包含若干个不同的Activity,用户可通过这些Activity执行不同的操作。无论Activity是用户单击您的应用图标时创建的主Activity还是您的应用在响应用户操作时开启的其他Activity,系统都会通过调用各个Activity的onCreate() 方法创建 Activity 的每个新实例。

您必须实现 onCreate() 方法来执行只应在Activity整个生命周期只需要调用一次的基本应用程序的启动逻辑。例如,您的 onCreate() 的实现应定义用户界面(如定义一些控件,并初始化)并且可能实例化某些类范围变量。

以下展示的示例onCreate() 方法,Activity执行了某些基本设置的一些代码,比如声明用户界面(为在XML中定义好的控件做出声明)、定义成员变量,以及配置某些 UI。

TextView mTextView; // Member variable for text view in the layout@Overridepublic void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    // Set the user interface layout for this Activity    // The layout file is defined in the project res/layout/main_activity.xml file    setContentView(R.layout.main_activity);    // Initialize member TextView so we can manipulate it later    mTextView = (TextView) findViewById(R.id.text_message);    // Make sure we're running on Honeycomb or higher to use ActionBar APIs    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {        // For the main activity, make sure the app icon in the action bar        // does not behave as a button        ActionBar actionBar = getActionBar();        actionBar.setHomeButtonEnabled(false);    }}

注意:使用 SDK_INT 可防止旧版系统以这种方式仅在 Android 2.0 (API 级别5)和更高级别执行新 API 工作。 较旧版本会遇到运行时异常。

一旦 onCreate() 完成执行操作,系统会相继调用 onStart() 和 onResume() 方法。 您的Activity从不会驻留在“已创建”Created或“已开始”Started状态。从代码上看,Activity会在 onStart() 被调用时变得可见,但紧接着会调用 onResume(),且Activity保持“继续”Resumed状态,直到有事情发生使Activity状态发生变化,比如当接听来电时,或者用户导航至另一个Activity,或设备屏幕关闭。

在接下来的其他课程中,您将看到其他Activity如何启动方法,当用于从“暂停”或“停止”状态返回原来的Activity时,onStart() 和 onResume() 在您的Activity生命周期中特别有用。

注意:onCreate() 方法包括一个称为 savedInstanceState 的参数,将在有关重新创建Activity的后续课程中讨论该参数。
这里写图片描述
图 2.Activity生命周期结构的另一个图示,其重点放在 创建Activity的新实例时系统依次调用的三大回调上:onCreate()、onStart() 和 onResume()。 一旦这一系列回调完成,Activity就进入“继续”状态,此时用户可与Activity进行交互,直至用户切换到其他Activity。

销毁Activity
Activity的第一个生命周期回调是 onCreate() ,它最后的回调是 onDestroy()。系统会对您的Activity调用此方法,作为您的Activity实例完全从系统内存删除的最终信号。

大多数应用不需要实现此方法,因为本地类引用与Activity一同销毁,并且您的Activity应在 onPause() 和 onStop() 期间执行大多数清理操作。 但是,如果您的Activity包含您在 onCreate() 期间创建的后台线程或其他如若未正确关闭可能导致内存泄露的长期运行资源,您应在 onDestroy() 期间终止它们。

@Overridepublic void onDestroy() {    super.onDestroy();  // Always call the superclass    // Stop method tracing that the activity started during onCreate()    android.os.Debug.stopMethodTracing();}

注意:在所有情况下,系统在调用 onPause() 和 onStop() 之后都会调用 onDestroy() ,只有一个例外:当您从 onCreate() 方法内调用 finish() 时。在有些情况下,比如当您的Activity作为临时决策工具运行以启动另一个Activity时,您可从 onCreate() 内调用 finish() 来销毁Activity。 在这种情况下,系统会立刻调用 onDestroy(),而不调用任何其他 生命周期方法。(finish不仅仅可以在onCreate调用,onStart onPause等也可以调用)

暂停和继续Activity
在正常使用应用的过程中,前台Activity有时会被其他导致Activity暂停的可视组件阻挡。 例如,当半透明Activity打开时(比如对话框样式中的Activity),原来的Activity会暂停。 只要Activity仍然部分可见但目前又未处于焦点之中,它会一直暂停。

但是,一旦Activity完全被阻挡并且不可见,它便停止(将在下一堂课中讨论)。

当您的Activity进入暂停状态时,系统会对您的 Activity 调用 onPause() 方法,通过该方法,您可以停止不应在暂停时继续的进行之中的操作(比如视频)或保留任何应该永久保存的信息,以防用户坚持离开应用。如果用户从暂停状态返回到您的Activity,系统会重新开始该Activity并调用 onResume() 方法。

注意:当您的Activity收到对 onPause() 的调用时,可能意味着Activity将暂停 一会,并且用户可能从焦点返回到您的Activity。但这通常意味着用户即将离开您的Activity。(即当收到onPause()通知后,有可能之后收到onResume重新进去该activity,也可能收到onStop onDestroy直接离开了此Activity)
这里写图片描述
图 1.当半透明Activity阻挡您的Activity时,系统会调用 onPause() 并且Activity会在“暂停”状态下等待 (1)。 如果用户在Activity仍然处于暂停状态时返回Activity,则系统会调用 onResume() (2)。

暂停Activity
当系统为您的Activity调用 onPause() 时,它从技术角度看意味着您的Activity仍然处于部分可见状态,但往往说明用户即将离开Activity并且它很快就要进入“停止”状态。 您通常应使用 onPause() 回调执行一下操作:

  • 停止动画或其他可能消耗 CPU 的进行之中的操作。
  • 提交未保存的更改,但仅当用户离开时希望永久性保存此类更改(比如电子邮件草稿)。
  • 释放系统资源,比如广播接收器、传感器手柄(比如 GPS)
    或当您的Activity暂停且用户不需要它们时仍然可能影响电池寿命的任何其他资源。

例如,如果您的应用使用 Camera, onPause() 方法是释放它的好位置。

@Overridepublic void onPause() {    super.onPause();  // Always call the superclass method first    // Release the Camera because we don't need it when paused    // and other activities might need to use it.    if (mCamera != null) {        mCamera.release()        mCamera = null;    }}

一般情况下,您不得使用 onPause() 永久性存储用户更改(比如输入表格的个人信息)。 只有在您确定用户希望自动保存这些更改的情况(比如,电子邮件草稿)下,才能在 onPause()中永久性存储用户更改。但您应避免在 onPause() 期间执行 CPU 密集型工作,比如向数据库写入信息,因为这会拖慢向下一Activity过渡的过程(您应改为在 onStop()期间执行高负载关机操作。

您应通过相对简单的方式在 onPause() 方法中完成大量操作,这样才能加快在您的Activity确实停止的情况下用户向下一个目标过渡的速度。

注意:当您的Activity暂停时,Activity 实例将驻留在内存中并且在Activity继续时被再次调用。您无需重新初始化在执行任何导致进入“继续”状态的回调方法期间创建的组件。

继续(Resume)Activity
当用户从“暂停”状态继续您的Activity时,系统会调用 onResume() 方法。

Be aware that the system calls this method every time your activity comes into the foreground, including when it’s created for the first time. As such, you should implement onResume() to initialize components that you release during onPause() and perform any other initializations that must occur each time the activity enters the Resumed state (such as begin animations and initialize components only used while the activity has user focus).

请注意,每当您的Activity进入前台时系统便会调用此方法,包括它初次创建之时。 同样地,您应实现onResume()以便:初始化会在 onPause() 期间释放的组件;以及执行每当Activity进入“继续”状态时必须进行的任何其他初始化操作(比如开始动画和初始化只在Activity具有用户焦点时使用的组件)。

onResume() 的以下示例对应于以上的 onPause() 示例,因此它会重新初始化在Activity Pause时释放的Camera。

@Overridepublic void onResume() {    super.onResume();  // Always call the superclass method first    // Get the Camera instance as the activity achieves full user focus    if (mCamera == null) {        initializeCamera(); // Local method to handle camera init    }}

Stopping and Restarting an Activity

正确停止和重新开始Activity是Activity生命周期中的重要过程,其可确保您的用户知晓应用始终保持Activity状态并且不会丢失进度。有几种Activity停止和重新开始的关键场景:

  • 用户打开“最近应用”窗口并从您的应用切换到另一个应用。当前位于前台的您的应用中的Activity将停止。如果用户从主屏幕启动器图标或“最近应用”窗口返回到您的应用,Activity会重新开始。
  • 用户在您的应用中执行开始新Activity的操作。当第二个Activity创建好后,当前Activity便停止。如果用户之后按了返回按钮,第一个Activity会重新开始。
  • 用户在其手机上使用您的应用的同时接听来电。
    Activity 课程提供两种生命周期方法:onStop() 和 onRestart(),这些方法允许您专门处理正在停止和重新开始的Activity。 不同于识别部分 UI 阻挡的暂停状态,停止状态保证 UI 不再可见,且用户的焦点在另外的Activity(或完全独立的应用)中。

注意:因为系统在停止时会将您的 Activity 实例保留在系统内存中,您根本无需实现 onStop() 和 onRestart()或甚至onStart() 方法。对于大多数相对简单的Activity而言, Activity将停止并重新开始,并且您可能只需使用 onPause() 暂停正在进行的操作,并从系统资源断开连接。
这里写图片描述
图 1.用户离开Activity时,系统会调用 onStop() 停止Activity(1)。 如果用户在Activity停止时返回,系统会调用 onRestart() (2),紧接着调用 onStart() (3) 和 onResume() (4)。 注意:无论什么场景导致Activity停止,系统始终会在调用 onStop() 之前调用 onPause()。

Stop Your Activity
当您的Activity收到 onStop() 方法的调用时,它不再可见,并且应释放几乎所有用户不使用时不需要的资源。 一旦您的Activity停止,如果需要恢复系统内存,系统可能会销毁该实例。 在极端情况下,系统可能会仅终止应用进程,而不会调用Activity的最终 onDestroy() 回调,因此您使用 onStop() 释放可能泄露内存的资源非常重要。

尽管 onPause() 方法在 onStop()之前调用,您应使用 onStop() 执行更大、占用更多 CPU 的关闭操作,比如向数据库写入信息。

例如,此处是将草稿笔记内容保存在永久存储中的 onStop() 的实现:

@Overrideprotected void onStop() {    super.onStop();  // Always call the superclass method first    // Save the note's current draft, because the activity is stopping    // and we want to be sure the current note progress isn't lost.    ContentValues values = new ContentValues();    values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());    values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());    getContentResolver().update(            mUri,    // The URI for the note to update.            values,  // The map of column names and new values to apply to them.            null,    // No SELECT criteria are used.            null     // No WHERE columns are used.            );}

当您的Activity停止时, Activity 对象将驻留在内存中并在Activity继续时被再次调用。 您无需重新初始化在任何导致进入“继续”状态的回调方法过程中创建的组件。 系统还会在布局中跟踪每个 View 的当前状态,如果用户在 EditText 小工具中输入文本,该内容会保留,因此您无需保存即可恢复它。

注意:即使系统在Activity停止时销毁了Activity,它仍会保留 Bundle(键值对的二进制大对象)中的 View 对象(比如 EditText 中的文本),并在用户导航回Activity的相同实例时恢复它们 (下一堂课 讲述更多有关在您的Activity被销毁且重新创建的情况下使用 Bundle 保存其他数据状态的知识)。

开始/重新开始(start/restart)Activity
当您的Activity从停止状态返回前台时,它会接收对 onRestart() 的调用。系统还会在每次您的Activity变为可见时调用 onStart() 方法(无论是正重新开始还是初次创建)。 但是,只会在Activity从停止状态继续时调用 onRestart() 方法,因此您可以使用它执行只有在Activity之前停止过但未销毁的情况下可能必须执行的特殊恢复工作。

应用需要使用 onRestart() 恢复Activity状态的情况并不常见,因此没有适用于一般应用群体的任何方法指导原则。 但是,因为您的 onStop() 方法应基本清理所有Activity的资源,您将需要在Activity重新开始时重新实例化它们。 但是,您还需要在您的Activity初次创建时重新实例化它们(没有Activity的现有实例)。 出于此原因,您应经常使用 onStart() 回调方法作为 onStop() 方法的对应部分,因为系统会在它创建您的Activity以及从停止状态重新开始Activity时调用 onStart() 。

例如,因为用户可能在回到它之前已离开应用很长时间, onStart() 方法是确认所需系统功能已启动的理想选择:

@Overrideprotected void onStart() {    super.onStart();  // Always call the superclass method first    // The activity is either being restarted or started for the first time    // so this is where we should make sure that GPS is enabled    LocationManager locationManager =            (LocationManager) getSystemService(Context.LOCATION_SERVICE);    boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);    if (!gpsEnabled) {        // Create a dialog here that requests the user to enable GPS, and use an intent        // with the android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS action        // to take the user to the Settings screen to enable GPS when they click "OK"    }}@Overrideprotected void onRestart() {    super.onRestart();  // Always call the superclass method first    // Activity being restarted from stopped state}

当系统销毁您的Activity时,它会调用您的 Activity 的 onDestroy() 方法。因为您通常应已使用 onStop() 释放大多数您的资源,到您接收对 onDestroy() 的调用时,大多数应用无需做太多操作。 此方法是您清理可导致内存泄露的资源的最后一种方法,因此您应确保其他线程被销毁且其他长期运行的操作(比如方法跟踪)也会停止。

重新创建Activity

在有些情况下,您的Activity会因正常应用行为而销毁,比如当用户按 返回按钮或您的Activity通过调用 finish()示意自己的销毁。 如果Activity当前被停止或长期未使用,或者前台Activity需要更多资源以致系统必须关闭后台进程恢复内存,系统也可能会销毁Activity。

当您的Activity因用户按了返回 或Activity自行完成而被销毁时,系统的那个Activity 实例将永久消失,因为行为指示不再需要Activity。 但是,如果系统因系统局限性(而非正常应用行为)而销毁Activity,尽管 Activity 实际实例已不在,系统会记住其存在,这样,如果用户导航回实例,系统会使用描述Activity被销毁时状态的一组已保存的数据来创建Activity的新实例。 系统用于恢复先前状态的已保存数据被称为“实例状态”,并且是 Bundle 对象中存储的键值对集合。

注意:每次用户旋转屏幕时,您的Activity将被销毁并重新创建。 当屏幕方向变化时,系统会销毁并重新创建前台Activity,因为屏幕配置已更改并且您的Activity可能需要加载备用资源(比如布局)。

默认情况下,系统会使用 Bundle 实例状态保存您的Activity布局(比如,输入到 EditText 对象中的文本值)中有关每个 View 对象的信息。 这样,如果您的Activity实例被销毁并重新创建,布局状态便恢复为其先前的状态,且您无需代码。 但是,您的Activity可能具有您要恢复的更多状态信息,比如跟踪用户在Activity中进度的成员变量。

注意:为了 Android 系统恢复Activity中视图的状态,每个视图必须具有 android:id 属性提供的唯一 ID。

要保存有关Activity状态的其他数据,您必须替代 onSaveInstanceState() 回调方法。当用户要离开Activity并在Activity意外销毁时向其传递将保存的 Bundle 对象时,系统会调用此方法。 如果系统必须稍后重新创建Activity实例,它会将相同的 Bundle 对象同时传递给 onRestoreInstanceState() 和 onCreate() 方法。
这里写图片描述
图 2.当系统开始停止您的Activity时,它会 调用 onSaveInstanceState() (1),因此,您可以指定您希望在 Activity 实例必须重新创建时保存的额外状态数据。如果Activity被销毁且必须重新创建相同的实例,系统将在 (1) 中定义的状态数据同时传递给 onCreate() 方法(2) 和 onRestoreInstanceState() 方法(3)。

保存Activity状态
当您的Activity开始停止时,系统会调用 onSaveInstanceState() 以便您的Activity可以保存带有键值对集合的状态信息。 此方法的默认实现保存有关Activity视图层次的状态信息,例如 EditText 小工具中的文本或ListView 的滚动位置。

要保存Activity的更多状态信息,您必须实现 onSaveInstanceState() 并将键值对添加至 Bundle 对象。 例如:

static final String STATE_SCORE = "playerScore";static final String STATE_LEVEL = "playerLevel";...@Overridepublic void onSaveInstanceState(Bundle savedInstanceState) {    // Save the user's current game state    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);    // Always call the superclass so it can save the view hierarchy state    super.onSaveInstanceState(savedInstanceState);}

注意:始终调用 onSaveInstanceState() 的超类实现,以便默认实现可以保存视图层次的状态。

恢复Activity状态
当您的Activity在先前销毁之后重新创建时,您可以从系统向Activity传递的 Bundle 恢复已保存的状态。onCreate() 和 onRestoreInstanceState() 回调方法均接收包含实例状态信息的相同 Bundle。

因为无论系统正在创建Activity的新实例还是重新创建先前的实例,都会调用 onCreate() 方法,因此您必须在尝试读取它之前检查状态 Bundle 是否为 null。 如果为 null,则系统将创建Activity的新实例,而不是恢复已销毁的先前实例。

例如,此处显示您如何可以在 onCreate() 中恢复一些状态数据:

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState); // Always call the superclass first    // Check whether we're recreating a previously destroyed instance    if (savedInstanceState != null) {        // Restore value of members from saved state        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);    } else {        // Probably initialize members with default values for a new instance    }    ...}

您可以选择实现系统在 onStart() 方法之后调用的 onRestoreInstanceState() ,而不是在onCreate() 期间恢复状态。 系统只在存在要恢复的已保存状态时调用 onRestoreInstanceState() ,因此您无需检查 Bundle 是否为 null:

public void onRestoreInstanceState(Bundle savedInstanceState) {    // Always call the superclass so it can restore the view hierarchy    super.onRestoreInstanceState(savedInstanceState);    // Restore state members from saved instance    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);}

注意:始终调用 onSaveInstanceState() 的超类实现,以便默认实现可以恢复视图层次的状态。

要了解更多有关因运行时重启事件(例如屏幕旋转时)而重新创建Activity的信息,请阅读处理运行时更改。

0 0
原创粉丝点击