Activity生命周期管理(Managing the Activity Lifecycle)

来源:互联网 发布:只有bluetooth网络连接 编辑:程序博客网 时间:2024/06/05 05:42

最开始学习安卓时翻译的google官网关于Activity的介绍.

原文地址为: http://developer.android.com/training/basics/activity-lifecycle/index.html


Activity生命周期管理

当一个用户浏览,退出和重回你的应用程序,程序的活动实例在它生命周期的不同状态转换.例如,当你的活动第一次启动时,它变成系统前台,并接收用户关注的焦点.在这个过程中,Android系统调用了一系列的活动,在其中设置了用户界面和其它组件的生命周期方法.如果用户执行一个动作,开始另一项活动或者切换到另一个应用程序时,系统调用活动的另一组生命周期方法,当活动移入后台时(该活动不再可见,但该活动实例其状态仍然完好).在生命周期回调方法中,你可以定义你的活动的行为当用户离开并重新进入.例如,如果你正在构建一个流媒体视频播放器,当用户切换到另一个应用程序,你可能会暂停视频和终止网络连接.当用户返回时,你可以重新连接到网络,并允许用户从相同的位置恢复播放视频.这段内容解释了每个活动实例接收的重要生命周期回调函数和怎样使用它们.这样,你的活动做用户所期望的,并且在不需要的情况下,不占用系统资源.

 

启动一个活动

不像其他的用main()方法启动应用程序的编程范式,Android系统中一个活动实例的启动代码是通过调用对应其生命周期的特定阶段的特定回调方法.有一序列的回调方法来启动和摧毁活动实例.

 

以下内容提供了最重要的生命周期方法的概述,并向你展示如何通过第一个生命周期回调方法,创建一个新的活动实例.

 

了解生命周期回调

在一个活动的生命过程中,系统序列的调用生命周期方法的核心集合类似阶梯金字塔.即活动的生命周期的每一个阶段都是金字塔上一个单独的步骤.系统创建了一个新的活动实例,每一个回调方法把活动状态向顶端移动一步.金字塔的顶部是活动前台运行和用户与之交互的关键点.

 

当用户开始离开活动时,为了拆除这个活动,系统调用其他方法使得活动状态沿着金字塔向下.在某些情况下,活动将会部分向下移动,并等待(例如当用户切换到其他应用程序),活动能从这个点返回金字塔的顶部(如果用户返回该活动)并恢复用户离开时的状态.


图1 简要说明了活动的生命周期,表现为一个阶梯金字塔.展示了,活动如何通过回调一步步恢复到顶部状态,有一个回调方法使活动状态下移.活动也可以从暂停和停止状态返回到恢复状态.

 

根据你的活动的复杂性,你可能并不需要实现所有的生命周期方法.但是,重要的是你必须了解每个你实现的方法,以确保应用程序的行为符合用户的期望.正确地实现你的活动的生命周期方法,确保你的应用程序的行为在以下几个方面良好:

如果用户收到一个电话,或切换到另一个程序,你的程序不会崩溃

当用户没有积极的使用它,不消耗宝贵的系统资源

不失去用户的进度,如果他们离开你的应用并在以后的时间里返回

不会崩溃或者失去用户的进度,当屏幕在横向和纵向之间切换

 

正如你将在接下来的课程中学到的那样,在如图1所示的几种情况下,一个活动在不同的状态这件转换.然而,这些状态中只有三种是可以静态的.即,可以存在三种状态之一,在相当长的一段时间内维持其自身状态.:

Resumed

   在这种状态下,活动是前台的,并且用户可以与他进行交互.(有时也被称为”运行”状态.)

Paused

   在这种状态下,活动被另一个活动部分遮盖,新活动在前台是半透明的或者没有完全覆盖整个屏幕.暂停的活动不接收用户输入并不能执行任何代码.

Stopped

   在这种状态下,该活动是完全隐藏的,而不是对用户可见的,它被认为是在背景中.虽然停了下来,活动实例及其所有状态信息,如成员变量,都被保留,但是它不能执行任何代码.

其它状态(Createdand Started)是短暂的,系统将通过调用下一个生命周期回调方法从当前状态迅速切换到下一个状态.也就是说,在系统调用onCreate()后,它很快调用onStart(),接着很快调用onResume().

 

指定你的应用程序的启动Activity

当用户从主屏幕选择你的应用程序图标时,系统调用Activity中的onCreate()函数,这个Activity是你在程序中定义为”Launcher”(或”main”)的Activity,这是Activity的主要切入点,并作为你的应用程序的用户界面.

你可以在Android的manifest文件中定义哪个Activity为主要的Activity,manifest.xml文件在你项目的根目录下.

你必须在你的应用程序中定义主要的Activity,方法是给这个Activity添加一个<intent-filter>,它包含MAIN的行为和LAUNCHER的属性.例如:

<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>

注意:当你通过ADT(Android SDK Tools)创建一个新的Android工程时,默认的项目文件中已经包括一个声明好过滤器的Activity.

 

如果不在你的manifest.xml文件中定义一个主要的Activity,那么你的应用程序的图标将不会出现在主屏幕的应用程序列表中.

 

 

创建一个新的实例

大多数应用程序包括几个不同的Activity,以允许用户执行不同的操作,不管Activity是用户触摸主屏幕图标启动的主要Activity,还是在你的应用程序里回应用户动作开始的Activity,系统都是通过调用Activity的onCreate()函数来创建Activity的新实例.

 

你必须实现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,防止就得系统在Android2.0(API 5)版本使用新的API,新的API只能在高版本中使用,确保应用程序正常运行.

 

当onCreate()方法执行完毕后,系统快速而连续的调用onStart()和onResume()方法.你的Activity不会停留在创建或者启动状态.从技术上来说,当onStart()被调用时,Activity已经对用户可见,紧接着onResume()被调用,并驻留在这个状态,直到某些事情发生,如收到一个电话,用户切换到其它的Activity,或者屏幕被关闭.

 

在接下里的其它课程中,你将了解到,当一个Activity从暂停状态或停止状态恢复时,在它的生命周期中,其它的启动方法onStart()和onResume()是十分有用的.

 

注:onCreate()方法包含一个叫savedInstanceState的参数,将在后续的重新创建Activity中讨论.



图2.另一个示例强调Activity生命周期结构的三个主要回调方法,即是系统创建Activity的新实例时序列的调用的onCreate(),onStart()和onResume()

当这一系列回调完成,Activity处于Resumed状态,此时用户可以与Activity进行交互直到切换到其它Activity.

 

 

销毁Activity

Activity生命周期的第一个回调函数是onCreate(),最后一个是onDestroy().系统将这个方法作为最终的信号,这样,你Activity的实例将被完全从系统内存中移除.

大多数应用程序并不需要实现这个方法,因为本地类得应用和Activity一起被销毁了,而你的Activity应该在onPause()和onStop()方法中做了大多数的清理工作.然而,如果你的Activity在onCreate()中创建了后台线程或者其它会长时间运行的资源,可能会造成内存泄露,所以,你应该在onDestroy()中结束它们.

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

注:几乎在所有情况下,当已经调用了onPause()和onStop()后,系统调用onDestroy()方法,除非你在onCreate()方法中调用finish()方法.在某些情况下,比如当前Activity只是为了启动另一个Activity临时存在,你应该在onCreate()中调用finish()来销毁它.这种情况下,系统会直接调用onDestroy()而不再调用其它任何生命周期方法.

 

 

暂停和恢复Activity

在正常使用应用程序时,前台Activity有时会被其它可视组件所遮盖,从而引起该Activity的暂停.例如,当打开一个半透明的Activity(如在一个对话框样式的Activity),之前的Activity暂停.只要Activity仍然是部分可见的,且其失去焦点,那么他一直暂停.

 

然而,一旦Activity被完全遮盖变为不可见,那么他停止(下一课讨论).

 

当你的Activity进入暂停状态,系统会调用Activity的onPause()方法.从而使你可以停止那些在暂停状态下不应该继续的行为(例如一个视频)或者其它任何应该永久保存的信息,防止用户在这种状态下离开你的应用.如果用户从暂停状态回到这个Activity,系统恢复这个Activity并调用onResume()方法.

 

