Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Activity生命周期都該做哪些事情?

Android Activity生命周期都該做哪些事情?

編輯:關於Android編程

Android系統根據生命周期的不同階段喚起對應的回調函數來執行代碼。系統存在啟動與銷毀一個activity的一套有序的回調函數。本節來討論下不同生命周期的回調函數裡都該做哪些事情,不該做哪些事情。

理解生命周期的回調

在一個activity的生命周期中,系統會像金字塔模型一樣去調用一系列的生命周期回調函數。Activity生命周期的每一個階段就像金字塔中的台階。當系統創建了一個新的activity實例,每一個回調函數會向上一階移動activity狀態。處在金字塔頂端意味著當前activity處在前台並處於用戶可與其進行交互的狀態。

當用戶退出這個activity時,為了回收該activity,系統會調用其它方法來向下一階移動activity狀態。在某些情況下,activity會隱藏在金字塔下等待(例如當用戶切換到其他app),此時activity可以重新回到頂端(如果用戶回到這個activity)並恢復用戶離開時的狀態。
這裡寫圖片描述
這是一張Activity的生命周期圖,當然我們也可以從打印中觀察整個Activity生命周期調用的回調方法。下面打印是從啟動一個MainActivity跳轉到另一個OtherActivity,然後點擊Back,直到整個程序退出。打印如下:
這裡寫圖片描述

根據activity的復雜度,也許不需要實現所有的生命周期方法。但了解每一個方法的回調時機並在其中填充相應功能,使得確保app能夠像用戶期望的那樣執行是很有必要的。如何實現一個符合用戶期待的app,我們需要注意下面幾點:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCsq508NhcHC1xMqxuvKjrLK7u+HS8s6q09DAtLXnzai7sLvy1d/H0Lu7tb3G5Mv7YXBwtvi1vNbCs8zQ8mNyYXNooaMg08O7p8O709C8pLvuxLO49tfpvP7KsbK7u+HP+7rEsaa587XEz7XNs9fK1LShoyDA67+qYXBwsqLH0tK7ts7KsbzkuvO3tbvYo6yyu7vhtqrKp9PDu6e1xMq508O9+LbIoaMgyeixuLeiyfrGwcS70P3Xqsqxsru74WNyYXNou/LV37aqyqfTw7untcTKudPDvfi2yKGjDQo8cD7Iu7b4o6zG5NbQ1rvT0Mj9uPbXtMysyse+ssystcSjrNXiyP249te0zKzPwmFjdGl2aXR5v8nS1LTm1NrSu7bOsci9z7OktcTKsbzkoaMoxuTL/Ly4uPbXtMysu+G63L/svs3H0Lu7tfSjrM2jwfS1xMqxvOSxyL3PtszU3Sk8L3A+DQpSZXN1bWVko7q4w9e0zKzPwqOsYWN0aXZpdHm0ptTax7DMqKOs08O7p7/J0tTT68v8vfjQ0L27u6WhoyjNqLOj0rKxu8DtveLOqiZyZHF1bztydW5uaW5nJnJkcXVvOyDXtMysKSBQYXVzZWSjurjD17TMrM/Co6xhY3Rpdml0ebXEsr+31rG7we3N4tK7uPZhY3Rpdml0ecv51dq4x6O6we3N4rXEYWN0aXZpdHnAtLW9x7DMqKOstavKx7DrzbjD97XEo6yyu7vhuLK4x9X7uPbGwcS7oaOxu9TdzaO1xGFjdGl2aXR5srvU2b3TytzTw7untcTK5Mjrx9Kyu9TZ1rTQ0MjOus60+sLroaMgU3RvcHBlZKO6uMPXtMysz8IsIGFjdGl2aXR5zerIq7G70v6y2KOsttTTw7unsru/ybz7oaO/ydLUyM/OqsrH1Nq688yooaO1sXN0b3BwZWQsIGFjdGl2aXR5yrXA/dPry/y1xMv509DXtMys0MXPoqOoyOezydSxseTBv7XIo6m2vLvhsbuxo8H0o6y1q2FjdGl2aXR5srvE3Na00NDIzrrOtPrC66GjPGJyIC8+DQrG5Mv817TMrCAoQ3JlYXRlZNPrU3RhcnRlZCm2vMrHtszU3bXEo6zPtc2zv+zL2bXE1rTQ0MTH0Km72LX3uq/K/bKizai5/da00NDPwtK7vde2zrXEu9i197qvyv3Sxravtb3PwtK7uPbXtMysoaPSsr7NysfLtaOs1NrPtc2ztffTw29uQ3JlYXRlKCksINauuvO74dG4y9m199PDb25TdGFydCgpLCDWrrrz1NnRuMvZ1rTQ0G9uUmVzdW1lKCmho9LUyc++zcrHu/mxvrXEYWN0aXZpdHnJ+sP81tzG2qGjDQo8cD7Su7Wpb25DcmVhdGUgstnX983qs8mjrM+1zbO74dG4y9m199PDb25TdGFydCgpINPrb25SZXN1bWUoKbe9t6iho87Sw8e1xGFjdGl2aXR5sru74dTaQ3JlYXRlZLvy1d9TdGFydGVk17TMrM2jwfSho7y8yvXJz8C0y7UsIGFjdGl2aXR51NpvblN0YXJ0KCmxu7X308O687+qyryxu9PDu6e/ybz7o6y1q8rHIG9uUmVzdW1lKCm74dG4y9mxu9a00NDKubXDYWN0aXZpdHnNo8H01NpSZXN1bWVk17TMrKOs1rG1vdK70KnS8svYt6LJ+rHku6+yxbvhuMSx5NXiuPbXtMysoaPA/cjnvdPK1bW90ru49sC0teejrNPDu6fH0Lu7tb3B7c3i0ru49mFjdGl2aXR5o6y78tXfysfJ6LG4xsHEu7nYsdWhozwvcD4NCjxoMiBpZD0="暫停與恢復activity">暫停與恢復Activity

在正常使用app時,前端的activity有時會被其他可見的組件阻塞(obstructed),從而導致當前的activity進入Pause狀態。例如,當打開一個半透明的activity時(例如以對話框的形式),之前的activity會被暫停。 只要之前的activity仍然被部分可見,這個activity就會一直處於Paused狀態。

然而,一旦之前的activity被完全阻塞並不可見時,則其會進入Stop狀態(將在下一小節討論)。

activity一旦進入paused狀態,系統就會調用activity中的onPause()方法, 該方法中可以停止不應該在暫停過程中執行的操作,如暫停視頻播放;或者保存那些有可能需要長期保存的信息。如果用戶從暫停狀態回到當前activity,系統應該恢復那些數據並執行onResume()方法。

Note: 當我們的activity收到調用onPause()的信號時,那可能意味者activity將被暫停一段時間,並且用戶很可能回到我們的activity。然而,那也是用戶要離開我們的activtiy的第一個信號。
這裡寫圖片描述

Figure 1. 當一個半透明的activity阻塞activity時,系統會調用onPause()方法並且這個activity會停留在Paused 狀態(1). 如果用戶在這個activity還是在Paused 狀態時回到這個activity,系統則會調用它的onResume() (2).

暫停Activity

當系統調用activity中的onPause(),從技術上講,意味著activity仍然處於部分可見的狀態.但更多時候意味著用戶正在離開這個activity,並馬上會進入Stopped state. 通常應該在onPause()回調方法裡面做以下事情:

停止動畫或者是其他正在運行的操作,那些都會導致CPU的浪費. 提交在用戶離開時期待保存的內容(例如郵件草稿). 釋放系統資源,例如broadcast receivers, sensors (比如GPS), 或者是其他任何會影響到電量的資源。

例如, 如果程序使用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()來保存用戶改變的數據 (例如填入表格中的個人信息) 到永久存儲(File或者DB)上。僅僅當確認用戶期待那些改變能夠被自動保存的時候(例如正在撰寫郵件草稿),才把那些數據存到永久存儲 。但是,我們應該避免在onPause()時執行CPU-intensive 的工作,例如寫數據到DB,因為它會導致切換到下一個activity變得緩慢(應該把那些heavy-load的工作放到onStop()去做)。

如果activity實際上是要被Stop,那麼我們應該為了切換的順暢而減少在OnPause()方法裡面的工作量。

Note:當activity處於暫停狀態,Activity.html” target=”_blank”>Activity實例是駐留在內存中的,並且在activity 恢復的時候重新調用。我們不需要在恢復到Resumed狀態的一系列回調方法中重新初始化組件。

恢復activity

當用戶從Paused狀態恢復activity時,系統會調用onResume()方法。

請注意,系統每次調用這個方法時,activity都處於前台,包括第一次創建的時候。所以,應該實現onResume()來初始化那些在onPause方法裡面釋放掉的組件,並執行那些activity每次進入Resumed state都需要的初始化動作 (例如開始動畫與初始化那些只有在獲取用戶焦點時才需要的組件)

下面的onResume()的例子是與上面的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
    }
}

停止與重啟Activity

恰當的停止與重啟我們的activity是很重要的,在activity生命周期中,他們能確保用戶感知到程序的存在並不會丟失他們的進度。在下面一些關鍵的場景中會涉及到停止與重啟:

用戶打開最近使用app的菜單並從我們的app切換到另外一個app,這個時候我們的app是被停止的。如果用戶通過手機主界面的啟動程序圖標或者最近使用程序的窗口回到我們的app,那麼我們的activity會重啟。 用戶在我們的app裡面執行啟動一個新activity的操作,當前activity會在第二個activity被創建後stop。如- - 果用戶點擊back按鈕,第一個activtiy會被重啟。 用戶在使用我們的app時接收到一個來電通話。

Activity類提供了Activity.onStop()”>onStop()與Activity.onRestart()”>onRestart()方法來允許在activity停止與重啟時進行調用。不同於暫停狀態的部分阻塞UI,停止狀態是UI不再可見並且用戶的焦點轉移到另一個activity中.

Note: 因為系統在activity停止時會在內存中保存Activity的實例,所以有時不需要實現onStop(),onRestart()甚至是onStart()方法. 因為大多數的activity相對比較簡單,activity會自己停止與重啟,我們只需要使用onPause()來停止正在運行的動作並斷開系統資源鏈接。
這裡寫圖片描述

Figure 1. 上圖顯示:當用戶離開我們的activity時,系統會調用onStop()來停止activity (1). 這個時候如果用戶返回,系統會調用onRestart()(2), 之後會迅速調用onStart()(3)與onResume()(4). 請注意:無論什麼原因導致activity停止,系統總是會在onStop()之前調用onPause()方法。

停止activity

當activity調用onStop()方法, activity不再可見,並且應該釋放那些不再需要的所有資源。一旦activity停止了,系統會在需要內存空間時摧毀它的實例(和棧結構有關,通常back操作會導致前一個activity被銷毀)。極端情況下,系統會直接殺死我們的app進程,並不執行activity的onDestroy()回調方法, 因此我們需要使用onStop()來釋放資源,從而避免內存洩漏。(這點需要注意)

盡管onPause()方法是在onStop()之前調用,我們應該使用onStop()來執行那些CPU intensive的shut-down操作,例如往數據庫寫信息。

例如,下面是一個在onStop()的方法裡面保存筆記草稿到persistent storage的示例:

@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 resume時被重新調用。我們不需要在恢復到Resumed state狀態前重新初始化那些被保存在內存中的組件。系統同樣保存了每一個在布局中的視圖的當前狀態,如果用戶在EditText組件中輸入了text,它會被保存,因此不需要保存與恢復它。

Note: 即使系統會在activity stop時停止這個activity,它仍然會保存View對象的狀態(比如EditText中的文字) 到一個Bundle中,並且在用戶返回這個activity時恢復它們(下一小節會介紹在activity銷毀與重新建立時如何使用Bundle來保存其他數據的狀態).

啟動與重啟activity

當activity從Stopped狀態回到前台時,它會調用onRestart().系統再調用onStart()方法,onStart()方法會在每次activity可見時都會被調用。onRestart()方法則是只在activity從stopped狀態恢復時才會被調用,因此我們可以使用它來執行一些特殊的恢復(restoration)工作,請注意之前是被stopped而不是destrory。

使用onRestart()來恢復activity狀態是不太常見的,因此對於這個方法如何使用沒有任何的guidelines。然而,因為onStop()方法應該做清除所有activity資源的操作,我們需要在重啟activtiy時重新實例化那些被清除的資源,同樣, 我們也需要在activity第一次創建時實例化那些資源。介於上面的原因,應該使用onStart()作為onStop()所對應方法。因為系統會在創建activity與從停止狀態重啟activity時都會調用onStart()。也就是說,我們在onStop裡面做了哪些清除的操作,就該在onStart裡面重新把那些清除掉的資源重新創建出來。

例如:因為用戶很可能在回到這個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
}

當系統Destory我們的activity,它會為activity調用onDestroy()方法。因為我們會在onStop方法裡面做釋放資源的操作,那麼onDestory方法則是我們最後去清除那些可能導致內存洩漏的地方。因此需要確保那些線程都被destroyed並且所有的操作都被停止。

重新創建Activity

有幾個場景中,Activity是由於正常的程序行為而被Destory的。例如當用戶點擊返回按鈕或者是Activity通過調用Activity.html#finish()”>finish()來發出停止信號。系統也有可能會在Activity處於stop狀態且長時間不被使用,或者是在前台activity需要更多系統資源的時關閉後台進程,以圖獲取更多的內存。

