【正文】
注:四大元件指的是應用元件:activity、service、broadcastreceiver、contentprovider;之前的控件指的是ui元件。
博文目錄:
一、activity簡介
二、activity的狀态和生命周期
三、activity的基本用法
四、向下一個activity傳遞資料
五、傳回資料給上一個activity
六、activity運作時螢幕方向與顯示方式
七、activity的現場儲存
八、activity通過sharedpreferences儲存資料
一、activity簡介:
activity元件是四大元件之一,在應用中一個activity可以用來表示一個界面, 中文意思也可以了解為“活動” ,即一個活動開始,代表activity元件啟動;活動結束,代表一個activity的生命周期結束。
一個android應用必須通過activity來運作和啟動,和j2me 的midlet 一樣,在android中,activity的生命周期統一交給系統管理。與midlet 不同的是安裝在android 中的所有的activity 都是平等的。
了解以下四個基本概念,将有助于我們更好的了解activity:
• application(app)
• activity
• activity棧
• task
每個application均占有獨立的記憶體空間。需要注意的是:application之間雖然互相獨立,但app_1中的activity與app_2中的activity之間可以進行通信(調用、通路等)。
1、activity的狀态:
(1)resumed:activity對象出于運作狀态。一個新activity 啟動入棧後,它在螢幕最前端,處于棧的最頂端,此時它處于可見并可以與使用者互動的激活狀态。
(2)paused:另一個activity位于前端,但是本activity還可見。
paused狀态常用于:當activity被另一個透明或者dialog樣式的activity覆寫時的狀态。此時它依然與視窗管理器保持連接配接,系統繼續維護其内部狀态,是以它仍然可見,但它已經失去了焦點故不可與使用者互動。注:一個activity出于paused狀态時,系統并不會釋放資源。釋放資源你的操作要靠開發者來完成。
(3)stopped:另一個activity位于前端,完全遮擋本activity。
(4)killed:activity被系統殺死回收或者沒有被啟動時。
繪制表格如下:
生命周期函數
調用時機
舉例
oncreate
在activity對象被第一次建立時調用
買車
onstart
當activity變得可見時調用
打火,啟動
onresume
當activity開始準備和使用者互動時調用
踩油門,驅動汽車前進
onpause
當系統即将啟動另外一個activity之前調用
松開油門
onstop
目前activity變得不可見時調用
熄火
ondestroy
目前activity被銷毀之前調用
車輛報廢
onrestart
當一個activity再次啟動之前調用
2、activity的生命周期:

生命周期的完整代碼如下:
三、activity的啟動模式:(面試注意)
activity有四種啟動模式:standard、singletop、singletask、singleinstance。可以在androidmanifest.xml中activity标簽的屬性android:launchmode中設定該activity的加載模式。
standard模式:預設的模式,以這種模式加載時,每當啟動一個新的活動,必定會構造一個新的activity執行個體放到傳回棧(目标task)的棧頂,不管這個activity是否已經存在于傳回棧中;
singletop模式:如果一個以singletop模式啟動的activity的執行個體已經存在于傳回桟的桟頂,那麼再啟動這個activity時,不會建立新的執行個體,而是重用位于棧頂的那個執行個體,并且會調用該執行個體的onnewintent()方法将intent對象傳遞到這個執行個體中;
注:如果以singletop模式啟動的activity的一個執行個體已經存在于傳回桟中,但是不在桟頂,那麼它的行為和standard模式相同,也會建立多個執行個體;
singletask模式:這種模式下,每次啟動一個activity時,系統首先會在傳回棧中檢查是否存在該活動的執行個體,如果存在,則直接使用該執行個體(會調用執行個體的onnewintent()方法),并把這個活動之上的所有活動統統清除;如果沒有發現就會建立一個新的活動執行個體;
singleinstance模式:總是在新的任務中開啟,并且這個新的任務中有且隻有這一個執行個體,并讓多個應用共享該棧中的該activity執行個體。一旦該模式的activity的執行個體存在于某個棧中,任何應用再激活該activity時都會重用該棧中的執行個體。其效果相當于多個應用程式共享一個應用,不管誰激活該activity都會進入同一個應用中。
注:也就是說被該執行個體啟動的其他activity會自動運作于另一個任務中。當再次啟動該activity的執行個體時,會重新調用已存在的任務和執行個體。并且會調用這個執行個體的onnewintent()方法,将intent執行個體傳遞到該執行個體中。和singletask相同,同一時刻在系統中隻會存在一個這樣的activity執行個體。(singleinstance即單執行個體)
注:前面三種模式中,每個應用程式都有自己的傳回棧,同一個活動在不同的傳回棧中入棧時,必然是建立了新的執行個體。而使用singleinstance模式可以解決這個問題,在這種模式下會有一個單獨的傳回棧來管理這個活動,不管是哪一個應用程式來通路這個活動,都公用同一個傳回棧,也就解決了共享活動執行個體的問題。(此時可以實作任務之間的切換,而不是單獨某個棧中的執行個體切換)
1、singleinstance模式詳解:
singleinstance模式從字面上看比較難了解,下面通過代碼舉例來分析。代碼如下:
(1)建立三個activity:firstactivity、secondactivity、thirdactivity。同時,将secondactivity的啟動模式設定為singleinstance。
(2)三個activity的代碼如下:
firstactivity.java:
上方代碼中,在oncreate()方法中列印目前傳回棧的id。點選按鈕,跳轉到secondactivity。
secondactivity.java:
上方代碼中,在oncreate()方法中列印目前傳回棧的id。點選按鈕,跳轉到thirdactivity。
thirdactivity.java:
運作程式,在firstactivity中點選按鈕進入secondactivity中,然後在secondactivity中點選按鈕進入thirdactivity。背景列印日志如下:
上方日志可以看到:secondactivity的task id不同于firstactivity和thirdactivity,這說明secondactivity确實是存放在一個單獨的傳回棧中的,而且這個傳回棧中隻有secondactivity這一個活動。
然後,我們按下back鍵進行傳回,你會發現thirdactivity竟然直接傳回到了firstactivity,再按下back鍵又會傳回到secondactivity,再按下back鍵才會退出程式。解釋如下:
firstactivity和thirdactivity存放在同一個傳回棧裡,當在thirdactivity中按下back鍵,thirdactivity出棧,那麼firstactivity就成為了棧頂活動顯示在界面上;然後在firstactivity界面再次按下back鍵,這是目前的傳回棧已經空了,于是就顯示了另一個傳回棧的棧頂活動,即secondactivity。最後按下back鍵,這時,所有的傳回棧都已經空了,自然也就退出了程式。
三、activity的基本用法:
1、隐藏标題欄:
注:第一行代碼一定要在第二行代碼之前執行。
2、在活動當中使用toast:
例如點選按鈕時,彈出吐司:
3、啟動一個activity的方法:即在預設啟動的activity中啟動另一個activity
核心代碼如下:
使用隐式intent,我們不僅可以啟動自己程式内的活動,還可以啟動其他程式的活動,這使得android多個應用程式之間的功能共享成為了可能。比如應用程式中需要展示一個網頁,沒有必要自己去實作一個浏覽器(事實上也不太可能),而是隻需要條用系統的浏覽器來打開這個網頁就行了。
【執行個體】:打開指定網頁。
監聽器部分的核心代碼如下:
第4行代碼:指定了intent的action是 intent.action_view,這是一個android系統内置的動作;
第5行代碼:通過uri.parse()方法,将一個網址字元串解析成一個uri對象,再調用intent的setdata()方法将這個uri對象傳遞進去。
詳見:《android第一行代碼》p48頁。
如果要打電話的話,可以使用下面的代碼:
四、向下一個activity傳遞資料:
不同的activity 執行個體可能運作在一個程序中,也可能運作在不同的程序中。是以,我們需要一種特别的機制幫助我們在activity 之間傳遞消息。android 中通過intent 對象來表示一條消息,一個intent 對象不僅包含有這個消息的目的地,還可以包含消息的内容,這好比一封email,其中不僅應該包含收件位址,還可以包含具體的内容。對于一個intent 對象,消息“目的地 ”是必須的,而内容則是可選項。
在上面的執行個體中通過activity. startactivity(intent)啟動另外一個activity的時候,我們在intent類的構造器中指定了“收件人位址”。
activity傳遞資料有以下兩種方式:
1、【方式一】使用intent自帶的bundle對象
傳遞資料,代碼如下:
這裡,我們采用另一種綁定監聽時間的方法,即在布局檔案中,對button按鈕做如下設定:
上方第7行代碼就是我們綁定的監聽事件,點選按鈕,将觸發gotosecondactivity()函數中的代碼。緊接着做下面的操作。
在mainactivity中發送資料:
在secondactivity中接收資料:
或者傳遞一個對象:
建立一個student.java的類檔案,作為傳遞的對象:
【工程檔案】
連結:http://pan.baidu.com/s/1jgvec6q
密碼:ic6c
2、【方式二】建立bundle對象來傳遞
通過按鈕監聽事件。核心代碼如下:
【工程檔案】
連結:http://pan.baidu.com/s/1ntlqzfn
密碼:xzn7
五、傳回資料給上一個activity:
步驟如下:
啟動帶傳回結果的mainactivity:
第二個參數為請求碼,用于在之後的回調中判斷資料的來源
在secondactivity中通過putextra放入資料,然後調用以下方法:(非常重要)
resultcode一般隻使用result_ok 或result_canceled這兩個值,第二個參數則把帶有資料的intent傳遞回去
secondacticity被銷毀之前,會調用上mainactivity的 onactivityresult()方法,是以要重寫這個方法:
public void onactivityresult(int requestcode, int resultcode,intent data)
舉例略。
1、鎖定螢幕方向:橫屏/ 豎屏
android 内置了方向感應器的支援。android 會根據所處的方向自動在豎屏和橫屏間切換。但是有時我們的應用程式僅能在橫屏/ 豎屏時運作,比如某些遊戲,此時我們需要鎖定該activity 運作時的螢幕方向,<activity>節點的android:screenorientation屬性可以完成該項任務,示例代碼如下:
【方法一】在清單檔案中配置:
【方法二】通過代碼實作(一般放在oncreate方法中的前面),如下:
這裡提一個小知識,android模拟器中,快捷鍵"ctrl+f11/f12"可以實作轉屏
2、全屏顯示:
可以在其oncreate()方法中添加如下代碼實作:
3、以對話框形式顯示activity:
在清單檔案中配置:
特别關注:activity的啟動模式。見《android第一行代碼》p68頁
七、activity的現場儲存:
程式在運作時,一些裝置的配置可能會改變,如:橫豎屏的切換、鍵盤的可用性等。這種事情一旦發生,activity會重新建立。
重新建立的過程如下:
在銷毀之前,會調用onsaveinstancestate()去儲存應用中的一些資料,儲存在系統當中;
然後調用ondestroy()銷毀之前的activity;
最後調用 oncreate()或onrestoreinstancestate()方法去重新建立一個activity。
現場儲存的步驟如下:
(1)在mainactivity中,調用onsaveinstancestate(),即添加如下代碼就可以将臨時資料儲存:
(2)資料儲存之後,修改mainactivity的oncreate()方法:
完整代碼如下:
當手動旋轉螢幕後,背景輸出結果如下:
上圖的日志中,如果把生命周期寫完整一點,列印的日志如下:
在旋轉螢幕時,如果不想重新建立activity,我們可以通過清單檔案androidmanifest.xml中android:configchanges來指定的某些屬性不發生變化,然後通知程式去調用onconfiguratonchanged()方法主動去改變一些設定(當旋轉螢幕的時候)。
清單檔案中,指定的常見屬性有:
"keyboard" 鍵盤發生了改變----例如使用者用了外部的鍵盤
"keyboardhidden" 鍵盤的可用性發生了改變
"orientation" 螢幕方向改變
"screensize" 螢幕大小改變
設定代碼舉例如下:
注:符号“|”表示“并且”的意思,這行代碼在實際應用中很常見。
接着在上面的java代碼的基礎之上,添加如下代碼:
最終,當手動旋轉螢幕後,背景輸出結果如下:
可以看到,onsaveinstancestate()方法并沒有被調用,也就是說,旋轉螢幕時,目前activity并沒有被銷毀。
八、activity通過shared preferences儲存資料:
通常情況下會發生這樣的問題,我們在編輯短信的同時有電話打進來,那麼接電話肯定是要啟動另一個activiy,那麼目前編輯短信的activity所編輯的資訊我們想暫時儲存下來,等接完電話後回到該activity時,可以繼續編輯短信。該功能需要如何去實作呢?
其實,sharedpreferences使用xml格式為android應用提供一種永久的資料存貯方式。對于一個android應用,它存貯在檔案系統的/data/ data/your_app_package_name/shared_prefs/目錄下,可以被處在同一個應用中的所有activity 通路。android 提提供了相關的api來處理這些資料而不需要程式員直接操作這些檔案或者考慮資料同步的問題。
現在就用代碼來實作這個功能:
首先使用sharedpreferences這個工具類:
其中,第一個參數代表xml檔案,如果有這個檔案,就會操作這個檔案,如果沒有這個檔案,就會建立這個檔案;第二個參數代表一種操作模式,0代表私有。
然後,我們要在onpause()方法裡儲存資料,之是以在onpause()方法裡儲存,是因為在所有可能會被記憶體銷毀的生命周期函數中,而onpause()方法最先執行。代碼如下:
将資料儲存在msg變量中,然後拿到editor這個編輯器,給它put進去。當然,這些隻是在記憶體中操作,如果要反映到檔案當中,還要執行 commit()方法。
緊接着,我們要在onresume()方法中重新還原資料:(為什麼要在這個方法中還原資料,不用我多解釋)
當程式中第一次啟動的時候,并沒有儲存資料,是以傳回一個預設的空值。将這個傳回的資料放到etmsg控件中就行了。
現在我們運作程式,是可以執行的。
例如,現在編輯内容,然後去别的程式,再回來的時候(就算我們把程式退出了),編輯的内容還依然存在。這個時候,我們打開檔案浏覽器,發現資料是儲存在data-data-android工程的檔案夾-shared-prefs目錄的data.xml檔案當中的,而且是永久儲存;是以,當在onresume()方法還原資料之後,我們還要加一部分代碼,來删掉這個檔案裡的内容(無法删除檔案本身),不然就會永久儲存本地成為垃圾了。代碼如下:
總結之後,最終的完整版代碼如下:
activity_main.xml檔案代碼:
<code> </code>
mainactivity.java的代碼如下:
運作程式之後,我們在編輯框輸入一些文字:
退出程式,然後導出data.xml檔案,打開後顯示如下:
說明輸入的文本被儲存在了data.xml檔案當中。當我們再回到程式,之前輸入的文字會被保留在界面上,而data.xml檔案中的文本則會被清空。
代碼優化:
上方代碼中如果我們在第40行代碼的後面加下面這一行代碼:
當傳回到原程式時,setselection方法可将輸入光标移動到文本的末尾位置以便繼續輸入。裡面的參數sp.getstring("msg", "")是之前所輸入的字元串。
<code>到這裡為止,android的基礎知識就講完了,以後會不斷完善補充的。</code>