注意:当你的Activity因为一个电话而进入暂停状态,它可能是一个迹象表明这个Activity只是被暂停一会儿,用户会很快回到你的Activity.然而,它通常第一个意味着用户离开你的Activity.

图1.当一个半透明的Activity遮盖你的当前的Activity,系统调用当前Activity的onPause()方法,当前Activity进入暂停状态(1)并等待.如果用户返回之前的Activity并且这个Activity是暂停状态,系统调用onResume()方法(2).

 

 

暂停你的Activity

当系统调用你Activity的onPause()方法,按理来说是你的Activity一直处于部分可见状态,但是大多数情况下,它表明用户离开这个Activity,Activity

很快会进入停止状态.通常你应该使用onPause()回调:

停止动画或者其它可能消耗CPU的行为

提交未保存的更改,用户可能希望在他们离开的时候永久的保存这些更改(如电子邮件草稿).

释放系统资源,如广播接收器,传感器(如GPS),或者任何在你暂停状态消耗电池寿命并且用户不需要的资源

 

例如,你的应用程序使用了相机,onPause()方法中是个释放它的好地方.

@Override
public void onPause(){
    super.onPause();  // Always call the superclass method first

    // Release the Camera because we don't need it whenpaused
    // and other activities might need to use it.
    if (mCamera!= null){
        mCamera.release()
        mCamera = null;
    }
}

一般情况下,你不应该在onPause()中永久保存用户的更改(如表格中的个人信息). 例外的情况是你确定用户的确是希望改变被自动保存(如起草一份电子邮件).然而,你不应该在onPause()中执行十分消耗CPU资源的操作,如写入数据库,因为它会显示的减缓过渡到下一个Activity(你应该在onStop()中执行这些操作).

 

你应该保证onPause()中的操作是简单的,这样是为了快速过渡到用户希望的下一个目标,实际上你的Activity是将被停止的.

注:当你的Activity被暂停,它的实例将驻留在内存中并在恢复的时候被调用.你不需要重新初始化在其它在其它状态下创建的组件.

 

 

恢复你的Activity

当用户从暂停状态恢复你的Activity,系统调用onResume()方法.

 

注意:系统在每次你的Activity变成前台时都会调用这个方法,包括第一次创建时.因此,你应该实现onResume()方法来初始化在onPause()阶段释放的资源,并且在执行在Activity每次进入恢复状态都必须的任何其它初始化(例如开始动画或者只在Activity获得焦点时才使用的组件).

 

下面是onResume的对应上诉的例子,关于初始化相机并在Activity暂停时释放.

@Override
public void onResume(){
    super.onResume();  // Always call the superclass method first

    // Get the Camera instance as the activity achieves fulluser focus
    if (mCamera== null){
        initializeCamera(); // Local method to handle camera init
    }
}

停止和重新启动Activity

为了确保你的用户感知你的应用程序一直活着并且不丢失他们的进度,停止和重启在Activity的生命周期中显得十分重要.在几个关键场景中,你的Activity停止并重新启动.

l  用户通过最近打开应用程序列表窗口,从你的应用程序切换到另一个应用程序.你的应用程序中的前台Activity会停止.如果用户通过主屏幕图标或最近打开程序列表窗口返回你的应用程序,Activity被重启.

l  用户在你的应用程序中开启了一个新的Activity.创建第二个Activity时,当前Activity停止.如果用户按下返回键,那么第一个Activity重启.

l  用户在使用你的应用程序时接到一个电话

 

Activity类提供两个生命周期方法,onStop()和onRestart(),允许你指定你的Activity在进入停止和重启时做相应的处理.不像暂停状态标识UI的部分被遮盖,停止状态,保证了用户界面是不可见的,用户的焦点在一个单独的Activity(或者一个完全独立的应用程序).

 

注:因为系统在Activity处于停止状态时保留Activity实例占据的内存.你可能不需要实现onStop()和onRestart()方法(或甚至是onStart()).大多数的Activity比较简单,仅仅可能需要onPause()来暂停将会继续的行为和释放系统资源.

图1.当用户离开你的Activity时,系统调用onStop()来停止activity(1).如果用户在activity停止时返回,系统调用onRestart()(2),并快速的调用onStart()(3)和onResume()(4).注意,不管什么情况下造成Activity停止,系统总是先调用onStop()之前调用onPause().

停止你的Activity

当你的Activity因为接到一个电话而进入到onStop()方法,Activity不再可见,你应当释放几乎所有不需要的资源,因为用户不再使用它.一旦你的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恢复时被重新调用.你不需要重新初始化在任何其它回调方法中创建的组件.系统还对当前状态下布局中的视图的状态进行跟踪,所以如果用户输入一个文本到EditText控件中,系统自动为你保存内容,这样你就不需要保存和恢复它.

 

注:即使系统在你的Activity停止后销毁它,系统仍然在一个Bundle(一种键值对存储结构)中保存了视图对象的状态(例如EditText中的文本),当用户切回到相同的Activity实例,系统会恢复这些状态(相关内容将会在下一课中讲到).

 

 

启动/重新启动你的Activity

当你的Activity从停止状态回到前台,系统还在每一次你的Activity变得可见时调用onStart()方法(不管是重启还是第一次启动).但是,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,它会调用onDestroy()方法.因为你一般应该在onStop()方法中释放你大多数的资源.当你收到一个电话而调用onDestroy()时,并没有太多东西需要你的应用程序去做.onDestroy()方法是你最后的机会来清理掉资源以防止内存泄露.所以,你应该确保条件执行的线程被销毁,同时其它长时间进行的行为如方法追踪也被停止.

重新创建Activity

在一些场景中,你的Activity被一些正常的应用行为所销毁,比如当用户按下返回键或者activity通过finish()发送销毁自己的信号.系统也可能在你的Activity长时间没有使用且处于停止状态时销毁你的Activity,或者前台程序需要更多资源导致系统必须关闭后台进程来提供内存.

当你的Activity应为用户按下返回键或者自身调用finish()而被销毁时从系统的角度出发,Activity的实例已经不再存在了,因为该行为表明这个Activity已经不再被需要.然而,如果由于系统自身限制而销毁Activity(非正常的程序行为),尽管真实的Activity已经不存在了,系统仍然会保留它的信息.如果用户切回到这个程序,系统将使用之前它onDestroy()状态下保存的信息为Activity创建一个新的实例.系统为恢复之前的状态而保存的数据称为”instance state”,这是一个通过Bundle对象保存的键值对集合.

 

注意:每次你旋转屏幕的时候,你的Activity都会被销毁.当屏幕改变方向,系统销毁并重新创建前台Activity,因为屏幕配置改变了,你的Activity可能需要加载替代资源(如布局).

默认情况下,系统使用Bundle实例状态来保存你Activity布局中每个视图对象的状态(如EditText中被输入的文本).所以,如果你的Activity被销毁并重新创建,你不需要任何代码就能通过系统为你保存的数据恢复到之前的状态.但是,你可能需要保存一些自定义的状态,例如一个保存用户在Activity中进度的成员变量.

 

注:为了Android系统能够恢复你Activity中视图的状态,每一个视图都必须在android:id属性中拥有独一无二的ID.

 

为了存储更多的活动状态的数据,你必须重载onSaveInstanceState()这个回调方法.当用户离开你的Activity,系统调用这个方法并将数据传递给Bundle对象,这样即使Activity被意外的销毁,数据也得以保存.如果系统之后必须重建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);}

注意:通常调用用父类的实现,默认可以保存视图的层次结构信息.

 

 

 

恢复你的Activity状态

当你的Activity在之前的销毁后重建,系统将通过Bundle保存的状态传递给你的Activity.onCreate()和onRestoreInstanceState()方法都会的到含有相同实例状态信息的Bundle.

 

因为不管是系统创建Activity的实例还是重建之前的,都会调用onCreate()方法,所以,在你尝试读取Bundle时,你必须检查Bundle是否为空.如果它是空的,那么系统创建的是一个新的实例,而不是恢复之前那个被销毁的.

 

例如,你如何通过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    }    ...}

除了在onCreate()中,你还可以实现onRestoreInstanceState()方法,系统会在onStart()后调用它.系统只在有状态数据需要恢复时才调用onrestoreInstanceState()方法,所以你不需要检查Bundle是否为空:

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);}

注意:通常调用用父类的实现,默认可以保存视图的层次结构信息.


0 0