當Activity是因為用戶點擊Back按鈕或者是activity通過調用finish()結束自己時,系統就丟失了對Activity實例的引用,因為這一行為意味著不再需要這個activity了。然而,如果因為系統資源緊張而導致Activity的Destory, 系統會在用戶回到這個Activity時有這個Activity存在過的記錄,系統會使用那些保存的記錄數據(描述了當Activity被Destory時的狀態)來重新創建一個新的Activity實例。那些被系統用來恢復之前狀態而保存的數據被叫做 “instance state” ,它是一些存放在Bundle對象中的key-value pairs。(請注意這裡的描述,這對理解onSaveInstanceState執行的時刻很重要)

Caution: 你的Activity會在每次旋轉屏幕時被destroyed與recreated。當屏幕改變方向時,系統會Destory與Recreate前台的activity,因為屏幕配置被改變,你的Activity可能需要加載另一些替代的資源(例如layout).
默認情況下, 系統使用 Bundle 實例來保存每一個View(視圖)對象中的信息(例如輸入EditText 中的文本內容)。因此,如果Activity被destroyed與recreated, 則layout的狀態信息會自動恢復到之前的狀態。然而,activity也許存在更多你想要恢復的狀態信息,例如記錄用戶Progress的成員變量(member variables)。

Note: 為了使Android系統能夠恢復Activity中的View的狀態,每個View都必須有一個唯一ID,由android:id定義。
為了可以保存額外更多的數據到saved instance state。在Activity的生命周期裡面存在一個額外的回調函數,你必須重寫這個函數。該回調函數並沒有在前面課程的圖片示例中顯示。這個方法是Activity.onSaveInstanceState(android.os.Bundle)>onSaveInstanceState() ,當用戶離開Activity時,系統會調用它。當系統調用這個函數時,系統會在Activity被異常Destory時傳遞 Bundle 對象,這樣我們就可以增加額外的信息到Bundle中並保存到系統中。若系統在Activity被Destory之後想重新創建這個Activity實例時,之前的Bundle對象會(系統)被傳遞到你我們activity的Activity.onRestoreInstanceState(android.os.Bundle)>onRestoreInstanceState()方法與 onCreate() 方法中。
這裡寫圖片描述
Figure 2. 當系統開始停止Activity時,只有在Activity實例會需要重新創建的情況下才會調用到Activity.onSaveInstanceState(android.os.Bundle)>onSaveInstanceState() (1) ,在這個方法裡面可以指定額外的狀態數據到Bunde中。如果這個Activity被destroyed然後這個實例又需要被重新創建時,系統會傳遞在 (1) 中的狀態數據到 onCreate() (2) 與 Activity.onRestoreInstanceState(android.os.Bundle)>onRestoreInstanceState()(3).

(通常來說,跳轉到其他的activity或者是點擊Home都會導致當前的activity執行onSaveInstanceState,因為這種情況下的activity都是有可能會被destory並且是需要保存狀態以便後續恢復使用的,而從跳轉的activity點擊back回到前一個activity,那麼跳轉前的activity是執行退棧的操作,所以這種情況下是不會執行onSaveInstanceState的,因為這個activity不可能存在需要重建的操作)

保存Activity狀態

當我們的activity開始Stop,系統會調用 onSaveInstanceState() ,Activity可以用鍵值對的集合來保存狀態信息。這個方法會默認保存Activity視圖的狀態信息,如在 EditText 組件中的文本或 ListView 的滑動位置。

為了給Activity保存額外的狀態信息,你必須實現onSaveInstanceState() 並增加key-value pairs到 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);
}

Note: 必須要調用 onSaveInstanceState() 方法的父類實現,這樣默認的父類實現才能保存視圖狀態的信息。

恢復Activity狀態

當Activity從Destory中重建,我們可以從系統傳遞的Activity的Bundle中恢復保存的狀態。 onCreate() 與 onRestoreInstanceState() 回調方法都接收到了同樣的Bundle,裡面包含了同樣的實例狀態信息。

由於 onCreate() 方法會在第一次創建新的Activity實例與重新創建之前被Destory的實例時都被調用,我們必須在嘗試讀取 Bundle 對象前檢測它是否為null。如果它為null,系統則是創建一個新的Activity實例,而不是恢復之前被Destory的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
    }
    ...
}

我們也可以選擇實現 onRestoreInstanceState() ,而不是在onCreate方法裡面恢復數據。 onRestoreInstanceState()方法會在 onStart() 方法之後執行. 系統僅僅會在存在需要恢復的狀態信息時才會調用 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);
}

Note: 與上面保存一樣,總是需要調用onRestoreInstanceState()方法的父類實現,這樣默認的父類實現才能保存視圖狀態的信息。更多關於運行時狀態改變引起的recreate我們的activity。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved