Android官方开发教程中文版4

更新时间:2024-01-13 14:07:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

Android官方开发教程中文版

管理Activity的生存周期

管理Activity的生存周期

当用户通过导航离开然后又返回你的App,App的Activity实例在它们的生存周期内在两个不同的状态之间转换。例如,Activity首次启动时成为系统的前台并接受用户的关注,在这个过程中,Android系统在你的Activity上调用一系列生命周期方法设置用户界面和其它组件。如果用户执行了一个启动另一个Activity或切换到其它App的动作,系统调用生命周期的其它方法把Activity移到后台(Activity不再可见,但实例和状态仍然完好无损)。

在生命周期的回调方法中,你可以定义当用户离开和重新进入Activity时,Activity的行为。例如,如果你正在创建一个流媒体视频播放器,当用户切换到其它App时,你可以暂停视频并中断网络连接。当用户返回时,你再重新连接网络并允许用户从暂停点恢复播放。

本课程解释了重要的生命周期回调方法,每个Activity实例接收和如何使用它们,使Activity执行用户期望的结果,并且当Activity不需要它们时,不会消耗系统资源。

启动Activity

不像其它编程范例由main()方法启动,Android系统在Activity中通过调用对应生命周期特定阶段的回调方法来启动代码。在启动Activity时有一系列的回调方法,销毁Activity时也有一系列的回调方法。

本节内容提供了大部分重要的生命周期方法的概览,并且展示了在创建Activity的新实例时如何处理首个生命周期的回调。

理解生命周期回调

在Activity的生存期内,系统在一个阶梯状金字塔的序列中调用核心的生命周期方法。也就是说,Activity生命周期的每一个阶段都是这个金字塔上的一个台阶。随着系统创建新的Activity实例,每个回调方法都把Activity的状态向顶部移动一步,当到达顶部时,Activity运行在前台并可以和用户交互。

当用户开始离开Activity时,系统调用其它的回调方法把Activity的状态返回到金字塔底部以消除Activity。在某些情况下,Activity仅仅移动到金字塔的中间并等待(例如用户切换到其它App),Activity可以从这里回到顶部(如果用户返回了Activity)并且从用户离开的地方恢复。

根据Activity的复杂度,你可能不需要实现所有的生命周期方法。不管怎样,重要的是你要理解每个回调方法并能实现它们,以确保你的App表现得如用户期望的那样。正确地实现Activity的生命周期方法以确保你的App在以下几个方面表现良好,包括:

? 用户在使用你的App时接到电话或切换到其它App时,不能崩溃。 ? 用户不再和App频繁交互时,不能浪费宝贵的系统资源。 ? 当用户离开App并在稍后返回时,不能丢失用户的进程。

? 当屏幕在水平和垂直方向间切换时,用户的进程不能丢失或崩溃。

在接下的课程中你将学习到,Activity在图一所示的不同状态间转换的几种情况。任何情况下,这些状态中只有三个会静止不变,也就是说,同一时间只能存在以下三个状态中的一个:

Resumed

这个状态下,Activity运行在前台,并且用户可以和它交互(有时也被称为“Running”状态)。 Paused

这个状态下,Activity被另一个Activity部分遮盖——另一个Activity运行在前台,并且背景是半透明的或者没有覆盖整个屏幕。暂停的Activity不会接收用户输入,也不会执行任何代码。 Stopped

这个状态下,Activity完全隐藏并对用户不可见,它被认为处于后台。当停止时,Activity实例以及它所有的状态信息,如成员变量仍然保持,但不会执行任何代码。 其它状态(Create和Started)非常短暂,系统通过调用下一个生命周期方法,很快从它们移动到下一个状态。也就是说,系统调用onCreate()之后,很快调用onStart(),接着又立即调用onResume()。

这就是Activity生命周期的基本知识,现在你要开始学习某些特定的生命周期行为。

图一:用阶梯状金字塔图解Activity生命周期。展示了每个回调方法是如何使Activity向顶部的Resume状态靠近,还有把Activity带回到底部的回调方法。Activity也可以从Paused和Stopped状态回到Resumed状态。

指定你的App的启动Activity

当用户从Home屏幕上选择你的App图标时,系统在App内为你声明的“执行”(或“主”)Activity调用onCreate()方法。这是你的App用户界面的主入口点。

你可以在Android清单文件中声明哪个Activity成为你的主Activity,AndroidManifest.xml文件在你的项目根目录中。

App的主Activity必须在清单文件的中定义,包含值为MAIN的action和值为LAUNCHAR的category属性,如:

注意:当你使用Android SDK工具创建Android项目时,默认的项目文件就包括一个用这个过滤器(filter)声明在清单文件中的Activity类。

如果你所有的Activity都没有包含值为MAIN的action和值为LAUNCHAR的category属性,那么你的App图标不会出现在Home屏幕的App列表中。

创建新实例

大多数App都包含了几个Activity以允许执行不同的操作。无论是由用户点击App图标时创建的主Activity,还是你的App在响应用户操作时启动的Activity,系统都会调用onCreate()方法创建Activity的实例。

你必须实现onCreate()方法来执行基本的应用程序启动逻辑,这些逻辑在Activity的整个生存期内只会发生一次。比如,你的onCreate()方法应该定义用户界面和实例化某些类变量。

下例演示了为Activity执行某些基本设置的部分代码,如定义用户界面(在XML布局文件中声明),声明成员变量以及配置某些UI。

TextView mTextView; // 布局中文本视图的成员变量

@Override

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

//为当前Activity设置用户界面

// 布局文件定义在项目的res/layout/main_activity.xml 文件中 setContentView(R.layout.main_activity);

// 初始化TextView成员,这样我们可以在后面操作它 mTextView = (TextView) findViewById(R.id.text_message);

// 确保我们运行在Honeycomb或更高版本下,以便使用操作栏API if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // 对主Activity,确保App的图标在操作栏中 // 不要看起来象个按纽

ActionBar actionBar = getActionBar(); actionBar.setHomeButtonEnabled(false); }

}

警告:用SDK_INT这种方式来防止旧系统执行新的API仅在Android2.0(API级别5)或更高版本下有效,旧版本这样做将会产生一个运行时异常。

一旦onCreate()执行完毕,系统会紧接着调用onStart()和onResume()方法,你的Activity永远都不会停留在Created或Started状态。从技术上说,当调用onStart()时,Activity就对用户可见,但onResume()会紧跟着被调用,Activity将保持在Resume状态直到某些事情改变它。比如收到一个电话,用户导航到其它Activity,或者设备屏幕关闭。

在接下来的课程中,你将看到其它启动方法:onStart()和onResume()在Activity从Paused和Stopped状态中恢复时是如何使用的。

注意:onCreate()方法有一个参数savedInstanceState,我们将在稍后的课程“重建Activity”中讨论它。

图二,另一张Activity生命周期结构的图解,当创建Activity新实例时,系统按顺序调用三个主要回调方法:onCreate(),onStart()以及onResume()。一旦这个回调系列的调用完成,Activity将到达Resume状态,用户可以和它交互,直到用户切换到不同的Activity。 销毁Activity

Activity的第一个生命周期回调方法是onCreate(),最后一个生命周期回调方法是onDestroy()。系统调用onDestroy()方法标识着你的Activity从系统内存中完全移除。

大部分App不需要实现这个方法,因为本地类的引用会随Activity一起被销毁,你的Activity应该在onPause()和onStop()中执行大部分的清理。无论如何,如果你的Activity包含了在onCreate()中创建的后台线程或其它长期资源,没有正确关闭的话可能会造成内存泄漏,你应该在onDestroy()中终止它们。

@Override

