四大元件之Activity

嶽小川發表於2017-02-10

[文章內容來自Developers]

###Activity
是一個應用元件,使用者可與其提供的螢幕進行互動,以執行撥打電話、拍攝照片、傳送電子郵件或檢視地圖等操作。 每個 Activity 都會獲得一個用於繪製其使用者介面的視窗。視窗通常會充滿螢幕,但也可小於螢幕並浮動在其他視窗之上。
一個應用通常由多個彼此鬆散聯絡的 Activity 組成。 一般會指定應用中的某個 Activity 為“主”Activity,即首次啟動應用時呈現給使用者的那個 Activity。 而且每個 Activity 均可啟動另一個 Activity,以便執行不同的操作。 每次新 Activity 啟動時,前一 Activity 便會停止,但系統會在堆疊(“返回棧”)中保留該 Activity。 當新 Activity 啟動時,系統會將其推送到返回棧上,並取得使用者焦點。 返回棧遵循基本的“後進先出”堆疊機制,因此,當使用者完成當前 Activity 並按“返回”按鈕時,系統會從堆疊中將其彈出(並銷燬),然後恢復前一 Activity。(任務和返回棧文件中對返回棧有更詳細的闡述。)
當一個 Activity 因某個新 Activity 啟動而停止時,系統會通過該 Activity 的生命週期回撥方法通知其這一狀態變化。Activity 因狀態變化—系統是建立 Activity、停止 Activity、恢復 Activity 還是銷燬 Activity— 而收到的回撥方法可能有若干種,每一種回撥都會為您提供執行與該狀態變化相應的特定操作的機會。 例如,停止時,您的 Activity 應釋放任何大型物件,例如網路或資料庫連線。 當 Activity 恢復時,您可以重新獲取所需資源,並恢復執行中斷的操作。 這些狀態轉變都是 Activity 生命週期的一部分。
本文的其餘部分闡述有關如何建立和使用 Activity 的基礎知識(包括對 Activity 生命週期工作方式的全面闡述),以便您正確管理各種 Activity 狀態之間的轉變。

###建立 Activity
要建立 Activity,您必須建立 Activity的子類(或使用其現有子類)。您需要在子類中實現 Activity 在其生命週期的各種狀態之間轉變時(例如建立 Activity、停止 Activity、恢復 Activity 或銷燬 Activity 時)系統呼叫的回撥方法。 兩個最重要的回撥方法是:
onCreate()
您必須實現此方法。系統會在建立您的 Activity 時呼叫此方法。您應該在實現內初始化 Activity 的必需元件。 最重要的是,您必須在此方法內呼叫 setContentView(),以定義 Activity 使用者介面的佈局。
onPause()
系統將此方法作為使用者離開 Activity 的第一個訊號(但並不總是意味著 Activity 會被銷燬)進行呼叫。 您通常應該在此方法內確認在當前使用者會話結束後仍然有效的任何更改(因為使用者可能不會返回)。
您還應使用幾種其他生命週期回撥方法,以便提供流暢的 Activity 間使用者體驗,以及處理導致您的 Activity 停止甚至被銷燬的意外中斷。

###實現使用者介面
Activity 的使用者介面是由層級式檢視 — 衍生自 View類的物件 — 提供的。每個檢視都控制 Activity 視窗內的特定矩形空間,可對使用者互動作出響應。 例如,檢視可以是在使用者觸控時啟動某項操作的按鈕。您可以利用 Android 提供的許多現成檢視設計和組織您的佈局。“小部件”是提供按鈕、文字欄位、核取方塊或僅僅是一幅影象等螢幕視覺(互動式)元素的檢視。 “佈局”是衍生自 ViewGroup的檢視,為其子檢視提供唯一佈局模型,例如線性佈局、網格佈局或相對佈局。 您還可以為 View類和ViewGroup類建立子類(或使用其現有子類)來自行建立小部件和佈局,然後將它們應用於您的 Activity 佈局。
利用檢視定義佈局的最常見方法是藉助儲存在您的應用資源內的 XML 佈局檔案。這樣一來,您就可以將使用者介面的設計與定義 Activity 行為的原始碼分開維護。 您可以通過 setContentView()將佈局設定為 Activity 的 UI,從而傳遞佈局的資源 ID。不過,您也可以在 Activity 程式碼中建立新 View,並通過將新 View插入 ViewGroup來建立檢視層次,然後通過將根 ViewGroup傳遞到 setContentView()來使用該佈局。
您必須在清單檔案中宣告您的 Activity,這樣系統才能訪問它。 要宣告您的 Activity,請開啟您的清單檔案,並將 元素的子項。例如:

