Android開發(fā)之Activity詳解
【Activity】
一個Activity是一個應用程序組件,提供一個屏幕,用戶可以用來交互為了完成某項任務,例如撥號、拍照、發(fā)送email、看地圖。每一個activity被給予一個窗口,在上面可以繪制用戶接口。窗口通常充滿屏幕,但也可以小于屏幕而浮于其它窗口之上。
一個應用程序通常由多個activities組成,他們通常是松耦合關系。通常,一個應用程序中的activity被指定為"main"activity,當?shù)谝淮螁討贸绦虻臅r候呈現(xiàn)給用戶的那個activity。每一個activity然后可以啟動另一個activity為了完成不同的動作。每一次一個activity啟動,前一個activity就停止了,但是系統(tǒng)保留activity在一個棧上(“back stack”)。當一個新activity啟動,它被推送到棧頂,取得用戶焦點。Back Stack符合簡單“后進先出”原則,所以,當用戶完成當前activity然后點擊back按鈕,它被彈出棧(并且被摧毀),然后之前的activity恢復。
當一個activity因新的activity啟動而停止,它被通知這種狀態(tài)轉(zhuǎn)變通過activity的生命周期回調(diào)函數(shù)。有許多回調(diào)函數(shù)一個activity可能會收到,源于它自己的狀態(tài)變化-無論系統(tǒng)創(chuàng)建它、停止它、恢復它、摧毀它-并且每個回調(diào)提供你完成適合這個狀態(tài)的指定工作的機會。例如,當停止的時候,你的activity應該釋放任何大的對象,例如網(wǎng)絡數(shù)據(jù)庫連接。當activity恢復,你可以重新獲得必要的資源和恢復被中斷的動作。這些狀態(tài)轉(zhuǎn)換都是activity的生命周期的部分。
【Creating an Activity】
創(chuàng)建一個activity,你必須創(chuàng)建一個Activity的子類(或者一個Activity的子類的子類)。在你的子類中,你需要實現(xiàn)系統(tǒng)回調(diào)的回調(diào)方法,當activity在它的生命周期的多種狀態(tài)中轉(zhuǎn)換的時候,例如當activity被創(chuàng)建、停止、恢復或摧毀。兩個最重要的回調(diào)方法是:
onCreate()
你必須實現(xiàn)這個方法。系統(tǒng)調(diào)用它當創(chuàng)建你的activity的時候。在你的實現(xiàn)中,你應該初始化你的activity的基本的組件。更重要的是,這里就是你必須調(diào)用setContentView()來定義activity用戶接口而已的地方。
onPause()
系統(tǒng)調(diào)用這個方法當用戶離開你的activity(雖然不總是意味著activity被摧毀)。這通常是你應該提交任何變化,那此將會超越user session而存在的(因為用戶可能不再回來)。
有若干其它生命周期回調(diào)函數(shù)你應該使用為了提供一個流暢的用戶體驗,并表操作異常中斷會引起你的activity被中斷甚至被摧毀。
1、Implementing a user interface
一個activity的用戶接口被一個層次化的視圖提供--繼承于View類的對象。每個View控制activity窗口中的一個特定矩形區(qū)域并且能響應用戶交互。例如,一個view可能是個button,初始化動作當用戶觸摸它的時候。
Android提供大量預定義的view,你可以使用來設計和組件你的布局?!癢idgets”是一種給屏幕提供可視化(并且交互)元素的view,例如按鈕、文件域、復選框或者僅僅是圖像?!癓ayouts”是繼承于ViewGroup的View,提供特殊的布局模型為它的子view,例如線程布局、格子布局或相關性布局。你可以子類化View和ViewGroup類(或者存在的子類)來創(chuàng)建自己的widget和而已并且應用它們到你的activity布局中。
最普通的方法是定義一個布局使用view加上XML布局文件保存在你的程序資源里。這樣,你可以單獨維護你的用戶接口設計,而與定義activity行為的代碼無關。你可以設置布局作為UI使用setContentView(),傳遞資源布局的資源ID??墒牵阋部梢詣?chuàng)建新Views在你的activity代碼,并且創(chuàng)建一個view層次通過插入新Views到ViewGroup,然后使用那個布局通過傳遞到根ViewGroup給setContentView()。
【Declaring the activity in the manifest】
你必須聲明你的activity在manifest文件為了它可以被系統(tǒng)訪問。要聲明你的activity,打開你的manifest文件,添加一個<activity>元素作為<application>元素的子元素。例如:
【Using intent filters】
一個<activity>元素也能指定多種intent filters--使用<inetent-filter>元素--為了聲明其它應用程序可以激活它。
當你創(chuàng)建一個新應用程序使用Android SDK工具,存根activity自動為你創(chuàng)建,包含一個intent filter,聲明了activity響應"main"動作,并且應該被 放置 在"launcher"分類。Intent filter看起來像這個樣子。
<action>元素指定這是一個"main"入口點對這個應用程序。<category>元素指定,這個activity應該被列入系統(tǒng)應用程序列表中(為了允許用戶啟動這個activity)。
如果你希望應用程序自包含,并且不希望別的應用程序激活它的activities,那么你不需要任何其它intent filters。只有一個activity應該有“main"動作和”launcher“分類,就像前面這個例子。你不希望被其它應用程序訪問原Activities應該沒有intent filters而且你能啟動他們通過自己顯示的intent。
可是,如果你希望你的activity響應影含的intents,從其它應用程序(和你自己的),那么你必須定義額外的intent filters為這個activity。每一種你希望響應的類型的intent,你必須包含<intent-filter>,包含<action>元素,可選的,一個<category>元素并且/或一個<data>元素。這些元素指定你的activity能響應的intent的類型。
【Starting an Activity】
你可以開啟另一個activity通過startActivity(),傳遞一個Intent描述了你希望啟動的Activity。Intent指定要么準備的activity你希望啟動或描述你希望完成的動作(操作系統(tǒng)選擇合適的activity為你,可能來自定不同的應用程序)。一個intent可以傳輸小量數(shù)據(jù)被啟動的activity使用。
完全工作在你的應用程序之內(nèi),你將經(jīng)常需要簡單的啟動一個未知的activity。你可以這么通過創(chuàng)建一個intent顯示的定義你希望啟動的activity,使用類名。例如,下面顯示一個activity怎么啟動另一個activity命名為SignInActivity:
可是,你的應用程序或許希望執(zhí)行一些動作,例如發(fā)送一份郵件、文件消息或者狀態(tài)更新,使用你的activity的數(shù)據(jù)。在這種情況下,你的應用程序或許沒有它自己的activity來完成這個動作,因此你可以促使設備上其它應用程序提供的activity來完成你的動作。這才是intent真正有價值的地方--你可以創(chuàng)建一個intent描述一個你希望執(zhí)行的動作,然后系統(tǒng)啟動一個合適的activity從其它應用程序。如果有多種activities可以處理這個intent,那么 用戶可以選擇哪一個來執(zhí)行。例如,如果你希望允許用戶發(fā)送郵件,你可以創(chuàng)建下面的Intent:
EXTRA_EMAIL額外的添加給intent一個字符串數(shù)組指定email地址,當一個郵件應用程序響應這個intent的時候,它讀取這些字符串數(shù)組并且放置他們到相應字段。在這種情況下,email應用程序的activity啟動并且當用戶執(zhí)行完,你的activity恢復。
【Starting an activity for a result】
有時,你或許希望接收一個結(jié)果從你啟動的activity。在這種情況下,開啟這個activity通過startActivityForResult()(而不是startActivity())。然后從隨后的activity接收結(jié)果,實現(xiàn)onActiviryResult()回調(diào)函數(shù)。當隨后的activity完成,它返回一個結(jié)果給你的onActivityResult()函數(shù)通過一個intent。
例如,或許你希望用戶選擇他們中的一個聯(lián)系人,所以你的activity可以對這個聯(lián)系人做些事情。下面是你怎么建立這樣一個Intent和操作結(jié)果:
這個例子展現(xiàn)了基本的邏輯你應該使用的在你的onActivityResult()函數(shù)中,為了操作一個activity的結(jié)果。第一個條件檢測是否請求成功--如果是,那么 resultCode將會是RESULT_OK--并且是否這個請求是否是這個響應是響知道--在這種情況下,requestCode匹配第二個參數(shù)用startActivityForResult()的參數(shù)。在那里,代碼操作activity結(jié)果通過查詢返回在intent中的數(shù)據(jù)(data參數(shù))。
將發(fā)生的是,一個ContentResolver實現(xiàn)查詢content provider,返回一個Cursor允許讀查詢的數(shù)據(jù)。
【Shut Down an Activity】
你可以關閉一個activity通過調(diào)用自身的finish()方法。你也可以關閉一個獨立的activity你之前啟動的通過finiActivity()。
注意:在大多數(shù)情況下,你不應該顯示結(jié)果一個activity使用這些方法。正在下文所討論的關于activity的生命周期,Android系統(tǒng)管理一個activity的生命周期為你,所以你不需要結(jié)果你自己的activity。調(diào)用這些函數(shù)對用戶體驗有害并且只有在你決對不希望用戶返回到這個activity的情況下。
【Managing the Activity Lifecycle】
管理你的activity的生命周期通過實現(xiàn)回調(diào)函數(shù)非常關鍵對開發(fā)一個健壯和有彈性的應用程序。一個activity的生命周期直接被與其相關聯(lián)的其它activity影響,task和bask stack。
一個activity可以存在于主要的三種狀態(tài):
1、Resumed
activity在前景并且擁有用戶焦點。(這個狀態(tài)有時也叫”running“)
2、Paused
另一個activity在前景并且擁有用戶焦點,但這個仍然可見。也就是說,另一個activity可見在這個的上面,當前activity部分透明或沒有覆蓋整個屏幕。一個paused activity完全活著(the Activity對象維在內(nèi)存中,它維護所有的狀態(tài)并且記憶信息,仍然連接著窗口管理器),但是可以被系統(tǒng)殺死在極端需要內(nèi)存的情形下。
3、Stopped
一個activity被另一個activity完全阻擋(activity現(xiàn)在在后臺)。一個stopped activity仍然活著(Activity object維持在內(nèi)存中,它維擴所有的狀態(tài)和成員信息,但沒有綁定窗口管理器)??墒?,它不再被用戶可見并且它可被系統(tǒng)銷毀在需要的地方。
如果一個activity paused或者stopped,系統(tǒng)可以從內(nèi)存中拋棄它通過要求它結(jié)束(調(diào)用它的finish()方法),或者簡單的殺掉它的進程。當activity再次被打開(在被finished或殺死后),它重新建立所有的東西。
【Implementing the lifecycle callbacks】
當一個activity轉(zhuǎn)換到或轉(zhuǎn)換出上面提到的狀態(tài),它被通過各種不同的回調(diào)函數(shù)通知。所有這些回調(diào)函數(shù)都是hook,你可以覆蓋來做合適的工作當你的activity狀態(tài)變化。下面的activity骨架包含每一個基本的生命周期函數(shù):
注意:你的這些生命周期函數(shù)的實現(xiàn)必須調(diào)用父類的實現(xiàn)在你做自己的工作之前,就像上面顯示的一樣。
放在一起,這些函數(shù)定義了整個生命周期關于一個activity。通過實現(xiàn)這些方法,你可以監(jiān)視三種嵌套的循環(huán)在activity生命周期中。
1、一個activity的整個生命時間發(fā)生在onCreate()和onDestroy()函數(shù)。你的activity應該設置全局狀態(tài)(例如定義布局)在onCreate(),并且釋放所有的資源在onDestroy()。例如,如果你的activity有一個線程在后臺跑下載數(shù)據(jù)從網(wǎng)絡,它可能創(chuàng)建那個線程在onCreate()然后停止線程在onDestroy()。
2、一個可視的生命期發(fā)生在onStart()和onStop()之間。在這期間,用戶可以看見activity在屏幕上并且和它交互。例如,onStop()被調(diào)時當一個新的activity開始并且這個不再被可見。在這兩個函數(shù)間,你可以維持資源那些需要用來展現(xiàn)activity給用戶的。例如,你可以注冊一個BroadcastReceiver在onStart(),然后注銷在onStop()當用戶不再看見你顯示的東西。系統(tǒng)可能會調(diào)onStart(0和onStop()多次在這整個生命線期間,當activity在是否可見間轉(zhuǎn)換的時候。
3、一個activity的前景生命期發(fā)生在onResume()和onPause()之間。在這期間,此activity在所有其它activity之上在屏幕上,并且擁有用戶焦點。一個activity可以經(jīng)常轉(zhuǎn)換進和轉(zhuǎn)換出前景--例如,onPause被調(diào)用當設備準備休眠蔌當一個對話框產(chǎn)生。因為這種狀態(tài)可以經(jīng)常轉(zhuǎn)換,代碼在這兩個狀態(tài)應該輕量為了避免減慢轉(zhuǎn)換速度使得用戶等待。
圖像1陳述這些循環(huán)并且展現(xiàn)一個activity可以發(fā)生的狀態(tài)轉(zhuǎn)換路徑。矩形代表你能實現(xiàn)的回調(diào)函數(shù)。
Figure 1. The activity lifecycle.
同樣的生命周期回調(diào)函數(shù)被列在table 1,更加詳細的描述了回調(diào)函數(shù)放置每一個在activity的事個生命周期,包含是否系統(tǒng)能殺死activity在回調(diào)函數(shù)完成后。
Table 1. A summary of the activity lifecycle's callback methods.
因為onPause()他們?nèi)齻€中的第一個,一量activity被建立,onPause()是最后一個被保證調(diào)用的方法--如果系統(tǒng)必須恢復內(nèi)存在緊急狀態(tài),然后onStop()和onDestroy()可能將不被調(diào)用。因此,你應該使用onPause()來寫數(shù)據(jù)(例如edit)的存儲。可是,你應該精心挑選哪個信息一定要在onPause()中留住,因為任何何阻塞的操作在這個函數(shù)阻塞到下一個activity的轉(zhuǎn)換因而降低用戶體驗。
【Saving activity state】
本文簡單的提到了什么一個activity被paused和stopped,activity的狀態(tài)維持著。這是真的因為activity對象仍然在內(nèi)存當它被paused或stopped--所有的信息關于它的成員變量和當前狀態(tài)都存在。如此,任何用戶的變化在activity中都維持在內(nèi)存里,所以當activity返回到前景的時候(resumes),這些變化仍然存在。
可是,當系統(tǒng)摧毀一個activity為了恢復內(nèi)存,activity對象被摧毀了,所以系統(tǒng)不能簡單的以完整狀態(tài)resume它。代替的是,系統(tǒng)必須創(chuàng)建Activity對象如果用戶瀏覽回它。也就是,用戶不知道系統(tǒng)摧毀了activity并且再創(chuàng)建了它,如此,可以希望activity是它剛才的那個。在這種情況下,你可以確定重要的信息關于activity的狀態(tài)被保留通過實現(xiàn)一個額外的回調(diào)函數(shù),允許你保存信息關于你的activity,然后恢復它當系統(tǒng)重新創(chuàng)建它的時候。
這個你可以保存當前狀態(tài)信息的回調(diào)函數(shù)是onSaveInstanceState()。系統(tǒng)調(diào)這個函數(shù)在摧毀activity這前,并且傳遞一個Bundle對象。Bundle就是你可存在狀態(tài)信息的地方,采用name-value對,使用方法如putString()。然后,如果系統(tǒng)殺死你的activity進程并且用戶瀏覽回到你的activity,系統(tǒng)傳遞Bundle給onCreate,這樣你就可以恢復activity狀態(tài)你在onSaveInnstanceState()時候保存的狀態(tài)。如果沒有信息被保存,傳遞給onCreate()的Bundle是null。
注意:不保證onSaveInstanceState()將會被調(diào)用在你的activity被摧毀前,因為有不需要存儲的情況存在(例如當用戶離開你的activity,用戶顯示的結(jié)束)。如果這個方法被調(diào)用,它總是在onStop()前,概率性在onPause()前。
可是,即使你不做什么事也不實現(xiàn) onSaveInstanceState(),一些activity的狀態(tài)被activity類的默認onSaveInstanceState實現(xiàn)恢復。特別的,默認的View的onSaveInstance()在布局方面,允許每一個視圖提供它自己的信息來被保存。幾乎所有 的Android框架中的widget實現(xiàn)這個方法合適的,這樣任何可見的變化對UI都自己保存并且恢復當你的activity被創(chuàng)建的時候。例如,EditText widget保存任何文本被用戶輸入的,并且CheckBox widget保存是否選中還是沒選中。惟一的工作要求你的是提供一個惟一的ID(通過android:id屬性)給每一個希望保存狀態(tài)的widget。如果一個widget沒有ID,那么 它不保存它的狀態(tài)。
雖然onSaveInstanceState()的默認實現(xiàn)保存非常有用的信息關于你的activity UI你仍然會需要覆蓋它來保存額外的信息。例如,你或許需要保存成員變量在activity生命期間變化的(和保存在UI中的數(shù)據(jù)有關,但保存這些UI值的變量卻不會被默認保存)。
因為默認的onSaveInstanceState()幫你 你保存UI狀態(tài),如果你覆蓋這些方法為了保存額外的信息,你應該每次調(diào)用父類的實現(xiàn)關于onSaveinstanState()在做工作之前。
注意:因為onSaveInstanceState()不保證被調(diào)用,你應該用它僅用它記錄臨時狀態(tài)關于你的activity--你應該永遠不用它來存儲永久性數(shù)據(jù)。代替的是,你應該用onPause()來存儲永遠性數(shù)據(jù)(例如保存在數(shù)據(jù)庫中的數(shù)據(jù))當用戶離開activity。
一個好的方法測試你程序保存狀態(tài)的功能是簡單的轉(zhuǎn)換設備以使屏幕方向改變。當屏幕方向變化,系統(tǒng)摧毀和重建activity為了應用可選的資源,適合新方向的。出于這個原因,你的activity恢復它的狀態(tài)當創(chuàng)建的時候非常重要,因為用戶通常轉(zhuǎn)換屏幕在使用應用程序的時候。
【Handling configuratinon changes】
一些設備配置能在運行時改變(例如屏幕方向,鍵盤是否可用和語言)。當這樣的變化發(fā)生時,Android重新開啟運行中的Activity(onDestroy()被調(diào)用,然后onCreate()被調(diào)用)。重啟行為被設計來幫助應用程序適應新的配置通過自動加載你的應用程序通過可選的資源,你提供的。如果你設置你的activity合適的操作這個事件,它將更有彈性對生命周期中無法預料的事件。
最好的方法操作配置變化,例如屏幕方向變,就是簡單的預定義你應用程序的狀態(tài)使用onSaveInstanceState()和onRestoreInstanceState()(或onCreate()),就像前面討論的。
【Coordinating activities】
當一個activity啟動另一個,他們都在體驗生命周期轉(zhuǎn)換。第一個activitypauses和stop(雖然,它不會stop如果他仍然可見在前景),另一個activity被創(chuàng)建。萬一這些activities共離數(shù)據(jù)保存到磁盤或哪,那就讓第一個activity不退出在另一個啟動前就顯得非常重要。相當?shù)那闆r是,后一個進程啟動覆蓋了前一個停止的時候。
生周周期回調(diào)被良好的定義了,特別的當兩個activities都在同一個進程,并且其中一個啟動另一個。下面是操作順序當activity A啟動activity B:
1、Activity A 的onPause()的方法執(zhí)行。
2、Activity B 的onCreate()、onStart()和onResume()方法執(zhí)行,順序的。(B現(xiàn)在擁有用戶焦點)
3、如果A不再可見,它的onStop()方法執(zhí)行。
這種生命期函數(shù)調(diào)用序列允許你從一個activity到另一個的信息轉(zhuǎn)換。例如,如果你必須寫入一個數(shù)據(jù)庫,當?shù)谝粋€activity stop,以便讓下一個activity能讀它,那么你應該寫入數(shù)據(jù)庫在onPause()而不是onStop()。
相關文章
Android編輯框EditText與焦點變更監(jiān)視器及文本變化監(jiān)視器實現(xiàn)流程詳解
這篇文章主要介紹了Android編輯框EditText與焦點變更監(jiān)視器及文本變化監(jiān)視器實現(xiàn)流程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧2022-09-09Android studio保存logcat日志到本地的操作
這篇文章主要介紹了Android studio保存logcat日志到本地的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04Android中判斷是否聯(lián)網(wǎng)實現(xiàn)代碼
這篇文章主要介紹了Android中判斷是否聯(lián)網(wǎng)實現(xiàn)代碼,本文直接給出實現(xiàn)代碼,需要的朋友可以參考下2015-06-06Android實現(xiàn)EditText中添加和刪除bitmap的方法
這篇文章主要介紹了Android實現(xiàn)EditText中添加和刪除bitmap的方法,實例分析了Android中EditText控件的bitmap操作技巧,需要的朋友可以參考下2016-01-01