安卓生命周期
摘自 google training,用于以后不用FQ随时查看
了解生命周期回调
在Activity的生命周期中,系统会按类似于阶梯金字塔的顺序调用一组核心的生命周期方法。 也就是说,Activity生命周期的每个阶段就是金字塔上的一阶。 当系统创建新Activity实例时,每个回调方法会将Activity状态向顶端移动一阶。 金字塔的顶端是Activity在前台运行并且用户可以与其交互的时间点。
当用户开始离开Activity时,系统会调用其他方法在金字塔中将Activity状态下移,从而销毁Activity。 在有些情况下,Activity将只在金字塔中部分下移并等待(比如,当用户切换到其他应用时),Activity可从该点开始移回顶端(如果用户返回到该Activity),并在用户停止的位置继续。
正确实现您的Activity生命周期方法可确保您的应用按照以下几种方式良好运行,包括:
- 如果用户在使用您的应用时接听来电或切换到另一个应用,它不会崩溃。
- 在用户未主动使用它时不会消耗宝贵的系统资源。
- 如果用户离开您的应用并稍后返回,不会丢失用户的进度。
- 当屏幕在横向和纵向之间旋转时,不会崩溃或丢失用户的进度。
Activity只能在以下三种状态之一下存在很长时间
继续:在这种状态下,Activity处于前台,且用户可以与其交互。(有时也称为“运行”状态。)
暂停:在这种状态下,Activity被在前台中处于半透明状态或者未覆盖整个屏幕的另一个Activity—部分阻挡。 暂停的Activity不会接收用户输入并且无法执行任何代码。
停止:在这种状态下,Activity被完全隐藏并且对用户不可见;它被视为处于后台。 停止时,Activity实例及其诸如成员变量等所有状态信息将保留,但它无法执行任何代码。
其他状态(“创建”和“开始”)是瞬态,系统会通过调用下一个生命周期回调方法从这些状态快速移到下一个状态。 也就是说,在系统调用 onCreate()
之后,它会快速调用 onStart()
,紧接着快速调用 onResume()
。
指定您的应用的启动器Activity
当用户从主屏幕选择您的应用图标时,系统会为您已声明为“启动器”( 或“主要”)Activity的应用中的 Activity
调用 onCreate()
方法。 这是作为 您的应用的用户界面主入口的Activity。
修改 AndroidManifest.xml
中要作为主Activity的<intent-filter>,如下
<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>
如果未对您的Activity之一声明 MAIN
操作或 LAUNCHER
类别,那么您的应用图标将不会出现在应用的主屏幕列表中。
创建Activity
系统会通过调用其 onCreate()
方法创建 Activity
的每个新实例,必须实现 onCreate()
方法执行只应在Activity整个生命周期出现一次的基本 应用启动逻辑
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //加载的XML布局 setContentView(R.layout.main_activity); //执行创建逻辑
//..
}
一旦 onCreate()
完成执行操作,系统会相继调用 onStart()
和 onResume()
方法。 您的Activity从不会驻留在“已创建”或“已开始”状态。
在技术上,Activity会在 onStart()
被调用时变得可见,但紧接着是 onResume()
,且Activity保持“继续”状态,直到有事情发生使其发生变化,比如当接听来电时,用户导航至另一个Activity,或设备屏幕关闭。
重新创建Activity
在有些情况下,您的Activity会因正常应用行为而销毁,比如当用户按 返回按钮或您的Activity通过调用 finish()
示意自己的销毁。
如果Activity当前被停止或长期未使用,或者前台Activity需要更多资源以致系统必须关闭后台进程恢复内存,系统也可能会销毁Activity。
当您的Activity因用户按了返回 或Activity自行完成而被销毁时,系统的 Activity
实例概念将永久消失,因为行为指示不再需要Activity。
但是,如果系统因系统局限性(而非正常应用行为)而销毁Activity,尽管 Activity
实际实例已不在,系统会记住其存在,这样,如果用户导航回实例,系统会使用描述Activity被销毁时状态的一组已保存数据创建Activity的新实例。
系统用于恢复先前状态的已保存数据被称为“实例状态”,并且是 Bundle
对象( onCreate()
中的参数)中存储的键值对集合。
注意:每次用户旋转屏幕时,您的Activity将被销毁并重新创建。 当屏幕方向变化时,系统会销毁并重新创建前台Activity,因为屏幕配置已更改并且您的Activity可能需要加载备用资源(比如布局)。
默认情况下,系统会使用 Bundle
实例状态保存您的Activity布局(比如,输入到 EditText
对象中的文本值)中有关每个 View
对象的信息。
这样,如果您的Activity实例被销毁并重新创建,布局状态便恢复为其先前的状态,且您无需代码。
但是,您的Activity可能具有您要恢复的更多状态信息,比如跟踪用户在Activity中进度的成员变量。
注意:为了 Android 系统恢复Activity中视图的状态,每个视图必须具有
android:id
属性提供的唯一 ID。
- 要保存有关Activity状态的其他数据,您必须替代
onSaveInstanceState()
回调方法。当用户要离开Activity并在Activity意外销毁时向其传递将保存的Bundle
对象时,系统会调用此方法。 - 如果系统必须稍后重新创建Activity实例,它会将相同的
Bundle
对象同时传递给onRestoreInstanceState()
和onCreate()
方法。
保存Activity状态
当您的Activity开始停止时,系统会调用 onSaveInstanceState()
以便您的Activity可以保存带有键值对集合的状态信息。 此方法的默认实现保存有关Activity视图层次的状态信息,例如 EditText
小工具中的文本或ListView
的滚动位置。
要保存Activity的更多状态信息,您必须实现 onSaveInstanceState()
并将键值对添加至 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()
的超类实现,以便默认实现可以保存视图层次的状态。
恢复Activity状态
当您的Activity在先前销毁之后重新创建时,您可以从系统向Activity传递的 Bundle
恢复已保存的状态。onCreate()
和 onRestoreInstanceState()
回调方法均接收包含实例状态信息的相同 Bundle
。
因为无论系统正在创建Activity的新实例还是重新创建先前的实例,都会调用 onCreate()
方法,因此您必须在尝试读取它之前检查状态 Bundle
是否为 null。 如果为 null,则系统将创建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 } ... }
您可以选择实现系统在 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); }
销毁Activity
当系统销毁您的Activity时系统会对您的Activity调用 onDestroy()
,作为您的Activity实例完全从系统内存删除的最终信号。
如果您的Activity包含您在 onCreate()
期间创建的后台线程或其他如若未正确关闭可能导致内存泄露的长期运行资源,您应在 onDestroy()
期间终止它们。
@Override public void onDestroy() { super.onDestroy(); //总是要写这一条 // Stop method tracing that the activity started during onCreate() android.os.Debug.stopMethodTracing(); }
注意:在所有情况下,系统在调用
onPause()
和onStop()
之后都会调用onDestroy()
,只有一个例外:当您从onCreate()
方法内调用finish()
时。在有些情况下,比如当您的Activity作为临时决策工具运行以启动另一个Activity时,您可从
onCreate()
内调用finish()
来销毁Activity。在这种情况下,系统会立刻调用
onDestroy()
,而不调用任何其他 生命周期方法。
暂停Activity
当系统为您的Activity调用 onPause()
时,它从技术角度看意味着您的Activity仍然处于部分可见状态,但往往说明用户即将离开Activity并且它很快就要进入“停止”状态。
您通常应使用 onPause()
回调在以下几种情况:
- 停止动画或其他可能消耗 CPU 的进行之中的操作。
- 提交未保存的更改,但仅当用户离开时希望永久性保存此类更改(比如电子邮件草稿)。
- 释放系统资源,比如广播接收器、传感器手柄(比如 GPS) 或当您的Activity暂停且用户不需要它们时仍然可能影响电池寿命的任何其他资源。
例如,如果您的应用使用 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()
中永久性存储用户更改。
但您应避免在 onPause()
期间执行 CPU 密集型工作,比如向数据库写入信息,因为这会拖慢向下一Activity过渡的过程(改为在 onStop()
期间执行)。
继续Activity
当用户从“暂停”状态继续您的Activity时,系统会调用 onResume()
方法。
请注意,每当您的Activity进入前台时系统便会调用此方法,包括它初次创建之时。
同样地,您应实现onResume()
初始化您在 onPause()
期间释放的组件并且执行每当Activity进入“继续”状态时必须进行的任何其他初始化操作(比如开始动画和初始化只在Activity具有用户焦点时使用的组件)。
onResume()
的以下示例对应于以上的 onPause()
示例,因此它初始化Activity暂停时释放的照相机。
@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 } }
停止并重新开始Activity
几种Activity停止和重新开始的关键场景:
- 用户打开“最近应用”窗口并从您的应用切换到另一个应用。当前位于前台的您的应用中的Activity将停止。 如果用户从主屏幕启动器图标或“最近应用”窗口返回到您的应用,Activity会重新开始。
- 用户在您的应用中执行开始新Activity的操作。当第二个Activity创建好后,当前Activity便停止。 如果用户之后按了返回按钮,第一个Activity会重新开始。
- 用户在其手机上使用您的应用的同时接听来电。
不同于识别部分 UI 阻挡的暂停状态,停止状态保证 UI 不再可见,且用户的焦点在另外的Activity(或完全独立的应用)中。
注意:因为系统在停止时会将您的
Activity
实例保留在系统内存中,您根本无需实现onStop()
和onRestart()
或甚至onStart()
方法。对于大多数相对简单的Activity而言, Activity将停止并重新开始,并且您可能只需使用
onPause()
暂停正在进行的操作,并从系统资源断开连接。
停止Activity
当您的Activity收到 onStop()
方法的调用时,它不再可见,并且应释放几乎所有用户不使用时不需要的资源。
一旦您的Activity停止,如果需要恢复系统内存,系统可能会销毁该实例。 在极端情况下,系统可能会仅终止应用进程,而不会调用Activity的最终 onDestroy()
回调,因此您使用 onStop()
释放可能泄露内存的资源非常重要。
您应使用 onStop()
执行更大、占用更多 CPU 的关闭操作,比如向数据库写入信息,如下:
@Override protected void onStop() { super.onStop(); // Always call the superclass method first //执行更大、占用更多 CPU 的关闭操作,比如向数据库写入信息。 }
当您的Activity停止时, Activity
对象将驻留在内存中并在Activity继续时被再次调用。
您无需重新初始化在任何导致进入“继续”状态的回调方法过程中创建的组件。 系统还会在布局中跟踪每个 View
的当前状态,如果用户在 EditText
小工具中输入文本,该内容会保留,因此您无需保存即可恢复它。
开始/重新开始Activity
当您的Activity从停止状态返回前台时,它会接收对 onRestart()
的调用。系统还会在每次您的Activity变为可见时调用 onStart()
方法(无论是正重新开始还是初次创建)。
但是,只会在Activity从停止状态继续时调用 onRestart()
方法,因此您可以使用它执行只有在Activity之前停止但未销毁的情况下可能必须执行的特殊恢复工作。
您应经常使用 onStart()
而不是 onRestart() 回调方法作为 onStop()
方法的对应部分,因为系统会在它创建您的Activity以及从停止状态重新开始Activity时调用 onStart()
。
@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()
的调用时,大多数应用无需做太多操作。
此方法是您清理可导致内存泄露的资源的最后一种方法,因此您应确保其他线程被销毁且其他长期运行的操作(比如方法跟踪)也会停止。