pAdTy_-7 管理活动的生命周期

来源:互联网 发布:查找数组最大值最小值 编辑:程序博客网 时间:2024/06/16 22:34

2015.10.24-10.27
个人英文阅读练习笔记(低水准)。原文地址:http://developer.android.com/training/basics/activity-lifecycle/index.html

2015.10.24
在android应用程序中,当用户由导航条进入某个活动、从此活动进入下一个活动、再回到这个活动中等过程,这个活动对象在其生命周期中具有不同的状态。例如,当活动第一次启动,活动会在系统的前景部分并接受用户的关注。在这个过程中,android系统会调用一系列的系统调用来管理活动内的用户接口(控件)及其它组件的生命周期。如果用户执行了启动另外一个活动或者转换到另外一个应用程序的动作,系统会调用另外一套声明周期方法来将之前的活动调整到后台(即活动不可见,但活动对象及其状态仍旧是完整的)。

在生命周期回调方法中,您可以定义当离开活动和重新进入活动时的行为。例如,假如您正在构建一个视屏流播放器,您可能需要在回调函数中定义视屏播放器的行为:当用户切换到其它应用时您应该要将视屏暂停并终止播放器与网络的连接;当用户切换回到播放器应用程序时,播放器重新连接到网络并且视屏还在原先暂停的时间处。

此笔记将会解释重要的生命周期回调方法,活动对象如何接收回调函数以及具体的操作。这样,就能完成用户所期望的功能,同时也能够在不需要活动时及时退出活动而不让它继续耗费系统资源。

1. 启动活动

学习关于活动生命周期的基础、用户如何启动应用程序以及基本的活动创建的运行。

不像其它应用程序模式以main()函数为入口启动程序,Android系统通过调用一个特殊的回调方法初始化代码到活动对象中,这个回调方法跟活动生命周期的每一个阶段都有关联。有一系列启动和销毁活动的回调方法。

此笔记提供最为重要的生命周期回调方法的总览,并展示如何用第一个生命周期回调方法来为活动创建一个新的对象。

(1). 理解生命周期回调方法

在活动的生命中,系统以金字塔阶梯的形式按照顺序调用一套核心的回调方法来维持各个活动生命状态。即,活动生命周期的每一个阶段在阶梯金字塔中是独立的。当系统创建了一个活动实例,此活动的回调函数将此活动的状态提升到阶梯金字塔的顶部。阶梯金字塔顶部的活动运行在前景部分即用户可以和其直接交互。

当用户开始离开活动时,系统将会调用其它方法来将活动移到阶梯金字塔下方以让此活动小时。在某些情况下,活动只会讲某些部分移到阶梯金子台之下或者只是等待(如用户切换到另外的应用程序),离开时等待的那个点可以被移到顶部(如果用户回到活动中)并且恢复离开时的状态。
这里写图片描述
图1. 活动生命周期的被表达为阶梯金字塔的简单图示。此图展示了对于每个回调方法来说如何一步一步地到达顶部的Resumed状态的,也各自有回调方法来让活动状态下降。在暂停或停止状态时活动也可以返回到恢复状态。

根据活动的复杂性,您可能并不需要实现所有的生命周期方法。但是,理解每一个回调方法及实现他们以确保应用程序行为为用户所期待是很重要的。适当的实现活动生命周期方法以让应用程序能够有以下几种行为:

  • 应用程序运行时,当用户接收到电话或者切换到另外一个应用程序时不会卡机。
  • 当用户当前没有使用应用程序时,应用程序不应该消耗系统有价值的资源。
  • 当用户离开应用程序晚些时间再回到应用程序中时不丢失用户之前的使用进度。
  • 屏幕翻转后应用程序不会卡机也不会丢失用户的使用进度。

在接下来的笔记中,将会描述活动在图1中展示的状态之间转变。但是,在这些状态中只有3种状态能是静态的。即,活动只能在以下3中状态下比较长期的存在。

恢复
在这个状态下,活动运行在前景,用户可以直接跟活动进行交互(有时候也称这种状态为运行状态)。

2015.10.25
暂停
在这个状态,活动的某一部分被另一个活动覆盖 —- 另一个运行在前景的活动是半透明的或者没有完全覆盖整个屏幕。暂停的活动不会接收用户输入也不会执行任何代码。

停止
在这个状态下,活动被完全隐藏并且对用户完全不可见,此时的它在后台。处于停止状态下的活动实例的状态信息如其内部变量都被保留着,但它不会再执行任何代码。

活动其它的状态(创建和启动)状态是瞬时的,系统会迅速调用下一个生命周期方法将活动的瞬时状态移到下一个状态。即,在系统调用onCreate()后,系统将马上调用onStart(),然后系统再度马上调用onResume()。

这就是活动生命周期的一些基本描述。接下来您将学习到一些关于特定生命周期中的一些行为。

2015.10.26

(2). 指明应用程序中的默认启动活动

当用户从屏幕上选择您的应用程序图标时,系统将会调用应用程序中被声明为”launcher(或者main)”活动中的onCreate()方法。这个活动就是应用程序图形用户接口的主活动(入口)。

您可以在工程目录下的清单文件AndrodManifest.xml文件中定义主活动。

应用程序中的主活动必须声明在包含“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>

注:用Android SDK工具创建的默认工程内,在清单文件中的过滤器标签下有一个默认活动类对应的活动被声明。

如果应用程序中无MAIN后者LAUNCHER列别的活动被声明,那么在屏幕上不会出现此应用程序的图标。

(3). 创建一个新的实例

大多数的应用程序包含不同的活动,以让用户可以做不同的操作。不管是主活动还是其它活动,当用户点击应用程序图标或者是响应用户点击活动中某处而展现新的活动时,系统都是通过调用onCreate()方法来创建活动的实例。

您必须实现onCreate()方法来决定应用程序的启动逻辑,onCreate()函数只会在活动启动时被执行一次。例如,您实现的onCreate()函数包含所定义的用户接口(xml)以及类中的一些变量。

举例,以下onCreate()方法中包含了活动的一些基本设置,具体包括声明用户接口(定义在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)及以上。旧的版本在执行SDK_INT时会发生异常。

一旦onCreate()执行完成,系统将会快速连续调用onStart()和onResume()方法。活动不会驻留在Created或者Started状态。从技术上说,在调用onStart()后用户就可见活动,但onResume()函数会被迅速调用,这样活动就停留在Resumed状态,直到有改变发生。比如当收到电话时,用户点击导航条去其它活动时,或者手机屏幕关闭时。

在紧随的其它笔记中,您将会看到其它的活动启动方法,onStart()和onResume(),这两个函数在用来从Paused或者Stopped状态恢复活动时非常有用。

注:onCreate()方法有一个名为savedInstanceState的参数,在重建活动中笔记这个参数的含义。
这里写图片描述
图2.另外一个活动生命周期的图示,此图强调在创建活动实例时被系统依次调用的3个主要回调方法:onScreate(),onStart()以及onResume()。只要这些回调方法被实现后,活动就能够到达用户能和其直接进行交互的Resumed状态,知道用户切换到其它活动。

(4). 销毁活动

活动生命周期的第一个回调方法为onCreate(),它们的最后一个回调方法为onDestroy()。系统会调用这个方法来将活动实例从内存中彻底移除。

大多数的应用程序不需要实现onDestroy()方法,因为本地包含活动对应的类引用都会被自动销毁。并且,您的活动在onPause()和onStop()阶段就应该已经做了大部分的清理工作。但是,如果您的活动包含一些在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()方法时。在这些情况中,如当您的活动被设为暂停且去启动另外一个活动时,您可能会在onCreate()中调用finish()来销毁活动。此时,系统会立即调用onDestroy()方法,而不会调用其它的生命周期函数。

2. 暂停活动 从暂停状态恢复活动

学习当活动暂停(活动的某些部分被覆盖)、从暂停中恢复时都发生了生么,以及当这些状态转变时您应该做什么。

在应用程序的正常使用中,前景活动有时候会被其它的视觉组件覆盖以至于进入暂停(pause)状态。例如,当一个半透明的活动被打开时(像对话框),之前的活动就会进入暂停状态。只要活动只有部分可见但不是聚焦的活动,这个活动仍然是暂停的。

然而,当活动完全被覆盖并且不再可见时,此活动则进入停止(stop)状态(在下一节中讨论这个话题)。

当活动进入暂停(paused)状态时,活动的系统调用onPause()方法将会得到执行,这将允许您停止暂停状态下应该停止(如视频流)的正在进行的行为,或者是当用户离开应用程序而应用程序当前进度应该保持时。当用户回到应用程序的暂停状态时,系统将会调用onResume()方法将活动至于恢复(onResume)状态。

注:当活动调用onPause()方法时,这就象征活动在用户再次返回到活动的这段期间活动处于暂停状态。然而,通常,活动处于暂停状态是因为用户离开了当前活动。
这里写图片描述
图1. 半透明活动覆盖活动,系统调用onPause()将活动置于暂停状态(1)。如果当活动处于暂停状态时用户再返回,系统将调用onResume()函数(2)。

(1). 停止活动

当系统为活动调用onPause()函数时,从技术上讲它意味着活动仍然是部分可见的,但绝大数它意味着用户离开了当前活动并且活动即将进入停止状态。您应该在onPause()函数中包含以下功能:

  • 停止动画或者其它消耗CPU的正在进行的行为。
  • 处理未经保存的改变,如用户离开活动但希望改变得到永久的保存(如草稿邮件)。
  • 释放活动处于暂停时用户不再所需的系统资源,如广播接收器、传感器手柄(如GPS)或者其它会消耗电池的资源。

例如,如果您的应用程序使用了相机,在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()方法之上,如写数据库。因为这会减慢可见部分到下一个活动(您应该在onStop()方法中来做这些耗时较多的操作)。

如果您的活动已经被停止,您应该保持在onPause()方法中的操作量的简单性,这样活动才能以一个快速的转变到用户的下一个活动。

注:当活动处于暂停状态下时,活动的实例将仍然驻留在内存中,当活动恢复时这段内存将会被重新得到访问并显示活动。您不必重新调用活动恢复之前的回调方法来重新初始化活动内的组件。

(2). 恢复活动

当用户将一个活动从暂停状态切换到恢复状态时,系统将会调用onResume()方法。

要意识到每当活动出现在前景时系统都会调用onResume()方法,包括第一次创建活动。因此,您应该在onResume()方法中初始化在onPause()期间释放的组件,以及需要初始化活动每次回到恢复状态的内容(如恢复用户之前所聚焦的组件操作)。

以下onResume()内容是与onPause()对应的例子,在其中初始化了相机相关的内容(在onPause()中被释放)。

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

3. 停止及重启活动

学习当用户完全离开您的活动后再回到其中的时候都发生了什么。

合适的停止和重启活动是活动生命周期中一个重要的过程,这会确保用户去意识您的应用程序一直都是持有活力且不会丢失他们的使用进度。以下是活动停止和重启的主要关键场景:

  • 用户打开最近应用程序窗并从您的应用程序切换到另外一个。在您应用程序中处于前景中的活动将会处于停止状态。如果用户从屏幕或者最近应用程序窗重新回到您的应用程序,活动将重启。
  • 用户在您的应用程序中开启一个新的活动。在第二个活动被创建后当前活动将会停止。如果用户按下返回按钮,第一个活动将会重启。
  • 手机用户在使用活动时收到来电。

活动的类提供了两个生命周期方法,onStop()和onRestart(),可以在这两个函数中指定活动停止和重启的具体行为。活动的暂停状态标识了一部分的UI覆盖,而在活动的停止状态下,所有的UI部分都不可见且用户聚焦到另外一个活动上(或者另外一个应用程序上)。

注:因为当活动停止时系统在内存中保留了活动的实例,您可能并不需要实现onStop()和onRestart()方法(甚至不用实现onStart()方法)。对于大多数比较简单的活动来说,就只需要用系统自带的停止和重启函数外加使用onPause()方法来暂停正在进行的行为并释放一些系统资源即可。
这里写图片描述
图1.当用户离开活动,系统调用onStop()来停止活动(1)。当用户回到已经停止的活动中时,系统调用onRestart()方法(2),紧接着调用onStart()和onResume()方法(4)。注意无论任何场景下,在调用onStop()之前都会调用onPause()。

(1). 停止活动

当对活动调用onStop()函数时,活动不再可见且应该释放用户不使用活动时的所有资源。活动一旦停止,系统若有需要覆盖系统内存时它有可能会销毁活动的实例。最极端的情况是,系统有可能在未调用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.            );}

当活动停止时,活动对象被保留在内存中,它可以回到恢复状态。您不必重新初始化从一开始到恢复状态的任何一个生命周期函数。系统为布局文件中的每个视图保持了跟踪,所以,如果用户填写了文字到编辑控件中,文字内容将会被保存,所以您不必保存和重新存储它(文字内容)。

注:即使系统在活动停止时销毁了活动,系统在Bundle(一种键值对)中仍旧保留了视图的状态(如编辑文本框中的文字内容)并且在用户重新回到活动中时重新存储它们(接下来将会更多的谈论当活动被销毁和重启时用Bundle来保存数据的其它状态)

(2). 开启/重启活动

当活动从停止状态回到前景时,会自动调用onRestart()方法。系统也会调用onStart()方法,这个方法在活动变成可见(不管是重建活动还是第一次建活动)时都会被调用。当活动从停止状态恢复时才会调用onRestart()方法,所以在活动之前被停止但没有被销毁的情况下,您可以用这个方法来进行一些特殊的必要的存储工作。

在应用程序中使用onRestart()方法来重新存储活动的状态时不常见的,对于这个方法,并没有一定的指导原则提供给应用程序开发人群。但是,因为onStop()方法将会清理掉活动中的所有资源,所以在重启活动室需要对应的重实例化一些所释放的资源。在活动第一次被创建时您同样需要实例化这些资源(当活动中没有存在的实例时)。因此,您通常需要编写和onStop()方法对应的onStart()方法,因为在创建活动或者从活动停止状态重建活动时都会调用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    }

当系统销毁活动时,系统会调用活动的onDestroy()方法。因为一般会在onStop()方法中释放大部分资源,不是所有的程序都有必要再去调用onDestroy()方法了。这个方法是清理活动资源的最后机会,这些资源主要涉及内存泄露问题,所以您应该确保在onDestroy()方法中让线程以及其它像方法跟踪这样长期运行的任务得到停止。

2015.10.27

4. 重造活动

学习当一个活动被销毁后都发生了什么,如何重建一个被销毁的活动。

有几种对应用程序的操作的场景会让活动被销毁,如在应用程序中按下了返回按钮或者活动自身调用了finish()方法。当活动处于停止状态太长时间或者前台的活动需要更多的资源时系统就会关闭处于后台下这样情况下活动来获得内存资源。

当用户按下返回按钮或者活动自身调用函数来销毁活动时,系统会认为此活动的实例将会永远消失,因为这样的操作就代表不再需要此活动的含义。但是,如果系统是因为系统约束(而不是通过正常的操作)来销毁活动,虽然活动的实例已经消失,但系统会记住它曾存在过。如此,当用户根据导航重新回到活动时系统会用此活动被销毁时所记录的数据来为此活动重新创造一个活动实例。系统存储数据之前的状态称为“实例状态”,实例状态是保存在Bundle对象中的键值对。

警告(warning):当用户旋转屏幕时,当前活动会被销毁后重建。当屏幕改变朝向时,系统会销毁前景活动并重建此活动,因为屏幕尺寸发生改变时活动需要载入其它可选的资源(如布局)。

默认情况下,系统会用Bundle实例状态来保存活动布局文件中的每个视图对象的信息(如输入到EditText对象中的文本)。所以,当活动实例被销毁且重建时,布局文件的状态会被自动存储为先前状态。但是,活动可能会有更多需要存储的状态信息,如活动中跟踪用户进度的成员变量。

注:为了在android系统中存储活动中的视图状态,每个视图都必须的ID必须唯一,这个ID由android:id指定。

若需保持活动其余的数据的信息,您必须重写onSaveInstanceState()回调方法。系统将会在用户离开活动时调用此函数,并将将会保存在记录活动意外被销毁的事件的Bundle对象传递给此函数。如果系统必须在以后重建活动实例,Bundle对象将同时被传递给onRestoreInstanceState()和onCreate()方法。
这里写图片描述
图2.系统开始停止活动时,系统调用onSaveInstanceState() (1),所以当活动实例必须被重建时您可以将其余的状态信息保存在此函数中。如果活动实例被销毁且要重建一个与之前相同的活动实例,系统将会将定义在(1)中的信息传递给onCreate() (2)和onSaveInstanceState()方法中。

(1). 保存活动状态

当活动进入停止状态时,系统会调用onSaveInstanceState(),所以您可以在此函数中通过键值对的方式保存活动的状态。此方法默认保存活动的视图层次结构,如EditText窗体部件中的文字或ListView中的进度位置。

要保存活动其余状态的信息,您必须往Bundle对象中添加键值对来实现onSaveInstanceState()方法,例如:

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

警告(warning):调用父类中的onSaveInstanceState()方法就能够保存视图的层次结构。

(2). 存储活动状态

当活动在销毁后再被重建时,您可以从系统传递给活动的Bundle对象中恢复活动的状态信息。onCreate()和onRestoreInstanceState()回调方法收到包含相同实例状态信息的同一个Bundle对象。

不管系统是创建活动的新实例还是重建实例都会调用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);}

警告(warning):调用父类中的onSaveInstanceState()方法就能够保存视图的层次结构。

更多关于运行时因某重启事件而导致活动实例重建请参考:Handling Runtime Changes.

[2015.11.11-09:27]

0 0
原创粉丝点击