在Android里,一個Activity一般是用于負(fù)責(zé)創(chuàng)建一個頁面,通過setContentView(View)
方法向用戶展示你的UI瀑粥。
若想啟動一個Activity豆挽,可以通過Context.startActivity(Intent)
炫七,并且這個Activity要在AndroidManifest.xml
清單文件里進(jìn)行申明磕蛇。有時你想從Activity結(jié)束時得到結(jié)果;例如囱桨,你可以啟動一個Activity仓犬,讓用戶在聯(lián)系人列表中選擇一個人; 當(dāng)它結(jié)束時,它返回選擇的人舍肠。為此搀继,你可以通過調(diào)用Activity.startActivityForResult(Intent, int)
,使用第二個整型的參數(shù)標(biāo)識你的請求翠语,然后在Activity的onActivityResult(int, int, Intent)
方法會返回你請求的結(jié)果律歼。
啟動模式
在同一個時間段只能有一個Activity是運(yùn)行的(其他Activity就算可見也不能獲得焦點(diǎn),觸摸事件等)啡专,多個Activity是由Activity堆棧管理的,當(dāng)啟動了一個新的Activity制圈,它就會被放置在這個棧的頂部们童,上一個Activity總是保持在棧的下面,也就是在這個新的Activity后面鲸鹦,直到新的Activity退出慧库。但是一個應(yīng)用程序里面棧不一定是只有一個的,這個由Activity的啟動模式?jīng)Q定的:
- standard:不管棧里有沒有已存在的實例馋嗜,都會在當(dāng)前棧中生成新的實例齐板;
- singleTask:如果當(dāng)前棧存在重復(fù)的Activity,則把重復(fù)的Activity置頂葛菇,在這個Activity之上的其他實例都會被移出棧甘磨;
- singleInstance:跟其他Activity不在一個棧中,獨(dú)立一個棧眯停,并且這個棧只能擁有這一個Activity济舆,并且如果以存在這個實例時,會重用這個實例;
- singleTop:如果當(dāng)前棧頂?shù)腁ctivity是重復(fù)的莺债,則可以重復(fù)利用滋觉,否則生成新的實例签夭;
申明Activity的啟動模式是在AndroidManifest.xml
清單文件里進(jìn)行的,通過android:launchMode="singleTask"
這樣的形式申明椎侠,一般App的首頁Activity都會申明為singleTask
第租。
生命周期
一個Activity通常有4種狀態(tài):
- 如果一個Activity在屏幕的前臺里顯示(在Activity棧的頂部),它是運(yùn)行的狀態(tài)(active or running)我纪。
- 如果一個Activity失去了焦點(diǎn)但是仍然保持可見狀態(tài)(例如一個不是填滿屏幕或者是透明的Activity在這個Activity的上面慎宾,很多App把Activity主題設(shè)置為透明的可滑動退出就屬于這種),它是處于暫停的狀態(tài)(paused)宣羊。一個暫停的Activity仍然是存活的(它保持所有狀態(tài)和成員信息璧诵,并保持附加到窗口管理器),但在內(nèi)存非常緊張不足的時候可能會被殺死仇冯。
- 如果一個Activity完全被另外一個Activity遮擋住之宿,它是處于停止的狀態(tài)(stopped)。它仍然保留所有的狀態(tài)和成員信息苛坚,但是比被,它不再是用戶可見的,所以它的窗口被隱藏泼舱,當(dāng)需要內(nèi)存時等缀,它經(jīng)常會優(yōu)先被殺死。
- 如果一個Activity是處于暫徒筷迹或者停止的狀態(tài)尺迂,則系統(tǒng)可以通過請求它完成或者簡單地殺死它的進(jìn)程來從內(nèi)存中刪除該Activity。當(dāng)它需要再一次顯示給用戶的時候冒掌,必須完全重新啟動(restarted)和恢復(fù)(restored)它之前的狀態(tài)噪裕。
為了避免內(nèi)存不足把托管Activity的進(jìn)程殺死時數(shù)據(jù)丟失,一般情況下都會在onPause()
方法里面進(jìn)行數(shù)據(jù)的持久化存儲股毫。此外膳音,onSaveInstanceState(Bundle)
方法也會被調(diào)用,你可以將Activity的任何動態(tài)實例狀態(tài)(例如當(dāng)前頁面滑動的位置铃诬,顯示的內(nèi)容)保存到給定的Bundle
中祭陷,然后當(dāng)Activity需要顯示時,會在它的onCreate(Bundle)
方法里接收到這個Bundle
趣席。
下圖是Activity主要的生命周期兵志,長方形表示你可以在Activity的狀態(tài)切換時實現(xiàn)的回調(diào)方法,彩色橢圓形是Activity可以處于的主要狀態(tài)宣肚。
你可能有興趣在你的Activity中監(jiān)控的三個關(guān)鍵循環(huán):
- 在 Activity的整個生命周期里毒姨,第一次調(diào)用
onCreate()
到最后調(diào)用onDestroy()
的時候。一般在onCreate()
進(jìn)行一些初始化操作钉寝,通過findViewById()
進(jìn)行View的初始化弧呐,在onDestroy()
里進(jìn)行資源的釋放闸迷。例如,如果在onCreate()
里開啟線程俘枫,從網(wǎng)絡(luò)下載相應(yīng)的數(shù)據(jù)腥沽,然后再onDestroy()
里停止線程。 - Activity的可見生命周期是從調(diào)用
onStart()
到調(diào)用onStop()
鸠蚪,在此期間今阳,用戶可以在屏幕上看到該Activity,雖然它可能不在前臺與用戶交互茅信。在這兩個方法之間盾舌,您可以維護(hù)向用戶顯示Activity所需要的資源。例如蘸鲸,通過BroadcastReceiver
在onStart()
注冊廣播監(jiān)聽器妖谴,更新你的UI,當(dāng)用戶不再看到你顯示的內(nèi)容時在onStop()
里取消該監(jiān)聽事件酌摇。 - Activity的前臺生命周期是從調(diào)用
onResume()
到調(diào)用onPause()
膝舅,在此期間,Activity在所有其他的Activity前面窑多,并與用戶交互仍稀。例如,當(dāng)設(shè)備進(jìn)入休眠時埂息,Activity結(jié)果被傳遞時技潘,當(dāng)一個新的意圖(Intent)發(fā)起時,所以在這方法中的代碼應(yīng)該是比較輕量級的千康,不會阻塞UI享幽。
值得一提的是,很多App在界面上是可滑動退出的吧秕,如果Activity是透明的,那么在這個Activity啟動時迹炼,前一個Activity會調(diào)用onPause()
砸彬,但不會調(diào)用onStop()
方法,應(yīng)為前一個Activity仍然屬于可見狀態(tài)斯入,盡管是完全被遮住看不見而已砂碉,當(dāng)這個Activity退出后,前一個Activity只會調(diào)用onResume()
方法刻两,而不會執(zhí)行onRestart()
和onStart()
方法增蹭;還有很多時候,你若想要通過廣播等方法去監(jiān)聽某些事件磅摹,然后更新UI滋迈,如果你要一直保持更新UI盡管已經(jīng)啟動了新的Activity在前面霎奢,這個時候就不能再onStart()
和onStop()
方法對里去注冊取消監(jiān)聽了,而是應(yīng)該在onCreate()
和onDestroy()
里進(jìn)行饼灿;
配置更改
如果設(shè)備的配置(由Resources.Configuration類定義 )更改幕侠,則顯示用戶界面的任何內(nèi)容都需要更新以匹配該配置。因為Activity是與用戶交互的主要機(jī)制碍彭,所以它包括用于處理配置更改的特殊支持晤硕。
除非你指定,配置變更(如屏幕方向庇忌,語言舞箍,輸入設(shè)備等的變化)會導(dǎo)致你的當(dāng)前Activity被破壞,通過正常的Activity生命周期過程適當(dāng)?shù)貓?zhí)行onPause()
皆疹, onStop()
和onDestroy()
疏橄。如果活動已經(jīng)在前臺或用戶可見,一旦onDestroy()
在該實例中被調(diào)用墙基,那么將創(chuàng)建新的Activity實例软族,而前一實例通過onSaveInstanceState(Bundle)
保存數(shù)據(jù)到Bundle
里,再通過onCreate(Bundle)
的Bundle
恢復(fù)之前的數(shù)據(jù)残制。
在某些特殊情況下立砸,你可能希望根據(jù)一種或多種類型的配置更改繞過重新啟動Activity,這時可以通過在AndroidManifest.xml
清單文件里申明Activity時初茶,申明android:configChanges
屬性來完成颗祝。對于您處理的任何類型的配置更改,您將收到對當(dāng)前ActivityonConfigurationChanged(Configuration)
方法的調(diào)用恼布, 而不是重新啟動螺戳。如果配置更改涉及到你不處理的配置更改,則Activity仍將重新啟動折汞,onConfigurationChanged(Configuration)
也不會被調(diào)用倔幼。
有些時候,你的Activity是支持橫豎屏切換的(例如看視頻)爽待,本身界面也是支持橫豎屏的切換顯示损同,為了避免重新啟動Activity,可以這樣android:configChanges="screenSize|orientation|keyboardHidden"
鸟款,screenSize|orientation
是屏幕的變化時會更改的屬性膏燃,keyboardHidden
則是用戶打開手機(jī)硬件鍵盤;
進(jìn)程的生命周期
Android系統(tǒng)嘗試盡可能長地保持應(yīng)用程序進(jìn)程何什,但最終需要在內(nèi)存不足時刪除舊進(jìn)程组哩。如活動生命周期中所述,關(guān)于要刪除哪個進(jìn)程的決策與用戶與其交互的狀態(tài)密切相關(guān)。一般來說伶贰,一個進(jìn)程可以基于其中運(yùn)行的Activity有四個狀態(tài)蛛砰,這里按照重要性的順序列出。系統(tǒng)將在殺死更重要的進(jìn)程(第一個進(jìn)程)之前殺死不太重要的進(jìn)程(最后一個進(jìn)程)幕袱。
- 前臺Activity(在該用戶當(dāng)前交互的屏幕的頂部的Activity)被認(rèn)為是最重要的暴备。如果它使用的內(nèi)存超過了設(shè)備可提供的,它的進(jìn)程會作為最后的手段被殺死们豌。通常設(shè)備這時候已經(jīng)到了內(nèi)存分頁狀態(tài)(memory paging state)的地步涯捻,終止一些前臺進(jìn)程是為了保證用戶界面的及時響應(yīng)。
- 一個可見的Activity(即對用戶可見望迎,但不是在前臺的Activity障癌,例如一個位于前臺后面的對話框),被認(rèn)為是非常重要的辩尊,不會被殺死除非必須保持前臺運(yùn)行的Activity涛浙。
- 一個背景Activity(Activity是對用戶不可見,并已暫停)已不再是關(guān)鍵摄欲,所以系統(tǒng)可以安全地殺死它的進(jìn)程回收內(nèi)存以提供內(nèi)存給其他前臺或可見的進(jìn)程轿亮。如果它的進(jìn)程需要被殺死,當(dāng)用戶后退回Activity(使它在屏幕上再次可見)時胸墙,通過
onCreate(Bundle)
方法里的Bundle
恢復(fù)用戶最后離開這個Activity時的狀態(tài)我注,在Activity被銷毀時,會調(diào)用onSaveInstanceState(Bundle)
方法存儲Activity的狀態(tài)到Bundle
里迟隅。 - 一個空的進(jìn)程沒有持有Activity或其他應(yīng)用程序組件(如Service或 BroadcastReceiver類)但骨。當(dāng)內(nèi)存變得很低時這些會被系統(tǒng)迅速殺死。因此智袭,在Activity之外執(zhí)行的任何后臺操作必須通過Activity上下文(Context)持有的BroadcastReceiver或Service中執(zhí)行奔缠,以確保系統(tǒng)知道它需要保持您的進(jìn)程。
有時吼野,一個Activity可能需要做一個長期運(yùn)行的操作校哎,它獨(dú)立于Activity生命周期本身而存在。例如可以是允許你將圖片上傳到網(wǎng)站的相機(jī)應(yīng)用瞳步。上傳可能需要很長時間闷哆,應(yīng)用程序應(yīng)允許用戶在上傳時離開應(yīng)用。要完成此操作谚攒,你的Activity應(yīng)該啟動一個Service進(jìn)行上傳阳准。這允許系統(tǒng)在上傳的持續(xù)時間內(nèi)正確地優(yōu)先考慮進(jìn)程(認(rèn)為它比其他非可見應(yīng)用程序更重要)氛堕,而與原始Activity是暫停(paused)馏臭,停止(stopped)還是結(jié)束(finished)無關(guān)。
本文大部分參考翻譯自谷歌API文檔,并且自己整理補(bǔ)充了一些內(nèi)容括儒,以下是資料鏈接:
[https://developer.android.google.cn/reference/android/app/Activity.html]