`

Getting Started-----Managing the Activity Lifecycle

 
阅读更多

          作为一个用户,在你的app里不同的页面和前后台切换时,你的app里的Activity实例在它的生命周期的不同状态间切换。例如,当你的activity第一次启动时,它处于系统前台,接受用户焦点。在这处理之间,Android系统调用一系列Activity上生命周期方法,在这些方法里,你可以设置用户界面和初始化其他的组件。如果用户执行一个开启另一个Activity或者切换到其他app的操作,这是当当前activity切换到后台时(activity对用户不再可见,但是实例和它的状态仍然是原封不动的),系统调用另外的一系列的生命周期方法。

       在生命周期回调方法里,你能声明当用户离开和再次进入该activity的行为和操作。例如,如果你正在构建一个流视频播放器,当用户切换到另一个app时,你可能要暂停视频,并中断网络连接。当用户返回时,你能重新连接网络,并允许用户在相同点恢复视频播放。

        本文解释了Activity实例重要的生命周期回调方法。也告诉你如何使用这些方法来达到用户期望的操作和行为,同时如何在Activity不需要它们时不消耗系统资源。

 

          Lessons

          Starting an Activity

                      Learn the basics about the activity lifecycle, how the user can launch your app, and  how to perform basic activity creation.

           Pausing and Resuming an Activity

                      Learn what happens when your activity is paused (partially obscured) and resumed  and what you should do during these state changes.

          Stopping and Restarting an Activity

                   Learn what happens when the user completely leaves your activity and returns to it.

          Recreating an Activity

                    Learn what happens when your activity is destroyed and how you can rebuild the activity state when necessary.

 

        

         Starting an Activity

           不像其他的编程学科形态,应用从一个main()方法开始,Android系统的开始代码在一个Activity实例里。 通过调用相应的activity生命周期状态的特点回调方法启动。有一些列的开启activity的回调方法,同时也有一些列的销毁activity的回调方法。

        本文总体介绍了activity最重要的生命周期方法,告诉你怎么处理第一个用于产生一个新的activity的生命周期回调。

        

        Understand the Lifecycle Callbacks

        整个Activity的生命周期里,系统会调用类似于金字塔的一系列核心的生命周期方法。当系统产生一个新的activity实例时,系统会调用每一个回调方法,activty的状态也会一步一步由底向上推进。这金字塔的顶部是activity正运行的前台的那点,用户能和该activity交互。

        当用户开始离开该activity时,系统调用回调一系列其他的方法从金字塔顶部到底部一步一步移动activity的状态,从而销毁一个activity。一些情况下,activity并不完全移到金字塔底的状态,而是等待(例如当用户切换到其他app时),从而在移会到金字塔顶的状态(如果用户返回该activity),恢复到用户离开时的状态。

        

 Figure 1. A simplified illustration of the Activity lifecycle, expressed as a step pyramid. This shows how, for every callback used to take the activity a step toward the Resumed state at the top, there's a callback method that takes the activity a step down. The activity can also return to the resumed state from the Paused and Stopped state.

 

          是否需要实现所有的生命周期方法取决于你的activity的复杂性。然而,理解每一个生命周期方法并实现必要的生命周期方法时重要的。合理的实现activity生命周期方法能确保你的app行为在如下几个方面表现很好:

  • 当用户接电话或者切换到另一个app时不至于crash。
  • 当用户不使用该activity时,不占用有价值的系统资源
  • 当用户离开你的app,以后返回后,不丢失用户工作
  • 当横竖屏切换时,不crash或者不丢失用户工作

 

        本文将告诉你activity在如上图1中的不同状态切换的一些场景。然而,这些状态中,仅仅有3个是静态的。那即是,activity仅仅能在这三个状态时长时间存在:

        Resumed

              在该状态,activty处在前台,用户能和它交互。(有时也称为“running"状态)。

        Paused

              在该状态,activity是部分可见的,一部分被另一个activity遮挡——其他的activity在前台,是半透明            的,或者并没有完全覆盖整个屏幕。处于暂停状态的activity不会收到用户输入,也不能执行任何代码。

       Stopped

             在该状态,activity被完全的隐藏,对用户不可见;被认为是在后台。当处在该状态时,activity实例和它的所有的状态信息,例如成员变量等将被保持,但是也不能执行任何代码。

 

        其他的状态(Created和Started)是短暂的、非持久化的,系统会回调下一个生命周期方法很快的从这两个状态移到下一个状态。即:系统调用完onCreate()方法后,很快的调用onStart()方法,接着又很快的调用的onResume().

        这是最基本的activity生命周期。下面将讲述一些状态里该进行的生命周期行为。

 

        Specify Your App’s Launcher Activity

        当用户从手机的Home屏幕选择你的app时,系统会调用你的app里被声明为”launcher“(或者”main“)的activity的onCreate()方法。该Activity作为进入你的app用户界面的主入口。

        你的app的主Activity必须在manifest文件里声明。主activity的声明必须包含一个<intent-filter>元素,该元素里包含 MAIN action和 LAUNCHER category,例如:    
<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工程时,默认的会指定一个主activity
        Create a New Instance
        一般地,app都包含处理用户不同的action的一系列的activity。不管这些activity是不是主activity,系统都通过调用onCreate()方法产生Activity的实例。
        你必须实现onCreate方法执行基本的app开始逻辑。这些逻辑应该仅仅在activity的整个生命周期里发生一次。例如,你的Oncreate()实现应该定义用户界面,同时可能实现类范围的类变量。
       例如,下面的onCreate()方法代码例子执行了基本的activity的setup,例如声明用户界面(被定义在XML布局文件里)、定义成员变量和配置UI
       
TextView mTextView; // Member variable for text view in the layout

@Override
public 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能防止旧版本上运行新的API。但SDK_INT从Android 2.0(API 5)才出现。旧版本使用将产生runtime异常。
        一旦OnCreate()执行完成,系统很快的接着连续调用onStart()和OnResume()方法。你的Activity将重不可能停留在Created或者Started状态。学术上,当OnStart()调用后,activity变得对用户可见,但很快的OnResume()方法被调用,activity停留在Resumed状态,直到其他的改变发生,例如,接到一个来电,用户切换到其他的activity的,或者设置黑屏。
      注:OnCreate方法有一个参数:savedInstanceState。这将在后面的章节Recreating an Activity里讨论
     

 Figure 2. Another illustration of the activity lifecycle structure with an emphasis on the three main callbacks that the system calls in sequence when creating a new instance of the activity: onCreate()onStart(), and onResume(). Once this sequence of callbacks complete, the activity reaches the Resumed state where users can interact with the activity until they switch to a different activity.
 

             Destroy the Activity

 

             当activity的第一个生命周期回调方法时onCreate(),它对应的最后一个回调是onDestroy()。系统调用onDestroy()方法作为activity完全消耗的标志。那即意思,Activity正完全地从系统内存中移除。
            大多数应用不需要实现onDestroy()方法,因为本地类引用(Activity里的类)随着Activity一起被消耗,你的Activity应该在onPause()和onStop()里执行大部分的cleanup工作。然而,如果你的activity在onCreate()期间有你产生的后台线程,或者其他的长时间运行的资源,这些线程或者资源如果不合适的关闭可能存在潜在的内存泄露,你应该在onDestroy里kill它们。
        
@Override
public 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方法,而没有调用任何其他的生命周期方法
              

      Pausing and Resuming an Activity

        正常的app使用期间,前台activity可能被其他的可见组件遮挡,这引起activity暂停。例如,当一个半透明activity打开时(例如一个dialog样式的activity),前一个activity暂停。只要activity是部分的可见但是当前的activity失去焦点,activity仍然处在暂停状态。

        然而,一旦activity是完全的遮挡并且不可见,activity停止(这将在下一节讨论)。

        当你的activity进入暂停状态,系统调用onPause()方法,该方法允许你的停止正在进行的行为(日例如播放视频),或者在该方法里保存需要持久化保存的信息,以防用户继续退出你的app。如果用户从暂停状态返回到你的activity,系统恢复它,调用onResume()方法。 

        注:当你的activity收到onPause()方法调用的通知时,这可以认为是activity将暂停一会的迹象,用户可能返回到activity聚焦。然后,activity的onPause()方法调用时,我们首先更应该认为是用户将退出该activity。

        

 Figure 1. When a semi-transparent activity obscures your activity, the system calls onPause() and the activity waits in the Paused state (1). If the user returns to the activity while it's still paused, the system calls onResume() (2).

 

        Pause Your Activity  

        当系统调用onPause()方法时,理论上,你的acitivity的仍然是部分可见的,当时通常下情况下,我们认为这是用户即将要离开该activity马上进入Stopped状态的迹象。你通常应该在onPause()回调里做如下工作:

  • 停止动画或者其他正在进行的消耗CPU的action。    
  •  提交没有保存的改变,这些改变用户可能期望当他们退出activity时被永久保存(例如,一封email草稿)。
  • 释放系统资源,例如广播接收者、处理传感器资源(例如GPS) ,或者任何可能影响电量的资源。或者任何activity暂停而用户不需要的资源。

        例如,如果你的app使用Camera,onPause()是释放它的好地方。
       

@Override
public 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()方法里持久化用户改变到持久化存储的时刻是当特定用户需要在退出activity时能自动保存(例如当写emails草稿时)。然而,你应该避免在onPause()里执行耗时操作,例如写数据库。因为,应该这可能会放慢到下一activity的可见转换(你应该将这些重负载的关闭操作放在onStop方法里执行)。

        当你的activity是正在stop时,为了能快速的切换到用户的下一个目的地,你应该总是在onPause()方法里执行相对简单和少的操作。

        注:当你的activity是paused状态时,Activity实例被保留在内存,当Activity被恢复时,会被重新调用。你不需要重新初始化在Resunmed状态之前的生命周期回调方法里产生的组件。

 

        Resume Your Activity

        当用户从Paused状态返回到Paused状态时,系统调用onResume()方法。

       注意在每次activity回到前台时,包括该activity第一次被产生时系统都会调用该方法。例如,你应该在onResume()里初始化在那些在onPause()方法里释放的资源,或者其他需要每次在onResume里初始化的操作(例如启动动画或者初始化其他当用户获取到焦点后才需要使用的组件)。

           下面的onResume()方法例子对应于上面的onPause()方法的例子,因此,它初始化在onPause方法里被释放的照相机资源:

          

@Override
public 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生命周期里一个重要的处理过程。这些能确保用户感觉你的app总是存活的,并没有失去用户工作。如下是activity是停止状态,然后重启的几个关键情境:

  •         用户打开最经的app窗口,然后从你的app切换到另外一个app。当前你的app里处在前台的activity停止。如果用户从Home屏幕的你的app的launcher图标返回到你的app页面或者最近的app窗口,activity重启。
  •       用户执行开启一个新的activity的动作。当第二个activity产生的时候,当前activity停止。如果用户点击Back按钮,第一个activity重启。
  •       当使用你的app时,突然进来一个电话。

        为了能让你在Activity停止和重启时,能进行特定的操作,activity提供了两个生命周期方法:onStop()和onRestart()。不像暂停状态表明activity页面被部分遮挡,停止状态保证UI是不再可见,用户焦点在另外一个activity(或者完全另外一个app)。
        注:当activity是停止的,系统仍然在系统内存里维持你的activity实例,可能你根本不需要实现onStop()和onRestart()方法(或者甚至onStart())。大多数情况,activity都是比较简单的,我们不需要做其他特别的处理,你可能仅仅需要重写onPause()方法暂停正在进行的操作和行为,释放系统资源。

        

 Figure 1. When the user leaves your activity, the system calls onStop() to stop the activity (1). If the user returns while the activity is stopped, the system calls onRestart() (2), quickly followed by onStart() (3) and onResume() (4). Notice that no matter what scenario causes the activity to stop, the system always calls onPause() before calling onStop().

 

        Stop Your Activity

        当你的activity调用onStop()方法时,activity将变得不可见,应该释放几乎所有的不再被需要的资源。一旦你的activity存在stopped状态,系统可能因为内存紧张消耗你的activity实例。极端的情况下,系统可能简单的杀掉你的app的进程,而没有调用activity的onDestroy()方法。因此,这时使用onStop()方法释放资源以免造成内存泄露就显得重要了。

        虽然onPause()方法在onStop()方法之前调用,你应该使用onStop()方法执行更大的、更耗CPU的shut-down操作,例如写信息到数据库。

      例如,下面是onStop()实现的例子,用于保存保存草稿到持久化存储。

       

@Override
protected 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恢复时,会重新调用。你不需要重新初始化在Resunmed状态之前的生命周期回调方法里产生的组件 。系统也保存布局里的每个view的状态track。因此,如果用户在EditText空间里键入文本,键入内容会被保持,你不要保存和恢复它们。

        注:即使当activity在停止状态被系统消耗,系统仍然维持在Bundle(key-value对象块)里的view对象的状态(例如像EditText里的文本),在用户导航回相同的activity实例时会恢复它们(下课更进一步的讨论如何使用Bundle保存其他的数据状态以免activity被消耗和重建)。

 

        Start/Restart Your Activity

        当你的activity从停止状态回到前台时,它会调用onRestart()方法。系统也会调用onStart()方法,onStart()方法在你的activity每次变得可见时都会调用(不管是重启还是第一次产生)。然而,onRestart()方法仅仅在activity从停止状态恢复时才会调用。因此你能使用该方法执行专门的重建工作。而这些工作可能是仅仅在activity先前是停止状态,而不是消耗状态才需要执行的工作。

        需要使用onRestart()方法恢复activity状态是不常见的。因为,onStop()方法本质上应该释放所有的activity资源,当activity重启时你需要再次实例化它们。然而,当activity是第一次产生时(这时不存在activity的实例),你也需要实例化它们。因为这个原因,你常常应该使用onStart()回调匹配onStop()方法,因为不管是第一次产生activity还是从停止状态重启Activity,系统都会调用onStart()方法。

        例如,因为用户离开你的app后可能经历了长时间后才返回,onStart()方法是验证要求的系统特性是否enabled的好地方:

        

@Override
protected 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"
    }
}

@Override
protected void onRestart() {
    super.onRestart();  // Always call the superclass method first
    
    // Activity being restarted from stopped state    
}

         当系统消耗你的activity时,系统调用你的activity的onDestroy()方法。因为你应该在onStop()里释放几乎所有的资源,这时,onDestroy一般都不需要进行任何特别的操作。该方法时你释放可能引起内存泄露的资源的最后机会,因此你应该确保额外的线程被消耗,其他长时间的操作像方法跟踪被停止。

 

 

 

        Recreating an Activity

        下面几个场景时,你的activity可能因为正常的用户行为你的activity可能被销毁。例如当用户按返回键或者你的activity显示的调用finish()方法析构自己时。系统也可能销毁你的activity,如果activity当前是停止状态而且很长时间没被使用或者前台activity需要更多的资源。这时系统必须关闭后台进程以释放内存。

        当你的activity因为用户点击返回按钮或者activity自己finish掉时而被销毁时,系统里activity实例的概念也将永不存在了,因为这些行为操作表明activity是不在需要了。然而,如果activity由于系统限制(相比于正常的app用户行为,例如内存紧张)而被销毁,那么虽然这事实上的activity实例已经不存在了,但当用户导航回该activity里系统会记住该activity如何存在过,系统产生一个新的activity实例,但还是使用一系列之前使用过的保存数据,这些数据描述和记录了activity被销毁前的状态。这样,用户感觉不到activity被销毁了。系统使用这些数据恢复先前的状态,这些数据被称为“instance state”,是一个存在在Bundle对象的key-value集合。

        注意:当用户旋转屏幕时activity将被销毁和重建。当屏幕变成水平时,系统销毁后重建前台activity。因为屏幕配置以改变,你的activity可能需要加载其他的资源(例如布局)。

 

        默认地,系统使用Bundle实例状态保存你的activity布局里每个view的信息(例如EditText里的文本值)。因此,如果你的activity实例被销毁和重新创建,布局状态会被恢复到它先前的状态,而你不需要写额外的代码。然而,你的activity可能需要有个更多的信息要存储,例如显示用户进度的成员变量等。

       注:因为Android系统存储你的actiivty里视图的状态,每一个view必须要有一个唯一的ID,通过android:id属性提供。

        

        为了保存其他的activity状态数据,你需要重写onSaveInstanceState()回调方法。当用户离开你的activty时会调用该方法,该方法接受Bundle对象参数,该对象将在activity不可预期消耗时被系统保存。如果以后系统必须重新创建activity实例时,系统传递相同的Bundle对象给onRestoreInstanceState()和onCreate()方法。

        

         Save Your Activity State

        当你的activity开始停止时,系统调用onSaveInstanceState()方法。这些你的activity能以键值对集合的方式保存状态信息。该方法默认的实现是保存activity里view层次的信息,例如EditText控件里的文本,或者ListView的滚动位置。

        为了保存其他的状态信息,你必须实现onSaveInstanceState()方法,加key-value对到Bundle对象里。例如:

        

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...

@Override
public 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()方法的超类实现,这样默认的实现才能保存view层次的状态。

 

        Restore Your Activity State

        当你的activity因为被消耗而重新创建时,你能从系统传递给你的activity的Bundle里恢复保存的状态。onCreate()和onRestoreInstanceState()回调方法都会收到该相同的Bundle对象。

        因为不管是activity第一次创建,还是被消耗后重新创建先前的activity实例,onCreate()方法都会被调用,你需要在使用它前检查Bundle是否为空,如果是空,系统是正在产生该activity的新的实例(即该activity之前没有被创建过),相比于恢复先前被消耗的activity。

        例如,如下是在onCreate恢复状态数据的例子:
       

@Override
protected 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()方法后调用。系统仅在有状态需要restore时调用onRestoreInstanceState(),因此,你不需要check 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);
}

         注意:总是调用父类的onRestoreInstanceState()方法,因为默认的实现为恢复view层次状态。

        

        To learn more about recreating your activity due to a restart event at runtime (such as when the screen rotates), read Handling Runtime Changes.

        

  • 大小: 67.7 KB
  • 大小: 77.1 KB
  • 大小: 73.6 KB
  • 大小: 77.9 KB
  • 大小: 42.5 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics