AndroidAPI中Activity的一些內(nèi)容凫海,詳情:android API
<h3>概述:</h3>
Activity是這樣一個(gè)程序組件,它為用戶提供一個(gè)用于任務(wù)交互的畫面漾稀。例如崭捍,撥打電話殷蛇,拍照粒梦,發(fā)郵件〗闪埽或者查看地圖重抖。每一個(gè)activity都被分配一個(gè)窗口钟沛。在這個(gè)窗口里讹剔,你可以繪制用戶交互的內(nèi)容详民。 這個(gè)窗口通常占滿屏幕沈跨,但也有可能比屏幕小饿凛,并且浮在其它窗口的上面涧窒。
一個(gè)應(yīng)用程序通常由多個(gè)activity組成纠吴,它們彼此保持弱的綁定狀態(tài)戴已。典型的锅减,當(dāng)一個(gè)activity在一個(gè)應(yīng)用程序內(nèi)被指定為主activity, 那么當(dāng)程序第一次啟動(dòng)時(shí)怔匣,它將第一個(gè)展現(xiàn)在用戶面前。為了展現(xiàn)不同的內(nèi)容永部,每一個(gè)activity可以啟動(dòng)另外一個(gè)苔埋。 每當(dāng)一個(gè)新的activity被啟動(dòng)组橄,那么之前的將被停止罚随。但系統(tǒng)將會(huì)把它壓入一個(gè)棧(“back stack”即后退棧),當(dāng)一個(gè)新的activity啟動(dòng)淘菩,它將被 放到棧頂并獲得用戶焦點(diǎn)潮改。后臺(tái)棧遵循后進(jìn)先出的棧機(jī)制汇在。所以當(dāng)用戶完成當(dāng)前頁面并按下返回按鈕時(shí)糕殉,它將被pop出棧(并銷毀)阿蝶,之前的activity將被恢復(fù)羡洁。 (關(guān)于后退棧的更多討論在任務(wù)和后退棧)
當(dāng)一個(gè)activity因?yàn)榱硪粋€(gè)activity的啟動(dòng)而被停止焚廊,那么其生命周期中的回調(diào)方法咆瘟,將會(huì)以狀態(tài)改變的形式被調(diào)用。 activity通過它自身狀態(tài)的改變可以收到多個(gè)回調(diào)方法飞蛹。當(dāng)系統(tǒng)創(chuàng)建卧檐,停止霉囚,恢復(fù)盈罐,銷毀它的時(shí)候盅粪。并且每個(gè)回調(diào)方法都給你做相應(yīng)處理工作的機(jī)會(huì)票顾。 例如奠骄,當(dāng)停止的時(shí)候戚揭,你的activity應(yīng)當(dāng)釋放比較大的對(duì)象民晒,例如網(wǎng)絡(luò)連接锄禽,數(shù)據(jù)連接沃但。當(dāng)你的activity恢復(fù)時(shí)宵晚,你可以請(qǐng)求必須的資源并恢復(fù)一些被打斷的動(dòng)作晒他。 這些狀態(tài)事務(wù)的處理就構(gòu)成了activity的生命周期逸贾。
接下來將討論如何搭建和使用activity,完整討論activity的生命周期是怎么工作的,這樣你就可以合理地管理不同activity狀態(tài)間的事務(wù)處理触徐。
<h4 id=“1”>1.創(chuàng)建一個(gè)Activity</h4>
要?jiǎng)?chuàng)建一個(gè)activity,你必須創(chuàng)建一個(gè)Activity
(或者它存在的子類)的子類。 在你的子類里孔祸,你需要實(shí)現(xiàn)系統(tǒng)調(diào)用的回調(diào)方法发皿,這些方法用于activity在生命周期中進(jìn)行事務(wù)處理穴墅。例如創(chuàng)建玄货,停止松捉,恢復(fù)隘世,銷毀丙者。其中兩個(gè)最重要的回調(diào)方法分別為:
onCreate()
你必須實(shí)現(xiàn)這個(gè)方法械媒。系統(tǒng)會(huì)在創(chuàng)建activity的時(shí)候調(diào)用這個(gè)方法纷捞。 在實(shí)現(xiàn)這個(gè)方法的同時(shí)主儡,你需要實(shí)現(xiàn)你activity的重要組件缀辩。 最重要的是瓢阴,你必須在這里調(diào)用 setContentView()來定義你activity用于用戶交互的布局。
onPause()
系統(tǒng)將會(huì)調(diào)用這個(gè)方法作為用戶離開activity的首先提示(雖然這并不意味著activity正在被銷毀)液斜。這通常是你應(yīng)該在用戶會(huì)話之前提交并保存任何更改的時(shí)機(jī)。 (因?yàn)橛脩艨赡懿粫?huì)再回到這個(gè)activity).
你還應(yīng)該會(huì)用到一些其他的生命周期回調(diào)方法示损,它們將幫助你在activity和可能導(dǎo)致你的activity停止甚至銷毀之間保持流暢的用戶體驗(yàn)检访。 所有的生命周期回調(diào)方法都將在后面討論脆贵。
<h4 id=“2”>2.實(shí)現(xiàn)一個(gè)用戶交互界面</h4>
activity的用戶接口由一些View的派生類組成的層級(jí)結(jié)構(gòu)提供卖氨。 每一個(gè)view控制acitivity所在window的一個(gè)特殊的矩形空間筒捺。并且可以響應(yīng)用戶的交互焙矛。 例如,一個(gè)view可能是一個(gè)按鈕抛猫,當(dāng)用戶碰觸的時(shí)候?qū)l(fā)起動(dòng)作。
"Layouts"是一組繼承了ViewGroup的布局败匹。它們?yōu)樽右晥D提供了唯一的布局模型掀亩。 例如線性布局槽棍,表格布局炼七,相對(duì)布局豌拙。你也可以繼承View和ViewGroup
(或它們的子類)去創(chuàng)建你自己的組件或布局按傅,并用它們組成activity布局逞敷。
定義布局最常用的方式是使用XML布局文件推捐,它保存在你程序的資源中牛柒。這種方式可以保證你的業(yè)務(wù)邏輯代碼和用戶交互界面分開椭更。你可以通過setContentView()
傳遞布局文件的ID來設(shè)置程序UI虑瀑。 當(dāng)然,你也可以在activity代碼里自己新建View
滴须,并通過插入子View到ViewGroup舌狗。 然后把這些視圖的根視圖傳入到setContentView()。
<h4 id=“3”>3.使用filter</h4>
<activity> 也可以用很多<intent-filter>來指定其他的組件怎樣激活它扔水。當(dāng)你使用Android SDK tools來創(chuàng)建一個(gè)程序痛侍,主activity將會(huì)自動(dòng)包含一個(gè)被分類為"launcher"的intent filter,如下:
<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應(yīng)該被列如系統(tǒng)的啟動(dòng)器(launcher)(允許用戶啟動(dòng)它)
如果你想要你的程序更加獨(dú)立赵哲,并不想讓其他程序訪問你的activity,那么你就不必聲明intent filter,只有一個(gè)activity 應(yīng)該有"main"action和"launcher"分類,例如上述例子君丁。你不想公開的activity應(yīng)該不包含任何intent filter.但你可以使用明確 的intent來啟動(dòng)它們枫夺。(下文將詳述)。
然而谈截,如果你想要你的activity響應(yīng)其他程序(或當(dāng)前程序)的隱式intent,你必須為activity定義額外的intent filter筷屡。 每一個(gè)你想響應(yīng)的intent,都必須包含一個(gè) <intent-filter> ,并包含一個(gè) <action> 元素簸喂,另外毙死,可以包含一個(gè) <category> 也可以包含一個(gè) <data> 元素。 這些元素指定了intent 的類型喻鳄。
<h4 id=“4”>4.在manifest中聲明activity</h4>
為了能讓系統(tǒng)訪問到你的activity扼倘,必須在manifest文件里對(duì)其進(jìn)行聲明。 要聲明activity除呵,請(qǐng)打開你的mainifest文件并添加一個(gè) <activity> 元素再菊,它必須是<application>元素的子元素。例如:
<manifest ... >
<application ... >
<activity android:name=".ExampleActivity" />
...
</application ... >
...
</manifest >
該元素中還可以包含很多其它的屬性颜曾,用于定義諸如activity的label纠拔、activity的圖標(biāo)、activity UI的外觀theme之類泛豪。 android:name 屬性是唯一必需的屬性——它定義了activity的類名稠诲。應(yīng)用程序一經(jīng)發(fā)布,你就不得修改此名稱了诡曙。 假如修改了名稱臀叙,就可能破壞了某些功能,比如應(yīng)用程序的快捷方式
<h4 id=“5”>5.啟動(dòng)activity</h4>
可以通過調(diào)用 startActivity() 來啟動(dòng)另一個(gè)activity价卤,調(diào)用時(shí)傳遞一個(gè)描述了所要啟動(dòng)activity的 Intent 劝萤。這個(gè)intent或是精確指定了所要啟動(dòng)的activity,或是指明了需要執(zhí)行的action類型 (然后系統(tǒng)會(huì)為你選擇一個(gè)合適的activity慎璧,甚至可以是其它應(yīng)用程序中的activity)床嫌。 intent還可以攜帶少量的數(shù)據(jù),這些數(shù)據(jù)可被所啟動(dòng)的activity使用炸卑。
當(dāng)應(yīng)用程序運(yùn)行時(shí)既鞠,經(jīng)常會(huì)需要能夠便捷地啟動(dòng)其它已知的activity。 這只要通過創(chuàng)建一個(gè)顯式的intent即可盖文,這個(gè)intent用類名明確指定了你想要啟動(dòng)的activity。 例如蚯姆,下面是一個(gè)activity如何啟動(dòng)另一個(gè)名為SignInActivity的activity:
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
不過五续,你的應(yīng)用程序也許還需要執(zhí)行一些其它的action洒敏,比如發(fā)送一個(gè)email、文本信息或者狀態(tài)更新信息之類疙驾,而這些action又需要用到你的activity中的數(shù)據(jù)凶伙。 這種情況下,你的應(yīng)用程序本身可能不存在執(zhí)行這些action的activity它碎,所以你可以 利用本設(shè)備上其它應(yīng)用提供的activity來為你執(zhí)行這些動(dòng)作函荣。 這就是intent真正有價(jià)值的地方——你可以創(chuàng)建一個(gè)說明了你要執(zhí)行action的intent, 而系統(tǒng)會(huì)從其它應(yīng)用程序中啟動(dòng)一個(gè)合適的activity扳肛。 如果存在多個(gè)activity都能夠處理此intent傻挂,那么用戶可以自己選擇一個(gè)來執(zhí)行。 例如挖息,如果你想要允許用戶發(fā)送一個(gè)email信息金拒,可創(chuàng)建如下的intent:
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);
附加在intent的extra部分中的EXTRA_EMAIL信息是一個(gè)有關(guān)email目標(biāo)地址的字符串?dāng)?shù)組。 當(dāng)email應(yīng)用程序響應(yīng)這個(gè)intent時(shí)套腹, 它會(huì)讀取extra部分中的字符串?dāng)?shù)組并將它們填入撰寫email表單中的“to”字段绪抛。 在這種情況下,email應(yīng)用程序的activity將會(huì)被啟動(dòng)电禀。并且當(dāng)用戶完成發(fā)送后幢码,你的activity將會(huì)恢復(fù)運(yùn)行。
<h4 id=“6”>6. 啟動(dòng)activity并返回結(jié)果</h4>
有時(shí)你可能需要從你啟動(dòng)的activity里返回一個(gè)結(jié)果尖飞。 這種情況下症副,請(qǐng)通過調(diào)用 startActivityForResult() 來啟動(dòng)一個(gè)activity(而不是 startActivity() )。然后葫松,要想從被啟動(dòng)的activity里接收到結(jié)果瓦糕,請(qǐng)實(shí)現(xiàn) onActivityResult() 回調(diào)方法。當(dāng)該activity完成操作后腋么,它會(huì)把一個(gè)包含結(jié)果的 Intent 返回到你的 onActivityResult() 中咕娄。
比如,也許你需要用戶選取一個(gè)聯(lián)系人珊擂,以便于你的activity能夠根據(jù)聯(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...
}
}
}
以上例子展示了使用 onActivityResult() 方法來處理activity返回結(jié)果的基本邏輯。 第一個(gè)判斷條件是檢查請(qǐng)求是否成功——如果成功了resultCode 應(yīng)該是RESULT_OK 摧扇,以及要求響應(yīng)的請(qǐng)求是否是可識(shí)別的——在這種情況下圣贸,requestCode會(huì)與傳入 startActivityForResult() 的第二個(gè)參數(shù)相比較。 接下來扛稽,代碼通過查詢Intent 返回的數(shù)據(jù)(data參數(shù))來處理activity的返回結(jié)果吁峻。
接下來,ContentResolver 通過content provider執(zhí)行了一個(gè)查詢,查詢返回了一個(gè)包含查到數(shù)據(jù)以供讀取的 Cursor 用含。
<h4 id=“7”>7.關(guān)閉activity</h4>
可以調(diào)用activity的 finish() 方法來關(guān)閉它矮慕。也可以用 finishActivity() 方法來關(guān)閉一個(gè)你先前已經(jīng)啟動(dòng)的單個(gè)activity。
注意: 在大多數(shù)的情況下啄骇,不應(yīng)該使用這些方法來顯式地關(guān)閉一個(gè)activity痴鳄。 正如以下關(guān)于activity生命周期的部分所述,Android系統(tǒng)會(huì)替你管理activity的生命周期缸夹,所以你不需要關(guān)閉你的activity痪寻。 調(diào)用這些方法可能會(huì)對(duì)預(yù)期的用戶體驗(yàn)產(chǎn)生不利的影響,僅當(dāng)你確實(shí)不想讓用戶再返回到這個(gè)activity的實(shí)例時(shí)才會(huì)用到它們虽惭。
<h4 id=“8”>8.管理activity的生命周期</h4>
通過實(shí)現(xiàn)回調(diào)方法來管理你的activity的生命周期橡类,對(duì)于開發(fā)一個(gè)健壯而又靈活的應(yīng)用程序而言是至關(guān)重要的。 與其它activity的關(guān)聯(lián)性趟妥、自身的任務(wù)和back stack直接影響著一個(gè)activity的生命周期猫态。
activity可能處于三種基本的狀態(tài):
Resumed
activity在屏幕的前臺(tái)并且擁有用戶的焦點(diǎn)。(這個(gè)狀態(tài)有時(shí)也被叫做“running”披摄。)
Paused
另一個(gè)activity在前臺(tái)并擁有焦點(diǎn)亲雪,但是本activity還是可見的。 也就是說疚膊,另外一個(gè)activity覆蓋在本activity的上面义辕,并且那個(gè)activity是部分透明的或沒有覆蓋整個(gè)屏幕。 一個(gè)paused的activity是完全存活的(Activity 對(duì)象仍然保留在內(nèi)存里寓盗,它保持著所有的狀態(tài)和成員信息灌砖,并且保持與window manager的聯(lián)接),但在系統(tǒng)內(nèi)存嚴(yán)重不足的情況下它能被殺死傀蚌。
Stopped
本activity被其它的activity完全遮擋住了(本activity目前在后臺(tái))基显。 一個(gè)stopped的activity也仍然是存活的(Activity 對(duì)象仍然保留在內(nèi)存中,它保持著所有的狀態(tài)和成員信息善炫,但是不再與window manager聯(lián)接了)撩幽。 但是,對(duì)于用戶而言它已經(jīng)不再可見了箩艺,并且當(dāng)其它地方需要內(nèi)存時(shí)它將會(huì)被殺死窜醉。
如果activity被paused或stopped了,則系統(tǒng)可以從內(nèi)存中刪除它艺谆,通過請(qǐng)求finish(調(diào)用它的 finish() 方法)或者直接殺死它的進(jìn)程榨惰。 當(dāng)這個(gè)activity被再次啟動(dòng)時(shí)(在被finish或者kill后),它必須被完全重建静汤。
<h4 id=“9”>9.實(shí)現(xiàn)生命周期回調(diào)方法</h4>
當(dāng)一個(gè)activity在上述描述的狀態(tài)之間轉(zhuǎn)換時(shí)琅催,它將通過各種回調(diào)方法來獲得通知居凶。 所有的回調(diào)方法都是鉤子(hook),當(dāng)activity狀態(tài)發(fā)生改變時(shí)你都可以 重寫這些方法來執(zhí)行對(duì)應(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)這些生命周期方法時(shí)排监,必須保證在其它代碼之前首先調(diào)用一下父類的方法狰右,如上例所示杰捂。
總體來講,這些方法定義了一個(gè)activity的完整的生命周期棋蚌。 通過實(shí)現(xiàn)這些方法嫁佳,你可以監(jiān)控activity生命周期中三個(gè)嵌套的循環(huán):
activity的完整生存期會(huì)在 onCreate() 調(diào)用和 onDestroy() 調(diào)用之間發(fā)生。 你的activity應(yīng)該在 onCreate() 方法里完成所有“全局global”狀態(tài)的設(shè)置(比如定義layout)谷暮, 而在onDestroy() 方法里釋放所有占用的資源蒿往。 例如,如果你的activity有一個(gè)后臺(tái)運(yùn)行的線程湿弦,用于從網(wǎng)絡(luò)下載數(shù)據(jù)瓤漏,那么你應(yīng)該在 onCreate() 方法里創(chuàng)建這個(gè)線程并且在 onDestroy() 方法里停止這個(gè)線程。
activity的可見生存期會(huì)在 onStart() 調(diào)用和 onStop() 調(diào)用之間發(fā)生颊埃。在這期間蔬充,用戶可在屏幕上看見這個(gè)activity并可與之交互。 例如班利,當(dāng)一個(gè)新的activity啟動(dòng)后調(diào)用了 onStop() 方法饥漫,則這個(gè)activity就無法被看見了。 在這兩個(gè)方法之間罗标,你可以管理那些顯示activity所需的資源庸队。例如,你可以在 onStart() 方法里注冊(cè)一個(gè) BroadcastReceiver 用于監(jiān)控影響用戶界面的改動(dòng)闯割。并且當(dāng)用戶不再看到你的顯示內(nèi)容時(shí)彻消,在 onStop() 方法里注銷掉它。 系統(tǒng)會(huì)在activity的整個(gè)生存期內(nèi)多次調(diào)用 onStart() 和onStop()宙拉, 因?yàn)閍ctivity可能會(huì)在顯示和隱藏之間不斷地來回切換宾尚。
activity的前臺(tái)生存期會(huì)在 onResume() 調(diào)用和 onPause() 之間發(fā)生。在這期間鼓黔,activity是位于屏幕上所有其它的activity之前央勒,并且擁有用戶的輸入焦點(diǎn)。 activity可以頻繁地進(jìn)入和退出前臺(tái)——例如澳化, 當(dāng)設(shè)備進(jìn)入休眠時(shí)或者彈出一個(gè)對(duì)話框時(shí)崔步, onPause() 就會(huì)被調(diào)用。因?yàn)檫@個(gè)狀態(tài)可能會(huì)經(jīng)常發(fā)生轉(zhuǎn)換缎谷,為了避免切換遲緩引起的用戶等待井濒,這兩個(gè)方法中的代碼應(yīng)該相當(dāng)?shù)剌p量化灶似。
圖1說明了activity在狀態(tài)之間可能行走的這些循環(huán)和路徑。矩形代表了你可以實(shí)現(xiàn)的回調(diào)方法瑞你,用于activity狀態(tài)轉(zhuǎn)換時(shí)執(zhí)行相應(yīng)操作酪惭。
圖上為activity生命周期
同樣的生命周期回調(diào)方法已經(jīng)在表中列出了,該表更詳細(xì)地描述了每個(gè)回調(diào)方法者甲,并且指明了每個(gè)方法在activity的全生命周期中的位置春感, 包括回調(diào)方法完成后系統(tǒng)是否會(huì)殺死這個(gè)activity。
activity生命周期回調(diào)方法匯總
標(biāo)為“之后可否被殺死虏缸?”的列指明了系統(tǒng)是否可以在這個(gè)方法返回之后的任意時(shí)刻殺掉這個(gè)activity的宿主進(jìn)程鲫懒, 而不再執(zhí)行其它流程上的activity代碼。 有三個(gè)方法是標(biāo)為“可以”:( onPause()刽辙、 onStop()窥岩、 和onDestroy())。 因?yàn)閛nPause()是三個(gè)方法中的第一個(gè)宰缤, 一旦activity被創(chuàng)建颂翼, onPause() 就是進(jìn)程可以被殺死之前最后一個(gè)能確保被調(diào)用的方法 ——如果系統(tǒng)在某種緊急情況下必須回收內(nèi)存,則 onStop() 和onDestroy() 可能就不會(huì)被調(diào)用了慨灭。因此朦乏,你應(yīng)該使用 onPause() 來把至關(guān)重要的需長期保存的數(shù)據(jù)寫入存儲(chǔ)器(比如用戶所編輯的內(nèi)容)。 不過缘挑,應(yīng)該對(duì)必須通過 onPause() 方法進(jìn)行保存的信息有所選擇集歇,因?yàn)樵摲椒ㄖ兴械淖枞僮鞫紩?huì)讓切換到下一個(gè)activity的停滯,并使用戶感覺到遲緩语淘。
“之后可否被殺死诲宇?”列中標(biāo)為“否”的方法,在它們被調(diào)用時(shí)的那一刻起惶翻,就會(huì)保護(hù)本activity的宿主進(jìn)程不被殺掉姑蓝。 因此,只有在 onPause() 方法返回時(shí)至 onResume() 方法被調(diào)用時(shí)之間吕粗,activity才會(huì)被殺掉纺荧。直到 onPause() 再次被調(diào)用并返回時(shí),activity都不會(huì)再次允許被殺死颅筋。
Note:表1中標(biāo)明的技術(shù)上不“可殺”的activity仍然有可能會(huì)被系統(tǒng)殺死——但那只有在沒有任何資源的極端情況下才會(huì)發(fā)生宙暇。 什么時(shí)候activity會(huì)被殺掉,已在文檔進(jìn)程和線程里詳細(xì)說明了议泵。
<h4 id=“10”>10.保存activity的狀態(tài)</h4>
[管理Activity生命周期]一節(jié)中已簡單提到占贫,當(dāng)一個(gè)activity被paused或者stopped時(shí),activity的狀態(tài)可以被保存先口。 的確如此型奥,因?yàn)?Activity 對(duì)象在paused或者stopped時(shí)仍然被保留在內(nèi)存之中——它所有的成員信息和當(dāng)前狀態(tài)都仍然存活瞳收。 這樣用戶在activity里所作的改動(dòng)全都還保存著,所以當(dāng)activity返回到前臺(tái)時(shí)(當(dāng)它“resume“)厢汹,那些改動(dòng)仍然有效螟深。
不過,如果系統(tǒng)是為了回收內(nèi)存而銷毀activity烫葬,則這個(gè) Activity 對(duì)象就會(huì)被銷毀界弧,這樣系統(tǒng)就無法簡單地resume一下就能還原完整狀態(tài)的activity。 如果用戶要返回到這個(gè)activity的話厘灼,系統(tǒng)必須重新創(chuàng)建這個(gè)Activity 對(duì)象夹纫。可是用戶并不知道系統(tǒng)是先銷毀activity再重新創(chuàng)建了它的设凹,所以,他很可能希望activity完全保持原樣茅姜。 這種情況下闪朱,你可以保證activity狀態(tài)的相關(guān)重要信息都由另一個(gè)回調(diào)方法保存下來了,此方法讓你能保存activity狀態(tài)的相關(guān)信息: onSaveInstanceState()钻洒。
在activity變得很容易被銷毀之前奋姿,系統(tǒng)會(huì)調(diào)用 onSaveInstanceState()方法。 調(diào)用時(shí)系統(tǒng)會(huì)傳入一個(gè)Bundle對(duì)象素标, 你可以利用 putString() 之類的方法称诗,以鍵值對(duì)的方式來把a(bǔ)ctivity狀態(tài)信息保存到該Bundle對(duì)象中。 然后头遭,如果系統(tǒng)殺掉了你的application進(jìn)程并且用戶又返回到你的activity寓免,系統(tǒng)就會(huì)重建activity并將這個(gè) Bundle 傳入onCreate() 和onRestoreInstanceState() 中,你就可以從 Bundle 中解析出已保存信息并恢復(fù)activity狀態(tài)计维。如果沒有儲(chǔ)存狀態(tài)信息袜香,那么傳入的 Bundle 將為null(當(dāng)activity第一次被創(chuàng)建時(shí)就是如此)。
圖 2. activity狀態(tài)完整地返回給用戶的兩種方式:被銷毀destroyed后再被重建鲫惶,而且必須恢復(fù)了之前保存的狀態(tài)蜈首;或是被停止stopped后再被恢復(fù)resumed,狀態(tài)都完整保留著欠母。
注意: activity被銷毀之前欢策,并不能確保每次都會(huì)調(diào)用 onSaveInstanceState() ,因?yàn)榇嬖谀切┎槐乇4鏍顟B(tài)的情況(比如用戶使用BACK鍵離開了你的activity赏淌,因?yàn)橛脩裘黠@是關(guān)了這個(gè)activity)踩寇。 如果系統(tǒng)要調(diào)用 onSaveInstanceState() 方法,那么它通常會(huì)在 onStop() 方法之前并且可能是在 onPause() 之前調(diào)用猜敢。
不過姑荷,即使你沒有實(shí)現(xiàn) onSaveInstanceState() 方法盒延,有些activity狀態(tài)還是會(huì)通過 Activity 類缺省實(shí)現(xiàn)的onSaveInstanceState() 方法保存下來。特別的是鼠冕,缺省為layout中的每個(gè) View 實(shí)現(xiàn)了調(diào)用相應(yīng)的onSaveInstanceState() 方法添寺,這允許每一個(gè)view提供自己需被保存的信息。 幾乎Android框架下所有的widget都會(huì)在適當(dāng)?shù)臅r(shí)候?qū)崿F(xiàn)該方法懈费,這樣计露,任何UI上可見的變化都會(huì)自動(dòng)保存下來,并在activity重建后自動(dòng)恢復(fù)憎乙。 例如票罐,EditText widget會(huì)保存所有用戶已經(jīng)輸入的文本, CheckBoxwidget 也會(huì)保存是否被選中泞边。你所要做的工作僅僅是為每一個(gè)你想要保存其狀態(tài)的widget提供一個(gè)唯一的ID(就是 android:id 屬性)该押。如果這個(gè)widget沒有ID的話,系統(tǒng)是無法保存它們的狀態(tài)的阵谚。
通過把a(bǔ)ndroid:saveEnabled 設(shè)置為"false",或者調(diào)用 setSaveEnabled() 方法蚕礼,你也可以顯式地阻止layout中的某個(gè)view保存狀態(tài)。 通常不應(yīng)該禁用保存梢什,不過假如你需要恢復(fù)activity UI的各個(gè)不同的狀態(tài)奠蹬,也許可以這么做。
盡管缺省實(shí)現(xiàn)的 onSaveInstanceState() 方法會(huì)保存activity UI的有用信息嗡午,你仍然需要覆蓋它來存入更多的信息囤躁。 例如,你可能需要保存在activity生命周期中改變的成員變量值(可能是關(guān)于UI恢復(fù)的值荔睹,但是默認(rèn)情況下狸演,存放這些UI狀態(tài)的成員變量值是不會(huì)被恢復(fù)的)。
因?yàn)槟J(rèn)實(shí)現(xiàn)的 onSaveInstanceState() 方法已經(jīng)幫你保存了一些UI的狀態(tài)应媚,所以如果你重寫此方法是為了保存更多的狀態(tài)信息严沥,那么在執(zhí)行自己的代碼之前應(yīng)該確保先調(diào)用一次父類的 onSaveInstanceState() 方法。同理中姜,如果重寫 onRestoreInstanceState() 的話消玄,也應(yīng)該調(diào)用一次父類的該方法,這樣缺省的代碼就能正扯撸恢復(fù)view的狀態(tài)了翩瓜。
注意:因?yàn)?onSaveInstanceState() 并不保證每次都會(huì)被調(diào)用,所以你應(yīng)該只用它來記錄activity的一些臨時(shí)狀態(tài)信息(UI的狀態(tài))——千萬不要用它來保存那些需要長久保存的數(shù)據(jù)携龟。 替代方案是兔跌,你應(yīng)該在用戶離開activity的時(shí)候利用 onPause() 來保存永久性數(shù)據(jù)(比如那些需要存入數(shù)據(jù)庫里的數(shù)據(jù))。
一個(gè)檢測應(yīng)用程序狀態(tài)恢復(fù)能力的好方法就是旋轉(zhuǎn)設(shè)備峡蟋,使得屏幕方向發(fā)生改變坟桅。 當(dāng)屏幕的方向改變時(shí)华望,因?yàn)橐獡Q用符合實(shí)際屏幕參數(shù)的資源,系統(tǒng)會(huì)銷毀并重建這個(gè)activity仅乓。 正因如此赖舟,你的activity能夠在被重建時(shí)完整地恢復(fù)狀態(tài)是非常重要的,因?yàn)橛脩魰?huì)在使用應(yīng)用程序時(shí)會(huì)頻繁地旋轉(zhuǎn)屏幕夸楣。
<h4 id=“11”>11.多Activity的合作</h4>
當(dāng)activity啟動(dòng)另一個(gè)activity時(shí)宾抓,它倆生命周期的狀態(tài)都會(huì)發(fā)生轉(zhuǎn)換。 第一個(gè)activity paused并stopped(盡管它也可能不會(huì)被stopped豫喧,如果它仍然后臺(tái)可見的話)石洗,而另一個(gè)activity是被created。 如果這兩個(gè)activity共用了保存在磁盤或其它地方的數(shù)據(jù)紧显,那么請(qǐng)明白:在第二個(gè)activity被created之前讲衫,第一個(gè)activity還沒有完全被stopped,這點(diǎn)非常重要鸟妙。 或多或少焦人,第二個(gè)activity的啟動(dòng)進(jìn)程與第一個(gè)activity的關(guān)閉進(jìn)程在時(shí)間上會(huì)發(fā)生重疊。
生命周期回調(diào)方法的順序是很明確的重父,特別是兩個(gè)activity位于同一個(gè)進(jìn)程中、一個(gè)啟動(dòng)另一個(gè)的時(shí)候忽匈。 下面就是Aactivity A啟動(dòng)Activity B時(shí)的操作順序:
Activity A的 onPause()方法房午,如果活動(dòng)后臺(tái)不可見的話,onStop()方法同樣運(yùn)行丹允,否則不運(yùn)行郭厌。
Activity B的 onCreate() ,onStart() 和onResume() 方法依次運(yùn)行雕蔽。(Activity B現(xiàn)在獲得用戶焦點(diǎn)折柠。)
以上預(yù)設(shè)的生命周期回調(diào)方法順序使你能夠?qū)σ粋€(gè)activity啟動(dòng)另一個(gè)activity時(shí)的轉(zhuǎn)換信息進(jìn)行管理。 例如批狐,如果第一個(gè)activity停止時(shí)你須寫入數(shù)據(jù)庫以便后續(xù)的activity可以讀取數(shù)據(jù)扇售,那么你應(yīng)該在 onPause() 方法而不是 onStop() 方法里寫入數(shù)據(jù)庫。