[文章內(nèi)容來自Developers]
Activity
是一個應(yīng)用組件儡毕,用戶可與其提供的屏幕進(jìn)行交互病涨,以執(zhí)行撥打電話、拍攝照片靡菇、發(fā)送電子郵件或查看地圖等操作众雷。 每個 Activity 都會獲得一個用于繪制其用戶界面的窗口斗幼。窗口通常會充滿屏幕盈厘,但也可小于屏幕并浮動在其他窗口之上缝其。
一個應(yīng)用通常由多個彼此松散聯(lián)系的 Activity 組成私植。 一般會指定應(yīng)用中的某個 Activity 為“主”Activity忌栅,即首次啟動應(yīng)用時呈現(xiàn)給用戶的那個 Activity。 而且每個 Activity 均可啟動另一個 Activity,以便執(zhí)行不同的操作索绪。 每次新 Activity 啟動時湖员,前一 Activity 便會停止,但系統(tǒng)會在堆棧(“返回椚鹎”)中保留該 Activity娘摔。 當(dāng)新 Activity 啟動時,系統(tǒng)會將其推送到返回棧上唤反,并取得用戶焦點(diǎn)凳寺。 返回棧遵循基本的“后進(jìn)先出”堆棧機(jī)制,因此彤侍,當(dāng)用戶完成當(dāng)前 Activity 并按“返回”按鈕時肠缨,系統(tǒng)會從堆棧中將其彈出(并銷毀),然后恢復(fù)前一 Activity盏阶。(任務(wù)和返回棧文檔中對返回棧有更詳細(xì)的闡述晒奕。)
當(dāng)一個 Activity 因某個新 Activity 啟動而停止時,系統(tǒng)會通過該 Activity 的生命周期回調(diào)方法通知其這一狀態(tài)變化名斟。Activity 因狀態(tài)變化—系統(tǒng)是創(chuàng)建 Activity脑慧、停止 Activity、恢復(fù) Activity 還是銷毀 Activity— 而收到的回調(diào)方法可能有若干種砰盐,每一種回調(diào)都會為您提供執(zhí)行與該狀態(tài)變化相應(yīng)的特定操作的機(jī)會闷袒。 例如,停止時岩梳,您的 Activity 應(yīng)釋放任何大型對象囊骤,例如網(wǎng)絡(luò)或數(shù)據(jù)庫連接。 當(dāng) Activity 恢復(fù)時蒋腮,您可以重新獲取所需資源淘捡,并恢復(fù)執(zhí)行中斷的操作。 這些狀態(tài)轉(zhuǎn)變都是 Activity 生命周期的一部分池摧。
本文的其余部分闡述有關(guān)如何創(chuàng)建和使用 Activity 的基礎(chǔ)知識(包括對 Activity 生命周期工作方式的全面闡述)焦除,以便您正確管理各種 Activity 狀態(tài)之間的轉(zhuǎn)變。
創(chuàng)建 Activity
要創(chuàng)建 Activity作彤,您必須創(chuàng)建 Activity的子類(或使用其現(xiàn)有子類)膘魄。您需要在子類中實(shí)現(xiàn) Activity 在其生命周期的各種狀態(tài)之間轉(zhuǎn)變時(例如創(chuàng)建 Activity、停止 Activity竭讳、恢復(fù) Activity 或銷毀 Activity 時)系統(tǒng)調(diào)用的回調(diào)方法创葡。 兩個最重要的回調(diào)方法是:
onCreate()
您必須實(shí)現(xiàn)此方法。系統(tǒng)會在創(chuàng)建您的 Activity 時調(diào)用此方法绢慢。您應(yīng)該在實(shí)現(xiàn)內(nèi)初始化 Activity 的必需組件灿渴。 最重要的是,您必須在此方法內(nèi)調(diào)用 setContentView(),以定義 Activity 用戶界面的布局骚露。
onPause()
系統(tǒng)將此方法作為用戶離開 Activity 的第一個信號(但并不總是意味著 Activity 會被銷毀)進(jìn)行調(diào)用蹬挤。 您通常應(yīng)該在此方法內(nèi)確認(rèn)在當(dāng)前用戶會話結(jié)束后仍然有效的任何更改(因為用戶可能不會返回)。
您還應(yīng)使用幾種其他生命周期回調(diào)方法棘幸,以便提供流暢的 Activity 間用戶體驗焰扳,以及處理導(dǎo)致您的 Activity 停止甚至被銷毀的意外中斷。
實(shí)現(xiàn)用戶界面
Activity 的用戶界面是由層級式視圖 — 衍生自 View類的對象 — 提供的误续。每個視圖都控制 Activity 窗口內(nèi)的特定矩形空間吨悍,可對用戶交互作出響應(yīng)。 例如蹋嵌,視圖可以是在用戶觸摸時啟動某項操作的按鈕育瓜。您可以利用 Android 提供的許多現(xiàn)成視圖設(shè)計和組織您的布局⌒滥幔“小部件”是提供按鈕爆雹、文本字段停蕉、復(fù)選框或僅僅是一幅圖像等屏幕視覺(交互式)元素的視圖愕鼓。 “布局”是衍生自 ViewGroup的視圖,為其子視圖提供唯一布局模型慧起,例如線性布局菇晃、網(wǎng)格布局或相對布局。 您還可以為 View類和ViewGroup類創(chuàng)建子類(或使用其現(xiàn)有子類)來自行創(chuàng)建小部件和布局蚓挤,然后將它們應(yīng)用于您的 Activity 布局磺送。
利用視圖定義布局的最常見方法是借助保存在您的應(yīng)用資源內(nèi)的 XML 布局文件。這樣一來灿意,您就可以將用戶界面的設(shè)計與定義 Activity 行為的源代碼分開維護(hù)估灿。 您可以通過 setContentView()將布局設(shè)置為 Activity 的 UI,從而傳遞布局的資源 ID缤剧。不過馅袁,您也可以在 Activity 代碼中創(chuàng)建新 View,并通過將新 View插入 ViewGroup來創(chuàng)建視圖層次荒辕,然后通過將根 ViewGroup傳遞到 setContentView()來使用該布局汗销。
您必須在清單文件中聲明您的 Activity,這樣系統(tǒng)才能訪問它抵窒。 要聲明您的 Activity弛针,請打開您的清單文件,并將 <activity元素添加為<application>元素的子項李皇。例如:
<manifest ... >
<application ... >
<activity android:name=".ExampleActivity" />
...
</application ... >
...
</manifest >
您還可以在此元素中加入幾個其他特性削茁,以定義 Activity 標(biāo)簽、Activity 圖標(biāo)或風(fēng)格主題等用于設(shè)置 Activity UI 風(fēng)格的屬性。 android:name屬性是唯一必需的屬性—它指定 Activity 的類名茧跋。應(yīng)用一旦發(fā)布朦拖,即不應(yīng)更改此類名,否則厌衔,可能會破壞諸如應(yīng)用快捷方式等一些功能璧帝。
使用 Intent 過濾器<activity>元素還可指定各種 Intent 過濾器—使用 <intent-filter>元素—以聲明其他應(yīng)用組件激活它的方法。
當(dāng)您使用 Android SDK 工具創(chuàng)建新應(yīng)用時富寿,系統(tǒng)自動為您創(chuàng)建的存根 Activity 包含一個 Intent 過濾器睬隶,其中聲明了該 Activity 響應(yīng)“主”操作且應(yīng)置于“l(fā)auncher”類別內(nèi)。 Intent 過濾器的內(nèi)容如下所示:
<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>元素指定這是應(yīng)用的“主”入口點(diǎn)页徐。<category>元素指定此 Activity 應(yīng)列入系統(tǒng)的應(yīng)用啟動器內(nèi)(以便用戶啟動該 Activity)苏潜。如果您打算讓應(yīng)用成為獨(dú)立應(yīng)用,不允許其他應(yīng)用激活其Activity变勇,則您不需要任何其他 Intent 過濾器恤左。 正如前例所示,只應(yīng)有一個 Activity 具有“主”操作和“l(fā)auncher”類別搀绣。 您不想提供給其他應(yīng)用的 Activity 不應(yīng)有任何 Intent 過濾器飞袋,您可以利用顯式 Intent 自行啟動它們(下文對此做了闡述)。
不過链患,如果您想讓 Activity 對衍生自其他應(yīng)用(以及您的自有應(yīng)用)的隱式 Intent 作出響應(yīng)巧鸭,則必須為 Activity 定義其他 Intent 過濾器。 對于您想要作出響應(yīng)的每一個 Intent 類型麻捻,您都必須加入相應(yīng)的 <intent-filter>纲仍,其中包括一個 <action>元素,還可選擇性地包括一個 <category>元素和/或一個 <data>元素贸毕。這些元素指定您的 Activity 可以響應(yīng)的 Intent 類型郑叠。
啟動 Activity
您可以通過調(diào)用 startActivity(),并將其傳遞給描述您想啟動的 Activity 的 Intent來啟動另一個 Activity明棍。Intent 對象會指定您想啟動的具體 Activity 或描述您想執(zhí)行的操作類型(系統(tǒng)會為您選擇合適的 Activity乡革,甚至是來自其他應(yīng)用的 Activity)。 Intent 對象還可能攜帶少量供所啟動 Activity 使用的數(shù)據(jù)击蹲。
在您的自有應(yīng)用內(nèi)工作時署拟,您經(jīng)常只需要啟動某個已知 Activity。 您可以通過使用類名創(chuàng)建一個顯式定義您想啟動的 Activity 的 Intent 對象來實(shí)現(xiàn)此目的歌豺。 例如推穷,可以通過以下代碼讓一個 Activity 啟動另一個名為 SignInActivity的 Activity:
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
不過,您的應(yīng)用可能還需要利用您的 Activity 數(shù)據(jù)執(zhí)行某項操作类咧,例如發(fā)送電子郵件馒铃、短信或狀態(tài)更新蟹腾。 在這種情況下,您的應(yīng)用自身可能不具有執(zhí)行此類操作所需的 Activity区宇,因此您可以改為利用設(shè)備上其他應(yīng)用提供的 Activity 為您執(zhí)行這些操作娃殖。 這便是 Intent 對象的真正價值所在 — 您可以創(chuàng)建一個 Intent 對象,對您想執(zhí)行的操作進(jìn)行描述议谷,系統(tǒng)會從其他應(yīng)用啟動相應(yī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 是一個字符串?dāng)?shù)組逼裆,其中包含應(yīng)將電子郵件發(fā)送到的電子郵件地址郁稍。 當(dāng)電子郵件應(yīng)用響應(yīng)此 Intent 時,它會讀取 extra 中提供的字符串?dāng)?shù)組胜宇,并將它們放入電子郵件撰寫窗體的“收件人”字段耀怜。 在這種情況下,電子郵件應(yīng)用的 Activity 啟動桐愉,并且當(dāng)用戶完成操作時财破,您的 Activity 會恢復(fù)執(zhí)行。
啟動 Activity 以獲得結(jié)果
有時仅财,您可能需要從啟動的 Activity 獲得結(jié)果狈究。在這種情況下,請通過調(diào)用 startActivityForResult()(而非 startActivity()))來啟動 Activity盏求。 要想在隨后收到后續(xù) Activity 的結(jié)果,請實(shí)現(xiàn) onActivityResult()回調(diào)方法亿眠。 當(dāng)后續(xù) Activity 完成時碎罚,它會使用 Intent向您的 onActivityResult()方法返回結(jié)果。
例如纳像,您可能希望用戶選取其中一位聯(lián)系人荆烈,以便您的 Activity 對該聯(lián)系人中的信息執(zhí)行某項操作。 您可以通過以下代碼創(chuàng)建此類 Intent 并處理結(jié)果:
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 結(jié)果時應(yīng)該在 onActivityResult()方法中使用的基本邏輯憔购。 第一個條件檢查請求是否成功(如果成功,則resultCode將為 RESULT_OK以及此結(jié)果響應(yīng)的請求是否已知 — 在此情況下岔帽,requestCode與隨 startActivityForResult()發(fā)送的第二個參數(shù)匹配玫鸟。 代碼通過查詢 Intent中返回的數(shù)據(jù)(data參數(shù))從該處開始處理 Activity 結(jié)果。
實(shí)際情況是犀勒,ContentResolver對一個內(nèi)容提供程序執(zhí)行查詢屎飘,后者返回一個 Cursor妥曲,讓查詢的數(shù)據(jù)能夠被讀取。
結(jié)束 Activity
您可以通過調(diào)用 Activity 的 finish()方法來結(jié)束該 Activity钦购。您還可以通過調(diào)用 finishActivity()結(jié)束您之前啟動的另一個 Activity檐盟。
注:在大多數(shù)情況下,您不應(yīng)使用這些方法顯式結(jié)束 Activity押桃。 正如下文有關(guān) Activity 生命周期的部分所述葵萎,Android 系統(tǒng)會為您管理 Activity 的生命周期,因此您無需結(jié)束自己的 Activity唱凯。 調(diào)用這些方法可能對預(yù)期的用戶體驗產(chǎn)生不良影響陌宿,因此只應(yīng)在您確實(shí)不想讓用戶返回此 Activity 實(shí)例時使用。
管理 Activity 生命周期
通過實(shí)現(xiàn)回調(diào)方法管理 Activity 的生命周期對開發(fā)強(qiáng)大而又靈活的應(yīng)用至關(guān)重要波丰。 Activity 的生命周期會直接受到 Activity 與其他 Activity壳坪、其任務(wù)及返回棧的關(guān)聯(lián)性的影響。
Activity 基本上以三種狀態(tài)存在:
繼續(xù)
此 Activity 位于屏幕前臺并具有用戶焦點(diǎn)掰烟。(有時也將此狀態(tài)稱作“運(yùn)行中”爽蝴。)
暫停
另一個 Activity 位于屏幕前臺并具有用戶焦點(diǎn),但此 Activity 仍可見纫骑。也就是說蝎亚,另一個 Activity 顯示在此 Activity 上方,并且該 Activity 部分透明或未覆蓋整個屏幕先馆。 暫停的 Activity 處于完全活動狀態(tài)(Activity對象保留在內(nèi)存中发框,它保留了所有狀態(tài)和成員信息,并與窗口管理器保持連接)煤墙,但在內(nèi)存極度不足的情況下梅惯,可能會被系統(tǒng)終止。
停止
該 Activity 被另一個 Activity 完全遮蓋(該 Activity 目前位于“后臺”)仿野。 已停止的 Activity 同樣仍處于活動狀態(tài)(Activity對象保留在內(nèi)存中铣减,它保留了所有狀態(tài)和成員信息,但未與窗口管理器連接)脚作。 不過葫哗,它對用戶不再可見,在他處需要內(nèi)存時可能會被系統(tǒng)終止球涛。
如果 Activity 處于暫土诱耄或停止?fàn)顟B(tài),系統(tǒng)可通過要求其結(jié)束(調(diào)用其 finish()方法)或直接終止其進(jìn)程亿扁,將其從內(nèi)存中刪除捺典。(將其結(jié)束或終止后)再次打開 Activity 時,必須重建魏烫。
實(shí)現(xiàn)生命周期回調(diào)
當(dāng)一個 Activity 轉(zhuǎn)入和轉(zhuǎn)出上述不同狀態(tài)時辣苏,系統(tǒng)會通過各種回調(diào)方法向其發(fā)出通知肝箱。 所有回調(diào)方法都是掛鉤,您可以在 Activity 狀態(tài)發(fā)生變化時替代這些掛鉤來執(zhí)行相應(yīng)操作稀蟋。 以下框架 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.
}}
注:正如以上示例所示煌张,您在實(shí)現(xiàn)這些生命周期方法時必須始終先調(diào)用超類實(shí)現(xiàn),然后再執(zhí)行任何操作退客。
這些方法共同定義 Activity 的整個生命周期骏融。您可以通過實(shí)現(xiàn)這些方法監(jiān)控 Activity 生命周期中的三個嵌套循環(huán):
Activity 的整個生命周期發(fā)生在 onCreate()調(diào)用與 onDestroy()調(diào)用之間。您的 Activity 應(yīng)在 onCreate()中執(zhí)行“全局”狀態(tài)設(shè)置(例如定義布局)萌狂,并釋放 onDestroy()中的所有其余資源档玻。例如,如果您的 Activity 有一個在后臺運(yùn)行的線程茫藏,用于從網(wǎng)絡(luò)上下載數(shù)據(jù)误趴,它可能會在onCreate()中創(chuàng)建該線程,然后在 onDestroy()中停止該線程务傲。
Activity 的可見生命周期發(fā)生在 onStart()調(diào)用與 onStop()調(diào)用之間凉当。在這段時間,用戶可以在屏幕上看到 Activity 并與其交互售葡。 例如看杭,當(dāng)一個新 Activity 啟動,并且此 Activity 不再可見時挟伙,系統(tǒng)會調(diào)用 onStop()楼雹。您可以在調(diào)用這兩個方法之間保留向用戶顯示 Activity 所需的資源。 例如尖阔,您可以在 onStart()中注冊一個 BroadcastReceiver以監(jiān)控影響 UI 的變化贮缅,并在用戶無法再看到您顯示的內(nèi)容時在 onStop()中將其取消注冊。在 Activity 的整個生命周期诺祸,當(dāng) Activity 在對用戶可見和隱藏兩種狀態(tài)中交替變化時携悯,系統(tǒng)可能會多次調(diào)用 onStart() 和 onStop()。
Activity 的前臺生命周期發(fā)生在 onResume()調(diào)用與 onPause()調(diào)用之間筷笨。在這段時間,Activity 位于屏幕上的所有其他 Activity 之前龟劲,并具有用戶輸入焦點(diǎn)胃夏。 Activity 可頻繁轉(zhuǎn)入和轉(zhuǎn)出前臺 — 例如,當(dāng)設(shè)備轉(zhuǎn)入休眠狀態(tài)或出現(xiàn)對話框時昌跌,系統(tǒng)會調(diào)用 onPause()仰禀。 由于此狀態(tài)可能經(jīng)常發(fā)生轉(zhuǎn)變,因此這兩個方法中應(yīng)采用適度輕量級的代碼蚕愤,以避免因轉(zhuǎn)變速度慢而讓用戶等待答恶。
圖 1 說明了這些循環(huán)以及 Activity 在狀態(tài)轉(zhuǎn)變期間可能經(jīng)過的路徑饺蚊。矩形表示回調(diào)方法,當(dāng) Activity 在不同狀態(tài)之間轉(zhuǎn)變時悬嗓,您可以實(shí)現(xiàn)這些方法來執(zhí)行操作污呼。
圖 1. Activity 生命周期。
表 1 列出了相同的生命周期回調(diào)方法包竹,其中對每一種回調(diào)方法做了更詳細(xì)的描述燕酷,并說明了每一種方法在 Activity 整個生命周期內(nèi)的位置,包括在回調(diào)方法完成后系統(tǒng)能否終止 Activity周瞎。
表 1. Activity 生命周期回調(diào)方法匯總表苗缩。
| 方法 | 說明 | 是否能事后終止? | 后接 |
| ------------- | :-------------:| -----:|
| onCreate() |首次創(chuàng)建 Activity 時調(diào)用声诸。 您應(yīng)該在此方法中執(zhí)行所有正常的靜態(tài)設(shè)置 — 創(chuàng)建視圖酱讶、將數(shù)據(jù)綁定到列表等等。 系統(tǒng)向此方法傳遞一個 Bundle 對象彼乌,其中包含 Activity 的上一狀態(tài)泻肯,不過前提是捕獲了該狀態(tài)。始終后接 onStart()囤攀。 |否|onStart()|
|onRestart()|在 Activity 已停止并即將再次啟動前調(diào)用软免。始終后接 onStart()|否|onStart()|
|onStart()|在 Activity 即將對用戶可見之前調(diào)用。如果 Activity 轉(zhuǎn)入前臺焚挠,則后接 onResume()膏萧,如果 Activity 轉(zhuǎn)入隱藏狀態(tài),則后接 onStop()蝌衔。|否|onResume()或onStop()
|onResume()|在 Activity 即將開始與用戶進(jìn)行交互之前調(diào)用榛泛。 此時,Activity 處于 Activity 堆棧的頂層噩斟,并具有用戶輸入焦點(diǎn)曹锨。始終后接 onPause()。|否|onPause()
|onPause()|當(dāng)系統(tǒng)即將開始繼續(xù)另一個 Activity 時調(diào)用剃允。 此方法通常用于確認(rèn)對持久性數(shù)據(jù)的未保存更改沛简、停止動畫以及其他可能消耗 CPU 的內(nèi)容,諸如此類斥废。 它應(yīng)該非常迅速地執(zhí)行所需操作椒楣,因為它返回后,下一個 Activity 才能繼續(xù)執(zhí)行牡肉。如果 Activity 返回前臺捧灰,則后接 onResume(),如果 Activity 轉(zhuǎn)入對用戶不可見狀態(tài)统锤,則后接 onStop()|是|onResume()或onStop()
|onStop()|在 Activity 對用戶不再可見時調(diào)用毛俏。如果 Activity 被銷毀炭庙,或另一個 Activity(一個現(xiàn)有 Activity 或新 Activity)繼續(xù)執(zhí)行并將其覆蓋,就可能發(fā)生這種情況煌寇。如果 Activity 恢復(fù)與用戶的交互焕蹄,則后接 onRestart(),如果 Activity 被銷毀唧席,則后接onDestroy()擦盾。|是|onRestart()或onDestroy()
|onDestroy()|在 Activity 被銷毀前調(diào)用。這是 Activity 將收到的最后調(diào)用淌哟。 當(dāng) Activity 結(jié)束(有人對 Activity 調(diào)用了 finish())迹卢,或系統(tǒng)為節(jié)省空間而暫時銷毀該 Activity 實(shí)例時,可能會調(diào)用它徒仓。 您可以通過 isFinishing()方法區(qū)分這兩種情形腐碱。|是|無
名為“是否能事后終止?”的列表示系統(tǒng)是否能在不執(zhí)行另一行 Activity 代碼的情況下掉弛,在方法返回后隨時終止承載 Activity 的進(jìn)程症见。 有三個方法帶有“是”標(biāo)記:(onPause()、onStop()和 onDestroy()
)殃饿。由于 onPause()是這三個方法中的第一個谋作,因此 Activity 創(chuàng)建后,onPause()必定成為最后調(diào)用的方法乎芳,然后才能終止進(jìn)程 — 如果系統(tǒng)在緊急情況下必須恢復(fù)內(nèi)存遵蚜,則可能不會調(diào)用 onStop()和 onDestroy()。因此奈惑,您應(yīng)該使用 onPause()向存儲設(shè)備寫入至關(guān)重要的持久性數(shù)據(jù)(例如用戶編輯)吭净。不過,您應(yīng)該對 onPause()調(diào)用期間必須保留的信息有所選擇肴甸,因為該方法中的任何阻止過程都會妨礙向下一個 Activity 的轉(zhuǎn)變并拖慢用戶體驗寂殉。
在是否能在事后終止?**列中標(biāo)記為“否”的方法可從系統(tǒng)調(diào)用它們的一刻起防止承載 Activity 的進(jìn)程被終止原在。 因此友扰,在從 onPause()返回的時間到 onResume()被調(diào)用的時間,系統(tǒng)可以終止 Activity庶柿。在 onPause()被再次調(diào)用并返回前焕檬,將無法再次終止 Activity。
注:根據(jù)表 1 中的定義屬于技術(shù)上無法“終止”的 Activity 仍可能被系統(tǒng)終止 — 但這種情況只有在無任何其他資源的極端情況下才會發(fā)生澳泵。進(jìn)程和線程處理文檔對可能會終止 Activity 的情況做了更詳盡的闡述。
保存 Activity 狀態(tài)
管理 Activity 生命周期的引言部分簡要提及兼呵,當(dāng) Activity 暫屯酶ǎ或停止時腊敲,Activity 的狀態(tài)會得到保留。 確實(shí)如此维苔,因為當(dāng) Activity 暫团龈ǎ或停止時,Activity對象仍保留在內(nèi)存中 — 有關(guān)其成員和當(dāng)前狀態(tài)的所有信息仍處于活動狀態(tài)介时。 因此没宾,用戶在 Activity 內(nèi)所做的任何更改都會得到保留,這樣一來沸柔,當(dāng) Activity 返回前臺(當(dāng)它“繼續(xù)”)時循衰,這些更改仍然存在。
不過褐澎,當(dāng)系統(tǒng)為了恢復(fù)內(nèi)存而銷毀某項 Activity 時会钝,Activity對象也會被銷毀,因此系統(tǒng)在繼續(xù) Activity 時根本無法讓其狀態(tài)保持完好工三,而是必須在用戶返回 Activity 時重建 Activity對象迁酸。但用戶并不知道系統(tǒng)銷毀 Activity 后又對其進(jìn)行了重建,因此他們很可能認(rèn)為 Activity 狀態(tài)毫無變化俭正。 在這種情況下奸鬓,您可以實(shí)現(xiàn)另一個回調(diào)方法對有關(guān) Activity 狀態(tài)的信息進(jìn)行保存,以確保有關(guān) Activity 狀態(tài)的重要信息得到保留:onSaveInstanceState()掸读。
系統(tǒng)會先調(diào)用 onSaveInstanceState()串远,然后再使 Activity 變得易于銷毀。系統(tǒng)會向該方法傳遞一個 Bundle寺枉,您可以在其中使用 putString()和 putInt()等方法以名稱-值對形式保存有關(guān) Activity 狀態(tài)的信息抑淫。然后,如果系統(tǒng)終止您的應(yīng)用進(jìn)程姥闪,并且用戶返回您的 Activity始苇,則系統(tǒng)會重建該 Activity,并將 Bundle同時傳遞給 onCreate()和 onRestoreInstanceState()筐喳。您可以使用上述任一方法從 Bundle提取您保存的狀態(tài)并恢復(fù)該 Activity 狀態(tài)催式。如果沒有狀態(tài)信息需要恢復(fù),則傳遞給您的 Bundle是空值(如果是首次創(chuàng)建該 Activity避归,就會出現(xiàn)這種情況)荣月。
注:無法保證系統(tǒng)會在銷毀您的 Activity 前調(diào)用 onSaveInstanceState()萌业,因為存在不需要保存狀態(tài)的情況(例如用戶使用“返回”按鈕離開您的 Activity 時坷襟,因為用戶的行為是在顯式關(guān)閉 Activity)。 **如果系統(tǒng)調(diào)用 onSaveInstanceState()生年,它會在調(diào)用 onStop()之前婴程,并且可能會在調(diào)用 onPause()之前進(jìn)行調(diào)用。
不過抱婉,即使您什么都不做档叔,也不實(shí)現(xiàn) onSaveInstanceState(),Activity類的 onSaveInstanceState()默認(rèn)實(shí)現(xiàn)也會恢復(fù)部分 Activity 狀態(tài)蒸绩。具體地講衙四,默認(rèn)實(shí)現(xiàn)會為布局中的每個 View調(diào)用相應(yīng)的 onSaveInstanceState()方法,讓每個視圖都能提供有關(guān)自身的應(yīng)保存信息侵贵。Android 框架中幾乎每個小部件都會根據(jù)需要實(shí)現(xiàn)此方法届搁,以便在重建 Activity 時自動保存和恢復(fù)對 UI 所做的任何可見更改。例如窍育,EditText小部件保存用戶輸入的任何文本卡睦,CheckBox小部件保存復(fù)選框的選中或未選中狀態(tài)。您只需為想要保存其狀態(tài)的每個小部件提供一個唯一的 ID(通過 android:id屬性)漱抓。如果小部件沒有 ID表锻,則系統(tǒng)無法保存其狀態(tài)。
您還可以通過將android:saveEnabled屬性設(shè)置為 "false"
或通過調(diào)用 setSaveEnabled()方法顯式阻止布局內(nèi)的視圖保存其狀態(tài)乞娄。您通常不應(yīng)將該屬性停用瞬逊,但如果您想以不同方式恢復(fù) Activity UI 的狀態(tài),就可能需要這樣做仪或。
盡管 onSaveInstanceState()的默認(rèn)實(shí)現(xiàn)會保存有關(guān)您的Activity UI 的有用信息确镊,您可能仍需替換它以保存更多信息。例如范删,您可能需要保存在 Activity 生命周期內(nèi)發(fā)生了變化的成員值(它們可能與 UI 中恢復(fù)的值有關(guān)聯(lián)蕾域,但默認(rèn)情況下系統(tǒng)不會恢復(fù)儲存這些 UI 值的成員)。
由于 onSaveInstanceState()的默認(rèn)實(shí)現(xiàn)有助于保存 UI 的狀態(tài)到旦,因此如果您為了保存更多狀態(tài)信息而替換該方法旨巷,應(yīng)始終先調(diào)用 onSaveInstanceState()的超類實(shí)現(xiàn),然后再執(zhí)行任何操作添忘。 同樣采呐,如果您替換 onRestoreInstanceState()方法,也應(yīng)調(diào)用它的超類實(shí)現(xiàn)搁骑,以便默認(rèn)實(shí)現(xiàn)能夠恢復(fù)視圖狀態(tài)斧吐。
注:由于無法保證系統(tǒng)會調(diào)用 onSaveInstanceState()又固,因此您只應(yīng)利用它來記錄 Activity 的瞬態(tài)(UI 的狀態(tài))— 切勿使用它來存儲持久性數(shù)據(jù),而應(yīng)使用 onPause()在用戶離開 Activity 后存儲持久性數(shù)據(jù)(例如應(yīng)保存到數(shù)據(jù)庫的數(shù)據(jù))会通。
您只需旋轉(zhuǎn)設(shè)備口予,讓屏幕方向發(fā)生變化,就能有效地測試您的應(yīng)用的狀態(tài)恢復(fù)能力涕侈。 當(dāng)屏幕方向變化時,系統(tǒng)會銷毀并重建 Activity煤辨,以便應(yīng)用可供新屏幕配置使用的備用資源裳涛。 單憑這一理由,您的 Activity 在重建時能否完全恢復(fù)其狀態(tài)就顯得非常重要众辨,因為用戶在使用應(yīng)用時經(jīng)常需要旋轉(zhuǎn)屏幕端三。
處理配置變更
有些設(shè)備配置可能會在運(yùn)行時發(fā)生變化(例如屏幕方向、鍵盤可用性及語言)鹃彻。 發(fā)生此類變化時郊闯,Android 會重建運(yùn)行中的 Activity(系統(tǒng)調(diào)用onDestroy(),然后立即調(diào)用 onCreate())蛛株。此行為旨在通過利用您提供的備用資源(例如適用于不同屏幕方向和屏幕尺寸的不同布局)自動重新加載您的應(yīng)用來幫助它適應(yīng)新配置团赁。
如果您對 Activity 進(jìn)行了適當(dāng)設(shè)計,讓它能夠按以上所述處理屏幕方向變化帶來的重啟并恢復(fù) Activity 狀態(tài)谨履,那么在遭遇 Activity 生命周期中的其他意外事件時欢摄,您的應(yīng)用將具有更強(qiáng)的適應(yīng)性。
正如上文所述笋粟,處理此類重啟的最佳方法是利用onSaveInstanceState()和 onRestoreInstanceState()(或 onCreate())保存并恢復(fù) Activity 的狀態(tài)怀挠。
協(xié)調(diào) Activity
當(dāng)一個 Activity 啟動另一個 Activity 時,它們都會體驗到生命周期轉(zhuǎn)變害捕。第一個 Activity 暫停并停止(但如果它在后臺仍然可見绿淋,則不會停止)時,同時系統(tǒng)會創(chuàng)建另一個 Activity尝盼。 如果這些 Activity 共用保存到磁盤或其他地方的數(shù)據(jù)吞滞,必須了解的是,在創(chuàng)建第二個 Activity 前东涡,第一個 Activity 不會完全停止冯吓。更確切地說,啟動第二個 Activity 的過程與停止第一個 Activity 的過程存在重疊疮跑。
生命周期回調(diào)的順序經(jīng)過明確定義组贺,當(dāng)兩個 Activity 位于同一進(jìn)程,并且由一個 Activity 啟動另一個 Activity 時祖娘,其定義尤其明確失尖。 以下是當(dāng) Activity A 啟動 Activity B 時一系列操作的發(fā)生順序:
Activity A 的 onPause()方法執(zhí)行啊奄。
Activity B 的 onCreate()、onStart()和 onResume()方法依次執(zhí)行掀潮。(Activity B 現(xiàn)在具有用戶焦點(diǎn)菇夸。)
然后,如果 Activity A 在屏幕上不再可見仪吧,則其 onStop()方法執(zhí)行庄新。
您可以利用這種可預(yù)測的生命周期回調(diào)順序管理從一個 Activity 到另一個 Activity 的信息轉(zhuǎn)變。 例如薯鼠,如果您必須在第一個 Activity 停止時向數(shù)據(jù)庫寫入數(shù)據(jù)择诈,以便下一個 Activity 能夠讀取該數(shù)據(jù),則應(yīng)在 onPause()而不是 onStop()執(zhí)行期間向數(shù)據(jù)庫寫入數(shù)據(jù)出皇。