<manifest ... >  
<application ... >      
<activity android:name=".ExampleActivity" />     
 ...  
</application ... >  
...
</manifest >複製程式碼

您還可以在此元素中加入幾個其他特性,以定義 Activity 標籤、Activity 圖示或風格主題等用於設定 Activity UI 風格的屬性。 android:name屬性是唯一必需的屬性—它指定 Activity 的類名。應用一旦釋出,即不應更改此類名,否則,可能會破壞諸如應用快捷方式等一些功能。
使用 Intent 過濾器元素還可指定各種 Intent 過濾器—使用 元素—以宣告其他應用元件啟用它的方法。
當您使用 Android SDK 工具建立新應用時,系統自動為您建立的存根 Activity 包含一個 Intent 過濾器,其中宣告瞭該 Activity 響應“主”操作且應置於“launcher”類別內。 Intent 過濾器的內容如下所示:

<activity android:name=".ExampleActivity" 
  android:icon="@drawable/app_icon">    
  <intent-filter>        
    <action android:name="android.intent.action.MAIN" />    
    <category android:name="android.intent.category.LAUNCHER"/>   
  </intent-filter>
</activity>複製程式碼

元素指定這是應用的“主”入口點。元素指定此 Activity 應列入系統的應用啟動器內(以便使用者啟動該 Activity)。如果您打算讓應用成為獨立應用,不允許其他應用啟用其Activity,則您不需要任何其他 Intent 過濾器。 正如前例所示,只應有一個 Activity 具有“主”操作和“launcher”類別。 您不想提供給其他應用的 Activity 不應有任何 Intent 過濾器,您可以利用顯式 Intent 自行啟動它們(下文對此做了闡述)。
不過,如果您想讓 Activity 對衍生自其他應用(以及您的自有應用)的隱式 Intent 作出響應,則必須為 Activity 定義其他 Intent 過濾器。 對於您想要作出響應的每一個 Intent 型別,您都必須加入相應的 ,其中包括一個 元素,還可選擇性地包括一個 元素和/或一個 元素。這些元素指定您的 Activity 可以響應的 Intent 型別。

###啟動 Activity
您可以通過呼叫 startActivity(),並將其傳遞給描述您想啟動的 Activity 的 Intent來啟動另一個 Activity。Intent 物件會指定您想啟動的具體 Activity 或描述您想執行的操作型別(系統會為您選擇合適的 Activity,甚至是來自其他應用的 Activity)。 Intent 物件還可能攜帶少量供所啟動 Activity 使用的資料。
在您的自有應用內工作時,您經常只需要啟動某個已知 Activity。 您可以通過使用類名建立一個顯式定義您想啟動的 Activity 的 Intent 物件來實現此目的。 例如,可以通過以下程式碼讓一個 Activity 啟動另一個名為 SignInActivity的 Activity:

Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);複製程式碼

不過,您的應用可能還需要利用您的 Activity 資料執行某項操作,例如傳送電子郵件、簡訊或狀態更新。 在這種情況下,您的應用自身可能不具有執行此類操作所需的 Activity,因此您可以改為利用裝置上其他應用提供的 Activity 為您執行這些操作。 這便是 Intent 物件的真正價值所在 — 您可以建立一個 Intent 物件,對您想執行的操作進行描述,系統會從其他應用啟動相應的 Activity。 如果有多個 Activity 可以處理 Intent,則使用者可以選擇要使用哪一個。 例如,如果您想允許使用者傳送電子郵件,可以建立以下 Intent:

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);複製程式碼

新增到 Intent 中的 EXTRA_EMAIL 是一個字串陣列,其中包含應將電子郵件傳送到的電子郵件地址。 當電子郵件應用響應此 Intent 時,它會讀取 extra 中提供的字串陣列,並將它們放入電子郵件撰寫窗體的“收件人”欄位。 在這種情況下,電子郵件應用的 Activity 啟動,並且當使用者完成操作時,您的 Activity 會恢復執行。
啟動 Activity 以獲得結果
有時,您可能需要從啟動的 Activity 獲得結果。在這種情況下,請通過呼叫 startActivityForResult()(而非 startActivity()))來啟動 Activity。 要想在隨後收到後續 Activity 的結果,請實現 onActivityResult()回撥方法。 當後續 Activity 完成時,它會使用 Intent向您的 onActivityResult()方法返回結果。
例如,您可能希望使用者選取其中一位聯絡人,以便您的 Activity 對該聯絡人中的資訊執行某項操作。 您可以通過以下程式碼建立此類 Intent 並處理結果:

private void pickContact() {    
// Create an intent to "pick" a contact, as defined by the content provider URI    
Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);    
startActivityForResult(intent, PICK_CONTACT_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {    
// If the request went well (OK) and the request was PICK_CONTACT_REQUEST    
if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) {        
// Perform a query to the contact's content provider for the contact's name        
Cursor cursor = getContentResolver().query(data.getData(),        new String[] {Contacts.DISPLAY_NAME}, null, null, null);        
if (cursor.moveToFirst()) { // True if the cursor is not empty            int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);            
String name = cursor.getString(columnIndex);            
// Do something with the selected contact's name...        
}    
}}複製程式碼

上例顯示的是,您在處理 Activity 結果時應該在 onActivityResult()方法中使用的基本邏輯。 第一個條件檢查請求是否成功(如果成功,則resultCode將為 RESULT_OK以及此結果響應的請求是否已知 — 在此情況下,requestCode與隨 startActivityForResult()傳送的第二個引數匹配。 程式碼通過查詢 Intent中返回的資料(data引數)從該處開始處理 Activity 結果。
實際情況是,ContentResolver對一個內容提供程式執行查詢,後者返回一個 Cursor,讓查詢的資料能夠被讀取。

###結束 Activity
您可以通過呼叫 Activity 的 finish()方法來結束該 Activity。您還可以通過呼叫 finishActivity()結束您之前啟動的另一個 Activity。
:在大多數情況下,您不應使用這些方法顯式結束 Activity。 正如下文有關 Activity 生命週期的部分所述,Android 系統會為您管理 Activity 的生命週期,因此您無需結束自己的 Activity。 呼叫這些方法可能對預期的使用者體驗產生不良影響,因此只應在您確實不想讓使用者返回此 Activity 例項時使用。

###管理 Activity 生命週期
通過實現回撥方法管理 Activity 的生命週期對開發強大而又靈活的應用至關重要。 Activity 的生命週期會直接受到 Activity 與其他 Activity、其任務及返回棧的關聯性的影響。
Activity 基本上以三種狀態存在:
繼續
此 Activity 位於螢幕前臺並具有使用者焦點。(有時也將此狀態稱作“執行中”。)
暫停
另一個 Activity 位於螢幕前臺並具有使用者焦點,但此 Activity 仍可見。也就是說,另一個 Activity 顯示在此 Activity 上方,並且該 Activity 部分透明或未覆蓋整個螢幕。 暫停的 Activity 處於完全活動狀態(Activity物件保留在記憶體中,它保留了所有狀態和成員資訊,並與視窗管理器保持連線),但在記憶體極度不足的情況下,可能會被系統終止。
停止
該 Activity 被另一個 Activity 完全遮蓋(該 Activity 目前位於“後臺”)。 已停止的 Activity 同樣仍處於活動狀態(Activity物件保留在記憶體中,它保留了所有狀態和成員資訊,但與視窗管理器連線)。 不過,它對使用者不再可見,在他處需要記憶體時可能會被系統終止。
如果 Activity 處於暫停或停止狀態,系統可通過要求其結束(呼叫其 finish()方法)或直接終止其程式,將其從記憶體中刪除。(將其結束或終止後)再次開啟 Activity 時,必須重建。
實現生命週期回撥
當一個 Activity 轉入和轉出上述不同狀態時,系統會通過各種回撥方法向其發出通知。 所有回撥方法都是掛鉤,您可以在 Activity 狀態發生變化時替代這些掛鉤來執行相應操作。 以下框架 Activity 包括每一個基本生命週期方法:

public class ExampleActivity extends Activity {    
@Override    
public void onCreate(Bundle savedInstanceState) { 
       super.onCreate(savedInstanceState);       
 // The activity is being created.   
 }    
@Override    
protected void onStart(){        
super.onStart();       
 // The activity is about to become visible.    
}    
@Override    
protected void onResume(){        
super.onResume();        
// The activity has become visible (it is now "resumed").    
}    
@Override    
protected void onPause() {        
super.onPause();        
// Another activity is taking focus (this activity is about to be "paused").    
}    
@Override    
protected void onStop(){        
super.onStop();        
// The activity is no longer visible (it is now "stopped")    
}    
@Override    
protected void onDestroy(){        
super.onDestroy();        
// The activity is about to be destroyed.    
}}複製程式碼

:正如以上示例所示,您在實現這些生命週期方法時必須始終先呼叫超類實現,然後再執行任何操作。
這些方法共同定義 Activity 的整個生命週期。您可以通過實現這些方法監控 Activity 生命週期中的三個巢狀迴圈:
Activity 的整個生命週期發生在 onCreate()呼叫與 onDestroy()呼叫之間。您的 Activity 應在 onCreate()中執行“全域性”狀態設定(例如定義佈局),並釋放 onDestroy()中的所有其餘資源。例如,如果您的 Activity 有一個在後臺執行的執行緒,用於從網路上下載資料,它可能會在onCreate()中建立該執行緒,然後在 onDestroy()中停止該執行緒。
Activity 的可見生命週期發生在 onStart()呼叫與 onStop()呼叫之間。在這段時間,使用者可以在螢幕上看到 Activity 並與其互動。 例如,當一個新 Activity 啟動,並且此 Activity 不再可見時,系統會呼叫 onStop()。您可以在呼叫這兩個方法之間保留向使用者顯示 Activity 所需的資源。 例如,您可以在 onStart()中註冊一個 BroadcastReceiver以監控影響 UI 的變化,並在使用者無法再看到您顯示的內容時在 onStop()中將其取消註冊。在 Activity 的整個生命週期,當 Activity 在對使用者可見和隱藏兩種狀態中交替變化時,系統可能會多次呼叫 onStart() 和 onStop()。
Activity 的前臺生命週期發生在 onResume()呼叫與 onPause()呼叫之間。在這段時間,Activity 位於螢幕上的所有其他 Activity 之前,並具有使用者輸入焦點。 Activity 可頻繁轉入和轉出前臺 — 例如,當裝置轉入休眠狀態或出現對話方塊時,系統會呼叫 onPause()。 由於此狀態可能經常發生轉變,因此這兩個方法中應採用適度輕量級的程式碼,以避免因轉變速度慢而讓使用者等待。

圖 1 說明了這些迴圈以及 Activity 在狀態轉變期間可能經過的路徑。矩形表示回撥方法,當 Activity 在不同狀態之間轉變時,您可以實現這些方法來執行操作。

四大元件之Activity

圖 1. Activity 生命週期。
表 1 列出了相同的生命週期回撥方法,其中對每一種回撥方法做了更詳細的描述,並說明了每一種方法在 Activity 整個生命週期內的位置,包括在回撥方法完成後系統能否終止 Activity。
表 1. Activity 生命週期回撥方法彙總表。

方法 說明 是否能事後終止? 後接
onCreate() 首次建立 Activity 時呼叫。 您應該在此方法中執行所有正常的靜態設定 — 建立檢視、將資料繫結到列表等等。 系統向此方法傳遞一個 Bundle 物件,其中包含 Activity 的上一狀態,不過前提是捕獲了該狀態。始終後接 onStart()。 onStart()
onRestart() 在 Activity 已停止並即將再次啟動前呼叫。始終後接 onStart() onStart()
onStart() 在 Activity 即將對使用者可見之前呼叫。如果 Activity 轉入前臺,則後接 onResume(),如果 Activity 轉入隱藏狀態,則後接 onStop()。 onResume()或onStop()
onResume() 在 Activity 即將開始與使用者進行互動之前呼叫。 此時,Activity 處於 Activity 堆疊的頂層,並具有使用者輸入焦點。始終後接 onPause()。 onPause()
onPause() 當系統即將開始繼續另一個 Activity 時呼叫。 此方法通常用於確認對永續性資料的未儲存更改、停止動畫以及其他可能消耗 CPU 的內容,諸如此類。 它應該非常迅速地執行所需操作,因為它返回後,下一個 Activity 才能繼續執行。如果 Activity 返回前臺,則後接 onResume(),如果 Activity 轉入對使用者不可見狀態,則後接 onStop() onResume()或onStop()
onStop() 在 Activity 對使用者不再可見時呼叫。如果 Activity 被銷燬,或另一個 Activity(一個現有 Activity 或新 Activity)繼續執行並將其覆蓋,就可能發生這種情況。如果 Activity 恢復與使用者的互動,則後接 onRestart(),如果 Activity 被銷燬,則後接onDestroy()。 onRestart()或onDestroy()
onDestroy() 在 Activity 被銷燬前呼叫。這是 Activity 將收到的最後呼叫。 當 Activity 結束(有人對 Activity 呼叫了 finish()),或系統為節省空間而暫時銷燬該 Activity 例項時,可能會呼叫它。 您可以通過 isFinishing()方法區分這兩種情形。

名為“是否能事後終止?”的列表示系統是否能在不執行另一行 Activity 程式碼的情況下,在方法返回後隨時終止承載 Activity 的程式。 有三個方法帶有“是”標記:(onPause()、onStop()和 onDestroy()
)。由於 onPause()是這三個方法中的第一個,因此 Activity 建立後,onPause()必定成為最後呼叫的方法,然後才能終止程式 — 如果系統在緊急情況下必須恢復記憶體,則可能不會呼叫 onStop()和 onDestroy()。因此,您應該使用 onPause()向儲存裝置寫入至關重要的永續性資料(例如使用者編輯)。不過,您應該對 onPause()呼叫期間必須保留的資訊有所選擇,因為該方法中的任何阻止過程都會妨礙向下一個 Activity 的轉變並拖慢使用者體驗。
是否能在事後終止?列中標記為“否”的方法可從系統呼叫它們的一刻起防止承載 Activity 的程式被終止。 因此,在從 onPause()返回的時間到 onResume()被呼叫的時間,系統可以終止 Activity。在 onPause()被再次呼叫並返回前,將無法再次終止 Activity。 注**:根據表 1 中的定義屬於技術上無法“終止”的 Activity 仍可能被系統終止 — 但這種情況只有在無任何其他資源的極端情況下才會發生。程式和執行緒處理文件對可能會終止 Activity 的情況做了更詳盡的闡述。

###儲存 Activity 狀態
管理 Activity 生命週期的引言部分簡要提及,當 Activity 暫停或停止時,Activity 的狀態會得到保留。 確實如此,因為當 Activity 暫停或停止時,Activity物件仍保留在記憶體中 — 有關其成員和當前狀態的所有資訊仍處於活動狀態。 因此,使用者在 Activity 內所做的任何更改都會得到保留,這樣一來,當 Activity 返回前臺(當它“繼續”)時,這些更改仍然存在。
不過,當系統為了恢復記憶體而銷燬某項 Activity 時,Activity物件也會被銷燬,因此係統在繼續 Activity 時根本無法讓其狀態保持完好,而是必須在使用者返回 Activity 時重建 Activity物件。但使用者並不知道系統銷燬 Activity 後又對其進行了重建,因此他們很可能認為 Activity 狀態毫無變化。 在這種情況下,您可以實現另一個回撥方法對有關 Activity 狀態的資訊進行儲存,以確保有關 Activity 狀態的重要資訊得到保留:onSaveInstanceState()。
系統會先呼叫 onSaveInstanceState(),然後再使 Activity 變得易於銷燬。系統會向該方法傳遞一個 Bundle,您可以在其中使用 putString()和 putInt()等方法以名稱-值對形式儲存有關 Activity 狀態的資訊。然後,如果系統終止您的應用程式,並且使用者返回您的 Activity,則系統會重建該 Activity,並將 Bundle同時傳遞給 onCreate()和 onRestoreInstanceState()。您可以使用上述任一方法從 Bundle提取您儲存的狀態並恢復該 Activity 狀態。如果沒有狀態資訊需要恢復,則傳遞給您的 Bundle是空值(如果是首次建立該 Activity,就會出現這種情況)。

四大元件之Activity
圖 2. 在兩種情況下,Activity 重獲使用者焦點時可保持狀態完好:系統在銷燬 Activity 後重建 Activity,Activity 必須恢復之前儲存的狀態;系統停止 Activity 後繼續執行 Activity,並且 Activity 狀態保持完好。
:無法保證系統會在銷燬您的 Activity 前呼叫 onSaveInstanceState(),因為存在不需要儲存狀態的情況(例如使用者使用“返回”按鈕離開您的 Activity 時,因為使用者的行為是在顯式關閉 Activity)。 **如果系統呼叫 onSaveInstanceState(),它會在呼叫 onStop()之前,並且可能會在呼叫 onPause()之前進行呼叫。
不過,即使您什麼都不做,也不實現 onSaveInstanceState(),Activity類的 onSaveInstanceState()預設實現也會恢復部分 Activity 狀態。具體地講,預設實現會為佈局中的每個 View呼叫相應的 onSaveInstanceState()方法,讓每個檢視都能提供有關自身的應儲存資訊。Android 框架中幾乎每個小部件都會根據需要實現此方法,以便在重建 Activity 時自動儲存和恢復對 UI 所做的任何可見更改。例如,EditText小部件儲存使用者輸入的任何文字,CheckBox小部件儲存核取方塊的選中或未選中狀態。您只需為想要儲存其狀態的每個小部件提供一個唯一的 ID(通過 android:id屬性)。如果小部件沒有 ID,則系統無法儲存其狀態。
您還可以通過將android:saveEnabled屬性設定為 "false"
或通過呼叫 setSaveEnabled()方法顯式阻止佈局內的檢視儲存其狀態。您通常不應將該屬性停用,但如果您想以不同方式恢復 Activity UI 的狀態,就可能需要這樣做。

儘管 onSaveInstanceState()的預設實現會儲存有關您的Activity UI 的有用資訊,您可能仍需替換它以儲存更多資訊。例如,您可能需要儲存在 Activity 生命週期內發生了變化的成員值(它們可能與 UI 中恢復的值有關聯,但預設情況下系統不會恢復儲存這些 UI 值的成員)。
由於 onSaveInstanceState()的預設實現有助於儲存 UI 的狀態,因此如果您為了儲存更多狀態資訊而替換該方法,應始終先呼叫 onSaveInstanceState()的超類實現,然後再執行任何操作。 同樣,如果您替換 onRestoreInstanceState()方法,也應呼叫它的超類實現,以便預設實現能夠恢復檢視狀態。
:由於無法保證系統會呼叫 onSaveInstanceState(),因此您只應利用它來記錄 Activity 的瞬態(UI 的狀態)— 切勿使用它來儲存永續性資料,而應使用 onPause()在使用者離開 Activity 後儲存永續性資料(例如應儲存到資料庫的資料)。
您只需旋轉裝置,讓螢幕方向發生變化,就能有效地測試您的應用的狀態恢復能力。 當螢幕方向變化時,系統會銷燬並重建 Activity,以便應用可供新螢幕配置使用的備用資源。 單憑這一理由,您的 Activity 在重建時能否完全恢復其狀態就顯得非常重要,因為使用者在使用應用時經常需要旋轉螢幕。

###處理配置變更
有些裝置配置可能會在執行時發生變化(例如螢幕方向、鍵盤可用性及語言)。 發生此類變化時,Android 會重建執行中的 Activity(系統呼叫onDestroy(),然後立即呼叫 onCreate())。此行為旨在通過利用您提供的備用資源(例如適用於不同螢幕方向和螢幕尺寸的不同佈局)自動重新載入您的應用來幫助它適應新配置。
如果您對 Activity 進行了適當設計,讓它能夠按以上所述處理螢幕方向變化帶來的重啟並恢復 Activity 狀態,那麼在遭遇 Activity 生命週期中的其他意外事件時,您的應用將具有更強的適應性。
正如上文所述,處理此類重啟的最佳方法是利用onSaveInstanceState()和 onRestoreInstanceState()(或 onCreate())儲存並恢復 Activity 的狀態。

###協調 Activity
當一個 Activity 啟動另一個 Activity 時,它們都會體驗到生命週期轉變。第一個 Activity 暫停並停止(但如果它在後臺仍然可見,則不會停止)時,同時系統會建立另一個 Activity。 如果這些 Activity 共用儲存到磁碟或其他地方的資料,必須瞭解的是,在建立第二個 Activity 前,第一個 Activity 不會完全停止。更確切地說,啟動第二個 Activity 的過程與停止第一個 Activity 的過程存在重疊。
生命週期回撥的順序經過明確定義,當兩個 Activity 位於同一程式,並且由一個 Activity 啟動另一個 Activity 時,其定義尤其明確。 以下是當 Activity A 啟動 Activity B 時一系列操作的發生順序:
Activity A 的 onPause()方法執行。
Activity B 的 onCreate()、onStart()和 onResume()方法依次執行。(Activity B 現在具有使用者焦點。)
然後,如果 Activity A 在螢幕上不再可見,則其 onStop()方法執行。

您可以利用這種可預測的生命週期回撥順序管理從一個 Activity 到另一個 Activity 的資訊轉變。 例如,如果您必須在第一個 Activity 停止時向資料庫寫入資料,以便下一個 Activity 能夠讀取該資料,則應在 onPause()而不是 onStop()執行期間向資料庫寫入資料。

相關文章