public void onDestroy() {

super.onDestroy(); // 首先调用基类方法

//停止在onCreate()中开始的对方法的跟踪 android.os.Debug.stopMethodTracing(); }

注意:系统会在任何情况下调用onPause()和onStop()方法后调用onDestroy(),只有一种情况除外:在onCreate()方法内调用了finish()方法。在某些情况下,例如你的Activity临时决定启动另一个Activity,你可以从onCreate()方法内调用finish()以销毁Activity。在这个案例中,系统会在不调用其它任何生命周期方法的情况下立即调用onDestroy()方法。

暂停及恢复Activity

在App正常使用的情况下,有时候前台Activity会被其它可视组件遮挡从而导致Activity暂停。比如一个半透明的Activity(如对话框风格之类的)打开时,之前的Activity会暂停。虽然这个Activity有部分可见,但它当前没有拥有焦点,所以保持在暂停状态。

不管怎样,一旦Activity被全部遮挡而不可见时,它将停止(我们在下一节中讨论)。 Activity进入暂停状态时,系统会调用onPause()方法,以允许你停止正在进行的行为,暂停点(如视频)或任何存留的信息都应该被持久保存以防止用户继续离开你的App。如果用户从暂停状态返回到Activity,系统恢复它并调用onResume()方法。

注意:当Activity收到onPause()的调用,它可能标识着你的Activity将会暂停,然后用户可能会把焦点返回到你的Activity。不管怎样,这通常都是用户离开App的第一个迹象。

当一个半透明Activity遮挡你的Activity时,系统调用onPause()方法并且Activity在暂停状态等待(1),如果用户在仍然暂停时返回Activity,系统将调用onResume()(2)。

暂停Activity

当系统为你的Activity调用onPause()时,技术上意味着你的Activity仍然有部分可见。但更多情况下表示用户正在离开这个Activity,并且Activity将很快进入停止状态。你应该在onPause()回调方法中做到:

? 停止动画或其它消耗CPU的行为。 ? 提交未保存的改变,但只有当用户希望这个改变被持久保存时才这么做(比如一个

Email的草稿)。

? 当Activity暂停并且用户不再需要它们时,释放系统资源。比如广播接收器、对传

感器的操作(GPS之类)或者任何影响电池寿命的资源。

例如,你的应用程序使用了照相机,onPause()方法是释放它的好地方: @Override

public void onPause() {

super.onPause(); //首先调用基类方法

// 释放照相机,因为暂停时我们不需要它 // 而其它Activity可能会使用它 if (mCamera != null) { mCamera.release() mCamera = null; } }

通常情况下,你不应该在onPause()方法中把用户的改变持久保存(比如登录到表单中的个人信息)。只有你确信用户希望这些改变会自动保存时(比如Email草稿),才在onPause()方法中把用户的改变持久储存。任何情况下,你都应该避免在onPause()中执行增加CPU负担的工作,比如写入数据库,因为这可能会使过渡到下一个Activity变得迟缓(你应该在onStop()的关闭操作中执行繁重的工作)。

如果你的Activity被停止了,你应该在onPause()方法中保持操作完成的数量,以允许快速过渡到用户的下一个目标。

注意:当Activity暂停时,Activity实例仍然驻留在内存中并在恢复时重新使用,你不需要重新初始化在Resume状态之前被回调方法创建的组件。

恢复Activity

当Activity从暂停状态中恢复时,系统会调用onResume()方法。

请注意,每当你的Activity进入前台,系统就会调用这个方法,包括它首次被创建时。这样一来,你应该实现onResume()方法来初始化在onPause()方法中释放的组件,以及执行其它在Activity每次进入Resume状态时必须发生的初始化工作(比如开始动画以及初始化仅在用户拥有焦点时用到的组件)。

下面onResume()的示例对应上面的onPause()示例,它初始化了在Activity暂停时释放的照相机。

@Override

public void onResume() {

super.onResume(); //首先调用基类方法

// 当Activity获得用户焦点时得到照相机的实例 if (mCamera == null) {

initializeCamera(); // 对照相机初始化的本地方法 } }

停止和重新启动Activity

在Activity生存周期内正确地停止和重启Activity是一个重要的步骤,它可以确保用户意识到App一直存活并且他们的进度没有丢失。以下几个关键场景中,Activity会停止和重启:

? 用户打开一个新的App窗口,以及从你的App切换到另一个App,你的App中当

前处于前台的Activity被停止。如果用户在“Home”屏幕中执行App图标或从新

App窗口中返回到你的App,Activity重新启动。

? 用户在你的App中执行某个操作启动一个新Activity,当第二个Activity被创建时,

当前Activity停止。如果用户按下“Back”按纽,第一个Activity重新启动。 ? 用户在手机上使用App时,接到电话。 Activity类提供了两个生命周期方法:onStop和onRestart(),它们允许你专门处理Activity的停止和重新启动。不像暂停状态只有部分UI被遮挡,停止状态确保UI不可见,并且用户的焦点处于不同的Activity(或完全不同的App)。

注意:因为Acctivity停止时,系统仍然会把它保留在内存中,你也许不需要在任何情况下都实现onStop(),onRestart()(或onStart())方法。对大部分Activity来说,简单地停止并重启就行了,你只需要在onPause()中暂停正在进行的操作以及断开和系统资源的连接。

当用户离开Activity时,系统调用onStop()停止Activity(1),如果用户从停止中返回,系统调用onRestart()(2),紧接着调用onStart()(3)和onResume()(4)。注意,不管什么情况导致Activity停止,系统都会在调用onStop()之前调用onPause()。

停止Activity

当Activity收到onStop()方法的调用时,它变得不可见并且释放几乎所有不再使用的资

源。Activity一旦停止,如果需要释放内存,系统可能会销毁它的实例。在极端情况下,系统可能简单地杀掉App的进程而不调用onDestroy()。因此,在可能存在内存泄漏的情况下,使用onStop()释放资源非常重要。

虽然onPause()在onStop()之前调用,你应该在onStop()中执行那行更大、更占CPU资源的关闭操作,例如把信息写入数据库。

下面是一个在onStop()中把便笺的草稿内容持久化保存的例子: @Override

protected void onStop() {

super.onStop(); //首先调用基类方法

// 保存便笺当前的草稿,因为Activity正在停止 // 我们不希望当前便笺的进度被丢失

ContentValues values = new ContentValues();

values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());

values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());

getContentResolver().update(

mUri, // 要更新的便笺的URI

values, // 列名映射以及应用到上面的新值 null, // 未使用SELECT参数 null // 未使用WHERE参数 ); }

当Activity停止时,Activity实例仍然驻留在内存中并在恢复时重新使用,你不需要重新初始化在Resume状态之前被回调方法创建的组件。系统会对布局中的每个视图保持跟踪,如果用户在一个EditText部件中输入了文本,文本将会被保留,所以你不需要保存和恢复它。

注意:即使系统在Activity停止时把它销毁,视图对象(如EditText中的文本)的状态仍然保留在Bundle(键值对中的一个)中,并且在用户返回到Activity同一个实例时恢复它们(下一节讨论更多关于使用Bundle保存其它状态数据以防止Activity被销毁和重建的内容)。

启动/重新启动Activity

Activity从停止状态返回到前台时会调用onRestart()。每当Activity成为可见时,系统都会调用onStart()方法(whether being restarted or created for the first time),只有Activity从停止状态中恢复时才会调用onRestart()方法,如果Activity只是被停止而没有被销毁,你可能有必要在onRestart()方法中执行一些特殊的恢复工作。

App使用onRestart()恢复Activity状态的情况很少见,因此对这种应用方式没有任何指南。因为在onStop()方法中清除了Activity的所有资源,所以你需要在Activity重新启动时重新初始化它们。另外,Activity首次创建时,你也需要实例化这些资源(当它们在Activity实例中还不存在时)。基于此,你应该用onStart()方法来对应onStop()方法,因为系统在创建Activity和从停止状态中恢复Activity时都会调用onStart()方法。

例如,在返回App之前,用户可能已经离开很长时间了,onStart()方法是一个用来验证所需的系统功能是否还允许的好地方。

@Override

protected void onStart() {

super.onStart(); //首先调用基类方法

// Activity可能是首次启动或重新启动 // 我们应该确保GPS功能已经启用 LocationManager locationManager =

(LocationManager) getSystemService(Context.LOCATION_SERVICE); boolean gpsEnabled = locationManager

.isProviderEnabled(LocationManager.GPS_PROVIDER);

if (!gpsEnabled) {

// 创建一个对话框要求用户启用GPS,当用户点击“OK”时,

// 用 android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS操作 // 打开设置屏幕,以便用户启用GPS。 }

}

@Override

protected void onRestart() {

super.onRestart(); //首先调用基类方法

// Activity从停止状态中恢复 }

重建Ativity

某些情况下,Activity被销毁是App的正常行为。比如用户按下“Back”按纽,或是Activity明确调用finish()方法来摧毁自己。如果Activity处于停止中,并且用户很长时间都没有使用它,或是前台Activity需要更多系统资源,系统不得不关闭后台进程以恢复内存,系统也可能会销毁Activity。

当Activity因为用户按下“Back”按纽或通过finish()方法结束自己时,由于这些行为表示Activity不再需要,系统会认为Activity实例永久消失。如果Activity被系统强制(相对于App的正常行为)销毁,虽然Activity实例已经消亡,但系统会“记得”它曾经存在,如果用户导航回来,系统会使用销毁时保存的数据和状态描述来创建新的Activity。系统用来恢复之前的状态(被称为“实例状态”)的这些数据保存在Bundle对象的键值对集合中。

警告:用户每次旋转屏幕时,Activity都会被销毁并重新创建。当屏幕方向改变时,系统销毁并重建前台Activity,因为屏幕设置发生变化,而且Activity可能要加载可替换资源(如布局)。

默认情况下,系统使用Bundle实例状态保存Activity中每个视图对象的信息(如EditText对象中的文本值)。所以当Activity被销毁和重建时,不需要通过代码来恢复布局状态。Activity可以有更多你想恢复的状态信息,比如一个跟踪用户进度的成员变量。

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

要保存有关Activity状态的额外数据,你必须重写onSaveInstaneState()回调方法。当用户离开Activity时,系统调用这个方法并传递Bundle对象,在Activity被意外摧毁时保存Bundle对象。如果系统必须在稍后重建Activity实例,它会把相同的Bundle对象传递给onRestoreInstance()和onCreate()方法。

系统开始停止Activity时,它调用onSaveInstance()(1),你可以在这里指定Activity重建时需要恢

复的额外的状态数据。如果Activity被摧毁并要重建相同实例,系统会把(1)中定义的状态数据

传递给onCreate()(2)和onRestoreInstance()(3)方法。

保存Activity状态

当Activity开始停止时,系统调用onSaveInstance()方法,Activity可以使用键值对集合保存状态信息。这个方法的默认实现会保存Activity视图层次的状态信息,比如EditText的文本或ListView的滚动条位置。

要保存Activity的额外状态信息,你必须实现onSaveInstance()方法并向Bundle对象中添中键值对,例如:

static final String STATE_SCORE = \static final String STATE_LEVEL = \...

@Override

public void onSaveInstanceState(Bundle savedInstanceState) {

// 保存用户当前的游戏状态

savedInstanceState.putInt(STATE_SCORE, mCurrentScore); savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);

// 总是调用基类方法,这样它可以保存视图层次状态 super.onSaveInstanceState(savedInstanceState); }

警告:永远要调用onSaveInstance()的基类实现,默认的实现会保存视图层次的状态。

恢复Activity状态

当Activity在销毁后重建时,你可以从系统传递给Activity的Bundle中恢复保存的状态。onCreate()和onRestoreInstance()方法都会收到相同的Bundle对象,它包含实例状态信息。

因为系统创建Activity的新实例或是重建之前的Activity都会调用onCreate()方法,所以你在尝试读取Bundle对象之前必须检查它是否为null。如果为null,系统在创建新的实例,否则就是恢复之前被摧毁的Activity。

下例是如何在onCreate()中恢复某些状态数据: @Override

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 首先调用基类

// 检查是否在重建之前摧毁的实例 if (savedInstanceState != null) {

// 从保存的状态中恢复成员的值

mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); } else {

// 可能需要为新实例初始化成员的默认值 } ... }

你也可以选择实现onRestoreInstance()来替换onCreate()以恢复状态,系统会在onStart()

方法后调用它。系统仅在恢复保存的状态时才会调用onRestoreInstance()方法,所以你不需要检查Bundle对象是否为空。

public void onRestoreInstanceState(Bundle savedInstanceState) { // 总是调用基类方法,它能恢复视图层次

super.onRestoreInstanceState(savedInstanceState);

// 从保存的实例中恢复状态成员

mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); }

警告:永远要调用onRestoreInstance()的基类实现,默认的实现会恢复视图层次的状态。

学习更多有关在运行时重新启动事件中重建Activity的内容(如屏幕旋转),请参考“处理运行时的改变”。

方法后调用它。系统仅在恢复保存的状态时才会调用onRestoreInstance()方法,所以你不需要检查Bundle对象是否为空。

public void onRestoreInstanceState(Bundle savedInstanceState) { // 总是调用基类方法,它能恢复视图层次

super.onRestoreInstanceState(savedInstanceState);

// 从保存的实例中恢复状态成员

mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); }

警告:永远要调用onRestoreInstance()的基类实现,默认的实现会恢复视图层次的状态。

学习更多有关在运行时重新启动事件中重建Activity的内容(如屏幕旋转),请参考“处理运行时的改变”。

本文来源:https://www.bwwdw.com/article/9k4o.html

Top