Activity是一個應用組件,用戶可與其提供的屏幕進行交互晒哄。以執(zhí)行撥打電話睁宰,拍攝照片,發(fā)送電子郵件或查看地圖等操作寝凌。 每個 Activity 都會獲得一個用于繪制其用戶界面的窗口(window)柒傻。窗口通常會充滿屏幕,但也可小于屏幕并浮動在其他窗口之上较木。
??一個應用通常由多個彼此松散聯系的 Activity 組成红符。 一般會指定應用中的某個 Activity 為“主”Activity(Main Activity),即首次啟動應用時呈現給用戶的那個 Activity伐债。 而且每個 Activity 均可啟動另一個 Activity预侯,以便執(zhí)行不同的操作。 每次新 Activity 啟動時峰锁,前一 Activity 便會停止萎馅,但系統(tǒng)會在堆棧(“返回棧”)中保留該 Activity祖今。 當新 Activity 啟動時校坑,系統(tǒng)會將其推送到返回棧上,并取得用戶焦點千诬。 返回棧遵循“后進先出”堆棧機制耍目,因此,當用戶完成當前 Activity 并按“返回” 按鈕時徐绑,系統(tǒng)會從堆棧中將其彈出(并銷毀)邪驮,然后恢復前一 Activity。(任務和返回棧文檔中對返回棧有更詳細的闡述傲茄。)
??當一個 Activity 因某個新 Activity 啟動而停止時毅访,系統(tǒng)會通過該 Activity 的生命周期回調方法通知其這一狀態(tài)變化沮榜。Activity 因狀態(tài)變化(系統(tǒng)是創(chuàng)建 Activity、停止 Activity喻粹、恢復 Activity 還是銷毀 Activity)而收到的回調方法可能有若干種蟆融,每一種回調方法都會為您提供執(zhí)行與該狀態(tài)變化相應的特定操作的機會。 例如守呜,停止時型酥,您的 Activity 應釋放任何大型對象,例如網絡或數據庫連接查乒。 當 Activity 恢復時弥喉,您可以重新獲取所需資源,并恢復執(zhí)行中斷的操作玛迄。 這些狀態(tài)轉變都是 Activity 生命周期的一部分由境。
??本文的其余部分闡述有關如何創(chuàng)建和使用 Activity 的基礎知識(包括對 Activity 生命周期工作方式的全面闡述),以便您正確管理各種 Activity 狀態(tài)之間的轉變蓖议。
創(chuàng)建Activity
要創(chuàng)建 Activity虏杰,您必須創(chuàng)建 Activity 的子類(或使用其現有子類)。您需要在子類中實現 Activity 在其生命周期的各種狀態(tài)之間轉變時(例如創(chuàng)建 Activity勒虾、停止 Activity嘹屯、恢復 Activity 或銷毀 Activity 時)系統(tǒng)調用的回調方法。 兩個最重要的回調方法是:
onCreate()
您必須實現此方法从撼。系統(tǒng)會在創(chuàng)建您的 Activity 時調用此方法。您應該在實現內初始化 Activity 的必需組件钧栖。 最重要的是低零,您必須在此方法內調用 setContentView(),以定義 Activity 用戶界面的布局拯杠。
onPause()
系統(tǒng)將此方法作為用戶離開 Activity 的第一個信號(但并不總是意味著 Activity 會被銷毀)進行調用掏婶。 您通常應該在此方法內確認在當前用戶會話結束后仍然有效的任何更改(因為用戶可能不會返回)。
您還應使用幾種其他生命周期回調方法潭陪,以便提供流暢的 Activity 間用戶體驗雄妥,以及處理導致您的 Activity 停止甚至被銷毀的意外中斷。 后文的管理 Activity 生命周期部分對所有生命周期回調方法進行了闡述依溯。
實現用戶界面
Activity 的用戶界面是由層級式視圖(衍生自 View 類的對象)提供的老厌。每個視圖都控制 Activity 窗口內的特定矩形空間,可對用戶交互作出響應黎炉。 例如枝秤,視圖可以是在用戶觸摸時啟動某項操作的按鈕。
??您可以利用 Android 提供的許多現成視圖設計和組織您的布局慷嗜〉淼“小工具”(Widget)是提供按鈕丹壕、文本字段、復選框或僅僅是一幅圖像等屏幕視覺(交互式)元素的視圖薇溃。 “布局”(Layout)是衍生自 ViewGroup 的視圖菌赖,為其子視圖提供唯一布局模型,例如線性布局(Linear Layout)沐序、網格布局(Grid Layout)或相對布局(Relative Layout)琉用。您還可以為 View 類和 ViewGroup 類創(chuàng)建子類(或使用其現有子類)來自行創(chuàng)建小工具和布局,然后將它們應用于您的 Activity 布局薄啥。
??利用視圖定義布局的最常見方法是借助保存在您的應用資源內的 XML 布局文件辕羽。這樣一來,您就可以將用戶界面的設計與定義 Activity 行為的源代碼分開維護垄惧。 您可以通過 setContentView()
將布局設置為 Activity 的 UI刁愿,從而傳遞布局的資源 ID。不過到逊,您也可以在 Activity 代碼中創(chuàng)建新 View铣口,并通過將新 View 插入 ViewGroup 來創(chuàng)建視圖層次,然后通過將根 ViewGroup 傳遞到 setContentView()來使用該布局觉壶。
??如需了解有關創(chuàng)建用戶界面的信息脑题,請參閱用戶界面文檔。
在清單文件中聲明 Activity
必須在清單文件中聲明您的 Activity铜靶,這樣系統(tǒng)才能訪問它叔遂。 要聲明您的 Activity,請打開您的清單文件争剿,并將<activity>
元素添加為 <application>
元素的子項已艰。例如:
<manifest ... >
<application ... >
<activity android:name=".ExampleActivity" />
...
</application ... >
...
</manifest >
您還可以在此元素中加入幾個其他特性,以定義 Activity 標簽蚕苇、Activity 圖標或風格主題等用于設置 Activity UI 風格的屬性哩掺。android:name
特性是唯一的必需特性—它指定 Activity 的類名。應用一旦發(fā)布涩笤,即不應更改此類名嚼吞,否則,可能會破壞諸如應用快捷方式等一些功能(請閱讀博客文章 Things That Cannot Change [不能更改的內容])蹬碧。
請參閱 <activity>
元素參考文檔舱禽,了解有關在清單文件中聲明 Activity 的詳細信息。
使用 Intent 過濾器
<activity>
元素還可指定各種 Intent 過濾器——使用 <Intent-filter>
元素——以聲明其他應用組件激活它的方法锰茉。當您使用 Android SDK 工具創(chuàng)建新應用時呢蔫,系統(tǒng)自動為您創(chuàng)建的存根 Activity 包含一個 Intent 過濾器,其中聲明了該 Activity 響應“主”操作且應置于“l(fā)auncher”類別內。 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>
<action>
元素指定這是應用的“主”入口點片吊。<category>
元素指定此 Activity 應列入系統(tǒng)的應用啟動器內(以便用戶啟動該 Activity)绽昏。
??如果您打算讓應用成為獨立應用,不允許其他應用激活其 Activity俏脊,則您不需要任何其他 Intent 過濾器全谤。 正如前例所示,只應有一個 Activity 具有“主”操作和“l(fā)auncher”類別爷贫。 您不想提供給其他應用的 Activity 不應有任何 Intent 過濾器认然,您可以利用顯式 Intent 自行啟動它們(下文對此做了闡述)。
??不過漫萄,如果您想讓 Activity 對衍生自其他應用(以及您的自有應用)的隱式 Intent 作出響應卷员,則必須為 Activity 定義其他 Intent 過濾器。 對于您想要作出響應的每一個 Intent 類型腾务,您都必須加入相應的 <Intent-filter>
毕骡,其中包括一個 <action>
元素,還可選擇性地包括一個 <category>
元素和/或一個 <data>
元素岩瘦。這些元素指定您的 Activity 可以響應的 Intent 類型未巫。
如需了解有關您的 Activity 如何響應 Intent 的詳細信息,請參閱 Intent 和 Intent 過濾器文檔启昧。
啟動 Activity
您可以通過調用 startActivity()
叙凡,并將其傳遞給描述您想啟動的 Activity 的 Intent 來啟動另一個 Activity。Intent 對象會指定您想啟動的具體 Activity 或描述您想執(zhí)行的操作類型(系統(tǒng)會為您選擇合適的 Activity密末,甚至是來自其他應用的 Activity)握爷。 Intent 對象還可能攜帶少量供所啟動 Activity 使用的數據。
??在您的自有應用內工作時严里,您經常只需要啟動某個已知 Activity饼拍。 您可以通過使用類名創(chuàng)建一個顯式定義您想啟動的 Activity 的 Intent 對象來實現此目的。 例如田炭,可以通過以下代碼讓一個 Activity 啟動另一個名為SignInActivity
的 Activity:
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
不過,您的應用可能還需要利用您的 Activity 數據執(zhí)行某項操作漓柑,例如發(fā)送電子郵件教硫、短信或狀態(tài)更新。 在這種情況下辆布,您的應用自身可能不具有執(zhí)行此類操作所需的 Activity瞬矩,因此您可以改為利用設備上其他應用提供的 Activity 為您執(zhí)行這些操作。 這便是 Intent 對象的真正價值所在——您可以創(chuàng)建一個 Intent 對象锋玲,對您想執(zhí)行的操作進行描述景用,系統(tǒng)會從其他應用啟動相應的 Activity。 如果有多個 Activity 可以處理 Intent,則用戶可以選擇要使用哪一個伞插。 例如割粮,如果您想允許用戶發(fā)送電子郵件,可以創(chuàng)建以下 Intent 對象:
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);
添加到 Intent 中的 EXTRA_EMAIL
extra 是一個字符串數組媚污,其中包含應將電子郵件發(fā)送到的電子郵件地址舀瓢。 當電子郵件應用響應此 Intent 時,它會讀取 extra 中提供的字符串數組耗美,并將它們放入電子郵件撰寫窗體的“收件人”字段京髓。 在這種情況下,電子郵件應用的 Activity 啟動商架,并且當用戶完成操作時堰怨,您的 Activity 會恢復執(zhí)行。
啟動 Activity 以獲得結果
有時蛇摸,您可能需要從啟動的 Activity 獲得結果备图。在這種情況下,請通過調用 startActivityForResult()
(而非startActivity()
)來啟動 Activity皇型。 要想在隨后收到后續(xù) Activity 的結果诬烹,請實現 onActivityResult()
回調方法。 當后續(xù) Activity 完成時弃鸦,它會使用 Intent
向您的 onActivityResult()
方法返回結果绞吁。
??例如,您可能希望用戶選取其中一位聯系人唬格,以便您的 Activity 對該聯系人中的信息執(zhí)行某項操作家破。 您可以通過以下代碼創(chuàng)建此類 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()
發(fā)送的第二個參數匹配喊积。 代碼通過查詢 Intent
中返回的數據(data 參數)從該處開始處理 Activity 結果烹困。
??實際情況是,ContentResolver
對一個內容提供程序執(zhí)行查詢乾吻,后者返回一個 Cursor
髓梅,讓查詢的數據能夠被讀取。如需了解詳細信息绎签,請參閱內容提供程序文檔枯饿。
如需了解有關 Intent 用法的詳細信息,請參閱 Intent 和 Intent 過濾器文檔诡必。
結束 Activity
您可以通過調用 Activity 的 finish()
方法來結束該 Activity奢方。您還可以通過調用 finishActivity()
結束您之前啟動的另一個 Activity。
注:在大多數情況下,您不應使用這些方法顯式結束 Activity蟋字。 正如下文有關 Activity 生命周期的部分所述稿蹲,Android 系統(tǒng)會為您管理 Activity 的生命周期,因此您無需完成自己的 Activity愉老。 調用這些方法可能對預期的用戶體驗產生不良影響司训,因此只應在您確實不想讓用戶返回此 Activity 實例時使用珊蟀。
管理 Activity 生命周期
通過實現回調方法管理 Activity 的生命周期對開發(fā)強大而又靈活的應用至關重要围详。 Activity 的生命周期會直接受到 Activity 與其他 Activity觉至、其任務及返回棧的關聯性的影響。
Activity 基本上以三種狀態(tài)存在:
- Resumed
此 Activity 位于屏幕前臺并具有用戶焦點咒林。(有時也將此狀態(tài)稱作“運行中”熬拒。)
- Paused
另一個 Activity 位于屏幕前臺并具有用戶焦點,但此 Activity 仍可見垫竞。也就是說澎粟,另一個 Activity 顯示在此 Activity 上方,并且該 Activity 部分透明或未覆蓋整個屏幕欢瞪。 已暫停的 Activity 處于完全 Activity 狀態(tài)(Activity 對象保留在內存中活烙,它保留了所有狀態(tài)和成員信息,并與窗口管理器保持連接)遣鼓,但在內存極度不足的情況下啸盏,可能會被系統(tǒng)終止。
- Stopped
該 Activity 被另一個 Activity 完全遮蓋(該 Activity 目前位于“后臺”)骑祟。 已停止的 Activity 同樣仍處于 Activity 狀態(tài)(Activity 對象保留在內存中回懦,它保留了所有狀態(tài)和成員信息,但未與窗口管理器連接)次企。 不過怯晕,它對用戶不再可見,在他處需要內存時可能會被系統(tǒng)終止缸棵。
如果 Activity 處于暫椭鄄瑁或停止狀態(tài),系統(tǒng)可通過要求其結束(調用其 finish()
方法)或直接終止其進程堵第,將其從內存中刪除稚晚。(將其結束或終止后)再次打開 Activity 時,必須重建型诚。
實現生命周期回調
當一個 Activity 轉入和轉出上述不同狀態(tài)時,系統(tǒng)會通過各種回調方法向其發(fā)出通知鸳劳。 所有回調方法都是掛鉤狰贯,您可以在 Activity 狀態(tài)發(fā)生變化時替代這些掛鉤來執(zhí)行相應操作。 以下框架 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 的整個生命周期。您可以通過實現這些方法監(jiān)控 Activity 生命周期中的三個嵌套循環(huán):
- Activity 的整個生命周期發(fā)生在
onCreate()
調用與onDestroy()
調用之間涵紊。您的 Activity 應在onCreate()
中執(zhí)行“全局”狀態(tài)設置(例如定義布局)傍妒,并釋放onDestroy()
中的所有其余資源。例如摸柄,如果您的 Activity 有一個在后臺運行的線程颤练,用于從網絡上下載數據,它可能會在onCreate()
中創(chuàng)建該線程驱负,然后在onDestroy()
中停止該線程嗦玖。 - Activity 的可見生命周期發(fā)生在
onStart()
調用與onStop()
調用之間。在這段時間跃脊,用戶可以在屏幕上看到 Activity 并與其交互宇挫。 例如,當一個新 Activity 啟動酪术,并且此 Activity 不再可見時器瘪,系統(tǒng)會調用onStop()
。您可以在調用這兩個方法之間保留向用戶顯示 Activity 所需的資源绘雁。 例如橡疼,您可以在onStart()
中注冊一個BroadcastReceiver
以監(jiān)控影響 UI 的變化,并在用戶無法再看到您顯示的內容時在onStop()
中將其取消注冊庐舟。在 Activity 的整個生命周期欣除,當 Activity 在對用戶可見和隱藏兩種狀態(tài)中交替變化時,系統(tǒng)可能會多次調用onStart()
和onStop()
继阻。 - Activity 的前臺生命周期發(fā)生在
onResume()
調用與onPause()
調用之間耻涛。在這段時間,Activity 位于屏幕上的所有其他 Activity 之前瘟檩,并具有用戶輸入焦點抹缕。 Activity 可頻繁轉入和轉出前臺—例如,當設備轉入休眠狀態(tài)或出現對話框時墨辛,系統(tǒng)會調用onPause()
卓研。 由于此狀態(tài)可能經常發(fā)生轉變,因此這兩個方法中應采用適度輕量級的代碼睹簇,以避免因轉變速度慢而讓用戶等待奏赘。
圖 1 說明了這些循環(huán)以及 Activity 在狀態(tài)轉變期間可能經過的路徑。矩形表示回調方法太惠,當 Activity 在不同狀態(tài)之間轉變時磨淌,您可以實現這些方法來執(zhí)行操作。
表 1 列出了相同的生命周期回調方法凿渊,其中對每一種回調方法做了更詳細的描述梁只,并說明了每一種方法在 Activity 整個生命周期內的位置缚柳,包括在回調方法完成后系統(tǒng)能否終止 Activity。
方法 | 描述 | 是否能事后終止 | 后接 |
---|---|---|---|
onCreate | 首次創(chuàng)建 Activity 時調用搪锣。 您應該在此方法中執(zhí)行所有正常的靜態(tài)設置— 創(chuàng)建視圖秋忙、將數據綁定到列表等等。系統(tǒng)向此方法傳遞一個 Bundle 對象构舟,其中包含 Activity 的上一狀態(tài)灰追,不過前提是捕獲了該狀態(tài)(請參閱后文的保存 Activity 狀態(tài))。始終后接 onStart() | 否 | onStart() |
onRestart | 在 Activity 已停止并即將再次啟動前調用狗超。始終后接 onStart() | 否 | onStart() |
onStart | 在 Activity 即將對用戶可見之前調用弹澎。如果 Activity 轉入前臺,則后接 onResume()抡谐,如果 Activity 轉入隱藏狀態(tài)裁奇,則后接 onStop()。 | 否 |
onResume() 或onStop()
|
onResume | 在 Activity 即將開始與用戶進行交互之前調用麦撵。 此時刽肠,Activity 處于 Activity 堆棧的頂層,并具有用戶輸入焦點免胃。始終后接 onPause()音五。 | 否 | onPause() |
onPause | 當系統(tǒng)即將開始繼續(xù)另一個 Activity 時調用。 此方法通常用于確認對持久性數據的未保存更改羔沙、停止動畫以及其他可能消耗 CPU 的內容躺涝,諸如此類。 它應該非常迅速地執(zhí)行所需操作扼雏,因為它返回后坚嗜,下一個 Activity 才能繼續(xù)執(zhí)行。如果 Activity 返回前臺诗充,則后接 onResume()苍蔬,如果 Activity 轉入對用戶不可見狀態(tài),則后接onStop()蝴蜓。 | 是 |
onResume() 或onStop()
|
onStop | Activity 對用戶不再可見時調用碟绑。如果 Activity 被銷毀,或另一個 Activity(一個現有 Activity 或新 Activity)繼續(xù)執(zhí)行并將其覆蓋茎匠,就可能發(fā)生這種情況格仲。如果 Activity 恢復與用戶的交互,則后接onRestart()诵冒,如果 Activity 被銷毀凯肋,則后接onDestroy()。 | 是 |
onRestart() 或onDestroy()
|
onDestroy | 在 Activity 被銷毀前調用汽馋。這是 Activity 將收到的最后調用侮东。 當 Activity 結束(有人調用 Activity 上的 finish())午笛,或系統(tǒng)為節(jié)省空間而暫時銷毀該 Activity 實例時,可能會調用它苗桂。 您可以通過 isFinishing() 方法區(qū)分這兩種情形。 | 是 | 無 |
名為“是否能事后終止告组?”的列表示系統(tǒng)是否能在不執(zhí)行另一行 Activity 代碼的情況下煤伟,在方法返回后隨時終止承載 Activity 的進程。 有三個方法帶有“是”標記:(onPause()
木缝、onStop()
和 onDestroy()
)便锨。由于 onPause()
是這三個方法中的第一個,因此 Activity 創(chuàng)建后我碟,onPause()
必定成為最后調用的方法放案,然后才能終止進程——如果系統(tǒng)在緊急情況下必須恢復內存,則可能不會調用 onStop()
和 onDestroy()
矫俺。因此吱殉,您應該使用 onPause()
向存儲設備寫入至關重要的持久性數據(例如用戶編輯)。不過厘托,您應該對 onPause()
調用期間必須保留的信息有所選擇友雳,因為該方法中的任何阻止過程都會妨礙向下一個 Activity 的轉變并拖慢用戶體驗。
??在是否能在事后終止铅匹?列中標記為“否”的方法可從系統(tǒng)調用它們的一刻起防止承載 Activity 的進程被終止押赊。 因此,在從 onPause()
返回的時間到 onResume()
被調用的時間包斑,系統(tǒng)可以終止 Activity流礁。在 onPause()
被再次調用并返回前,將無法再次終止 Activity罗丰。
注:根據表 1 中的定義屬于技術上無法“終止”的 Activity 仍可能被系統(tǒng)終止——但這種情況只有在無任何其他資源的極端情況下才會發(fā)生神帅。進程和線程處理文檔對可能會終止 Activity 的情況做了更詳盡的闡述。
保存 Activity 狀態(tài)
管理 Activity 生命周期的引言部分簡要提及丸卷,當 Activity 暫驼硐。或停止時,Activity 的狀態(tài)會得到保留谜嫉。 確實如此萎坷,因為當 Activity 暫停或停止時沐兰,Activity 對象仍保留在內存中 — 有關其成員和當前狀態(tài)的所有信息仍處于 Activity 狀態(tài)哆档。 因此,用戶在 Activity 內所做的任何更改都會得到保留住闯,這樣一來瓜浸,當 Activity 返回前臺(當它“繼續(xù)”)時澳淑,這些更改仍然存在。
??不過插佛,當系統(tǒng)為了恢復內存而銷毀某項 Activity 時杠巡,Activity 對象也會被銷毀,因此系統(tǒng)在繼續(xù) Activity 時根本無法讓其狀態(tài)保持完好雇寇,而是必須在用戶返回Activity時重建 Activity 對象氢拥。但用戶并不知道系統(tǒng)銷毀 Activity 后又對其進行了重建,因此他們很可能認為 Activity 狀態(tài)毫無變化锨侯。 在這種情況下嫩海,您可以實現另一個回調方法對有關 Activity 狀態(tài)的信息進行保存,以確保有關 Activity 狀態(tài)的重要信息得到保留:onSaveInstanceState()
囚痴。
??系統(tǒng)會先調用 onSaveInstanceState()
叁怪,然后再使 Activity 變得易于銷毀。系統(tǒng)會向該方法傳遞一個 Bundle
深滚,您可以在其中使用 putString()
和 putInt()
等方法以 名稱-值(key-value)對形式保存有關 Activity 狀態(tài)的信息奕谭。然后,如果系統(tǒng)終止您的應用進程成箫,并且用戶返回您的 Activity展箱,則系統(tǒng)會重建該 Activity,并將 Bundle
同時傳遞給 onCreate()
和 onRestoreInstanceState()
蹬昌。您可以使用上述任一方法從 Bundle
提取您保存的狀態(tài)并恢復該 Activity 狀態(tài)混驰。如果沒有狀態(tài)信息需要恢復,則傳遞給您的 Bundle 是空值(如果是首次創(chuàng)建該 Activity皂贩,就會出現這種情況)栖榨。
注:無法保證系統(tǒng)會在銷毀您的 Activity 前調用 onSaveInstanceState()愚争,因為存在不需要保存狀態(tài)的情況(例如用戶使用“返回” 按鈕離開您的 Activity 時,因為用戶的行為是在顯式關閉 Activity)挤聘。 如果系統(tǒng)調用
onSaveInstanceState()
轰枝,它會在調用onStop()
之前,并且可能會在調用onPause()
之前進行調用组去。
不過鞍陨,即使您什么都不做,也不實現 onSaveInstanceState()
从隆,Activity 類的 onSaveInstanceState()
默認實現也會恢復部分 Activity 狀態(tài)诚撵。具體地講缭裆,默認實現會為布局中的每個 View
調用相應的 onSaveInstanceState()
方法,讓每個視圖都能提供有關自身的應保存信息寿烟。Android 框架中幾乎每個Widget都會根據需要實現此方法澈驼,以便在重建 Activity 時自動保存和恢復對 UI 所做的任何可見更改。例如筛武,EditText Widget保存用戶輸入的任何文本盅藻,CheckBox
Widget保存復選框的選中或未選中狀態(tài)。您只需為想要保存其狀態(tài)的每個Widget提供一個唯一的 ID(通過 android:id
屬性)畅铭。如果Widget沒有 ID,則系統(tǒng)無法保存其狀態(tài)勃蜘。
您還可以通過將
android:saveEnabled
屬性設置為 "false" 或通過調用setSaveEnabled()
方法顯式阻止布局內的視圖保存其狀態(tài)硕噩。您通常不應將該屬性禁用,但如果您想以不同方式恢復 Activity UI 的狀態(tài)缭贡,就可能需要這樣做炉擅。
盡管 onSaveInstanceState()
的默認實現會保存有關您的Activity UI 的有用信息,您可能仍需替代它以保存更多信息阳惹。例如谍失,您可能需要保存在 Activity 生命周期內發(fā)生了變化的成員值(它們可能與 UI 中恢復的值有關聯,但默認情況下系統(tǒng)不會恢復儲存這些 UI 值的成員)莹汤。
由于 onSaveInstanceState()
的默認實現有助于保存 UI 的狀態(tài)快鱼, 因此如果您為了保存更多狀態(tài)信息而重寫該方法,應始終先調用 onSaveInstanceState()
的超類實現纲岭,然后再執(zhí)行任何操作抹竹。同樣,如果您替代 onRestoreInstanceState()
方法止潮,也應調用它的超類實現窃判,以便默認實現能夠恢復視圖狀態(tài)。
注:由于無法保證系統(tǒng)會調用
onSaveInstanceState()
喇闸,因此您只應利用它來記錄 Activity 的瞬態(tài)(UI 的狀態(tài))—切勿使用它來存儲持久性數據袄琳,而應使用onPause()
在用戶離開 Activity 后存儲持久性數據(例如應保存到數據庫的數據)。
您只需旋轉設備燃乍,讓屏幕方向發(fā)生變化唆樊,就能有效地測試您的應用的狀態(tài)恢復能力。 當屏幕方向變化時橘沥,系統(tǒng)會銷毀并重建 Activity窗轩,以便應用可供新屏幕配置使用的備用資源。 單憑這一理由座咆,您的 Activity 在重建時能否完全恢復其狀態(tài)就顯得非常重要痢艺,因為用戶在使用應用時經常需要旋轉屏幕仓洼。
處理配置變更
有些設備配置可能會在運行時發(fā)生變化(例如屏幕方向、鍵盤可用性及語言)堤舒。 發(fā)生此類變化時色建,Android 會重建運行中的 Activity(系統(tǒng)調用 onDestroy()
,然后立即調用 onCreate()
)舌缤。此行為旨在通過利用您提供的備用資源(例如適用于不同屏幕方向和屏幕尺寸的不同布局)自動重新加載您的應用來幫助它適應新配置箕戳。
??如果您對 Activity 進行了適當設計,讓它能夠按以上所述處理屏幕方向變化帶來的重啟并恢復 Activity 狀態(tài)国撵,那么在遭遇 Activity 生命周期中的其他意外事件時陵吸,您的應用將具有更強的適應性。
正如上文所述介牙,處理此類重啟的最佳方法 是利用 onSaveInstanceState()
和 onRestoreInstanceState()
(或onCreate()
)保存并恢復 Activity 的狀態(tài)壮虫。
??如需了解有關運行時發(fā)生的配置變更以及應對方法的詳細信息,請閱讀處理運行時變更指南环础。
協調 Activity
當一個 Activity 啟動另一個 Activity 時囚似,它們都會經歷生命周期轉變。第一個 Activity 暫停并停止(但如果它在后臺仍然可見线得,則不會停止)時饶唤,系統(tǒng)會創(chuàng)建另一個 Activity。 如果這些 Activity 共用保存到磁盤或其他地方的數據贯钩,必須了解的是募狂,在創(chuàng)建第二個 Activity 前,第一個 Activity 不會完全停止角雷。更確切地說熬尺,啟動第二個 Activity 的過程與停止第一個 Activity 的過程存在重疊。
??生命周期回調的順序經過明確定義谓罗,當兩個 Activity 位于同一進程粱哼,并且由一個 Activity 啟動另一個 Activity 時,其定義尤其明確檩咱。 以下是當 Activity A 啟動 Activity B 時一系列操作的發(fā)生順序:
- Activity A 的
onPause()
方法執(zhí)行揭措。 - Activity B 的
onCreate()
、onStart()
和onResume()
方法依次執(zhí)行刻蚯。(Activity B 現在具有用戶焦點绊含。) - 然后,如果 Activity A 在屏幕上不再可見炊汹,則其
onStop()
方法執(zhí)行躬充。
您可以利用這種可預測的生命周期回調順序管理從一個 Activity 到另一個 Activity 的信息轉變。 例如,如果您必須在第一個 Activity 停止時向數據庫寫入數據充甚,以便下一個 Activity 能夠讀取該數據以政,則應在 onPause()
而不是 onStop()
執(zhí)行期間向數據庫寫入數據。