版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
Android基本概念和模型
學(xué)習(xí)在一個全新的平臺上開發(fā)最重要的第一步是什么?我覺得當(dāng)然不是語言的問題,也更不是工
具的問題。學(xué)習(xí)Windows開發(fā),我們得了解Win32窗口的運行原理,消息隊列等機制,不了解這
些背后的機制和基本的運行模型,只靠RAD工具我們還是只能停留在普通應(yīng)用的階段。學(xué)習(xí)Web
開發(fā),不了解HTMLDOM,HTTP協(xié)議原理等內(nèi)容,只靠掌握如ASP.Net,JSP等廠商技術(shù),我
們也做不到Web開發(fā)的“心想事成”,“胸有成竹”;同樣如AnrsBlog中說到的正則表示式的應(yīng)用,
我們還得了解其背后的匹配原理。所以,我覺得面對一個全新的平臺,我們得首先了解其工作和
運行的基本模型和原理,才能做到以后在這個平臺上的“得心應(yīng)手”。
各位看官先不要被圖形中的生詞嚇?biāo)?,接下來我會詳?xì)解釋每一個概念。
先來看圖形中的灰色部分,這部分描述了一個完整的Android應(yīng)用程序可以包含的各個組成部分,
我們將組成一個Android程序的組件稱為AndroidComponent(圖中中間部分的基類),由若干個
AndroidComponent就組成了一個完整的Android應(yīng)用程序。先看圖中左下方的Activity,這個組
件我們可以認(rèn)為它是Windows中的窗體概念,這是Android程序的基本組成部分,也就是程序的
人機交互界面。比如一個簡單的短信程序就應(yīng)該包含三個Activity,一個短信列表界面,一個閱
讀短信詳細(xì)內(nèi)容的界面和一個編輯短信的界面。圖中左上角的Service顧名思議就是服務(wù),一個
Android程序中哪些部分是服務(wù)呢?舉例來說,短信程序并不只是在我們打開短信界面的時候才
去收取短信,我們退出界面后,手機仍然會去收取短信,并在新的短信到達(dá)時通知我們,所以一
定有某個任務(wù)在后臺運行著,這就是Service了;再比如說音樂播放功能,當(dāng)我們從播放界面返回
手機待機界面的時候仍然可以繼續(xù)聽音樂,這也是一個Service的例子。其實Activity+Service是
非常常見的手機軟件應(yīng)用,比如我要做的BlogMessage同樣也是這樣的結(jié)構(gòu)。左邊中間部分的
-BroadcastReceiver”是用于接收各種系統(tǒng)定義事件或自定義事件的接收器,如果我們的程序想偵
測?些系統(tǒng)事件的發(fā)生,我們就需要寫一個BroadcastReceiver。例如我們的程序想在手機打開
Wifi的時候立即去刷新最新的數(shù)據(jù),或者我們想在手機來電時執(zhí)行某個動作,這些都可以由
BroadcastReceiver訂閱特定的事件來完成。圖中左邊剩下的“ContentProvider”,我們可以把它理
解成一種特殊的Service,一種可以給其他程序提供數(shù)據(jù)的Service,例如手機中的聯(lián)系人信息,我
們?nèi)魏纬绦蚨伎梢院推渫ㄐ湃カ@取聯(lián)系人的信息,這就可實現(xiàn)為一個典型的ContentProvider。
再來看圖中藍(lán)色的部分,這是一個靜態(tài)的部署概念,就如同我們.Nei開發(fā)的程序集的概念一樣。
Apk是我們Android程序發(fā)布和部署的基本單位,一個完整的Android程序就可以打包為一個或
多個Apk進(jìn)行發(fā)布,我們從AndroidMarketing上下載安裝的程序也是一個個的Apk包,我們在
Eclipse中的一個Project的最終Build結(jié)果也就是一個Apk文件。一個Apk中包含了上面介紹的
4種AndroidComponento
最后,圖中黃色的部分就是系統(tǒng)運行時的概念了。由于Android平臺是基于Linux的,所以Process
(進(jìn)程)和Thread(線程)的概念和Linux中的一致,在代碼中我們可以編寫一個普通的JavaThread
來實現(xiàn)多線程。需要注意的是,Android中的Process是受系統(tǒng)自動管理的,并不是說我們在一個
程序界面中按了手機上的Back鍵或者Home鍵程序就結(jié)束了,大家也很難在Android的各種程序
中找到類似Symbian程序中的“退出”功能。Android系統(tǒng)會給每一個進(jìn)程都計算出一個“重要程度”
等級,在系統(tǒng)運行的某個時候例如資源不足的時候,系統(tǒng)會根據(jù)各個進(jìn)程的“重要程度”來決定先
釋放哪個進(jìn)程。(進(jìn)程“重要程度''的判斷在Google的官方文檔還是說的比較清楚的,實際上各個
AndroidComponent都有很完整的運行時生命周期,由于我們不太清楚進(jìn)程結(jié)束的時機,了解各個
AndroidComponent的運行時生命周期以及相關(guān)事件就對我們的開發(fā)來說非常重要,我會陸續(xù)在后
續(xù)的手記中詳細(xì)闡述這些內(nèi)容)。
一個Apk中包含的AndroidComponent在運行時可以運行在同一個進(jìn)程中,也可以運行在不同
的進(jìn)程中,這取決于我們在Apk的AndroidManifest.xml上進(jìn)行的配置(大家可以將這個
AndroidManifest.xml看成是Apk的全局配制信息,其中會描述這個Apk中包含了哪些Android
Component以及各個Component的運行和啟動方式等,我會在后續(xù)的Post中講解這些內(nèi)容)。
最后,圖中下面中間部分的“Task”是Android中一個很特殊的運行時概念,也是很復(fù)雜的一個
概念,Google的官方文檔用了很大的篇幅來說明這個概念。它有別于進(jìn)程和線程,并且只和
Activity的運行時有關(guān)系。
我們可以將其理解成“窗口?!?,這是由手機上的特殊操作方式所引出的概念。由于手機上的程
序,用戶一般只能在同一時間看到一個界面,例如在編輯短信的時候一般就不能看到短信列表的
界面。而一個完整的程序一般會由多個Activity組成,所以這些Activity會在運行時隨著打開的
先后順序會被放到同一個窗口棧(Task)中,當(dāng)前活動窗口棧中最上面的Activity就是用戶當(dāng)前
看到的界面,按手機上的“Back”則是銷毀當(dāng)前棧頂?shù)腁ctivity,回到上一個界面。
然而Task這個概念之所以復(fù)雜,是因為不同Process中的Activity可以被放到同一個Task中,
例如在我們的程序中可能會打開GoogleMap的地圖界面。具體Activity在運行時該被放到哪個
Task中,這會由Activity的taskAffinity屬性決定,一般情況下一個Apk中的所有Activity在運行
時會被放到同一個Task中,但是運行時Activity的taskAffinity是可以修改的。例如上面說的Google
M叩的例子,地圖顯示界面默認(rèn)是存在于GoogleM叩這個程序的默認(rèn)Task中的,但是我們卻可
以在運行時將這個界面帶到我們自己程序的當(dāng)前Task中來。窗口在Task中的“入?!焙汀俺鰲!辈?/p>
作和Activity的運行時生命周期息息相關(guān),后面我也會用更詳細(xì)的篇幅來介紹Task和Activity運
行時生命周期的關(guān)系。
Activity的運行時生命周期模型
由于在Android中,進(jìn)程的生命周期大多數(shù)時候是由系統(tǒng)管理的;另外也由于手機應(yīng)用的一些特
殊性,所以我們需要更多的去關(guān)注各個AndroidComponent的運行時生命周期模型。(所謂手機
應(yīng)用的特殊性主要是指這樣2點:1.手機應(yīng)用的大多數(shù)情況下我們只能在手機上看到一個程序
的一個界面,用戶除了通過程序界面上的功能按鈕來在不同的窗體間切換,還可以通過Back鍵
和Home鍵來返回上一個窗口,而用戶使用Back或者Home的時機是非常不確定的,任何時候
用戶都可以使用Home或Back來強行切換當(dāng)前的界面。2.往往手機上一些特殊的事件發(fā)生也
會強制的改變當(dāng)前用戶所處的操作狀態(tài),例如無論任何情況,在手機來電時,系統(tǒng)都會優(yōu)先顯示
電話接聽界面。)了解這些Component的生命周期模型一方面是讓我們對軟件在手機中的運行
情況做到心中有數(shù),更重要的,對于程序開發(fā)來說,生命周期中的每一個關(guān)鍵事件都會有我們可
以覆寫于各種Component對應(yīng)基類型的事件處理方法,了解各Component的生命周期就是讓我
們在開發(fā)程序時明白我們該怎樣去編寫各種事件的處理代碼。例如Activity的Create,就會有對
應(yīng)的事件處理函數(shù)onCreate,我們可以從Activity基類覆寫這個事件處理函數(shù)完成我們需要的相
關(guān)事件處理:
publicclassactMainextendsActivity{
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedlnstanceState);
……〃我們的事件處理代碼
)
)
這篇Post我們就來看看最常用的Activity的運行時生命周期模型(Service的運行時生命周期模型
在下一篇講述了如何啟動一個Service并和其通信后再做描述)。Activity的生命周期模型在
Google提供的官方文檔上有比較詳細(xì)的一個圖示(請自行翻墻查看)。其一共包含7個我們需要
關(guān)心的關(guān)鍵事件,下面對其分別詳細(xì)說明(文字中的粗體字表示后文中會經(jīng)常用到的概念在第一
次出現(xiàn)時會給出解釋,之后后文不再詳細(xì)說明):
1.voidonCreate(BundlesavedlnstanceState)
當(dāng)Activity被第首次加載時執(zhí)行。我們新啟動一個程序的時候其主窗體的onCreate事件就會被執(zhí)
行。如果Activity被銷毀后(onDestroy后),再重新加載進(jìn)Task時,其onCreate事件也會被重
新執(zhí)行。注意這里的參數(shù)savedlnstanceState(Bundle類型是一個鍵值對集合,大家可以看成
是.Net中的Dictionary)是一個很有用的設(shè)計,由于前面已經(jīng)說到的手機應(yīng)用的特殊性,一個
Activity很可能被強制交換到后臺(交換到后臺就是指該窗體不再對用戶可見,但實際上又還是存
在于某個Task中的,比如一個新的Activity壓入了當(dāng)前的Task從而“遮蓋“住了當(dāng)前的Activity,
或者用戶按了Home鍵回到桌面,又或者其他重要事件發(fā)生導(dǎo)致新的Activity出現(xiàn)在當(dāng)前Activity
之上,比如來電界面),而如果此后用戶在一段時間內(nèi)沒有重新查看該窗體(Android通過長按
Home鍵可以選擇最近運行的6個程序,或者用戶直接再次點擊程序的運行圖標(biāo),如果窗體所在
的Task和進(jìn)程沒有被系統(tǒng)銷毀,則不用重新加載Process,Task和Task中的Activity,直接重
新顯示Task頂部的Activity,這就稱之為重新查看某個程序的窗體),咳窗體連同其所在的Task
和Process則可能已經(jīng)被系統(tǒng)自動銷毀了,此時如果再次查看該窗體,則要重新執(zhí)行onCreate事
件初始化窗體。而這個時候我們可能希望用戶繼續(xù)上次打開該窗體時的操作狀態(tài)進(jìn)行操作,而不
是一切從頭開始。例如用戶在編輯短信時突然來電,接完電話后用戶又去做了一些其他的事情,
比如保存來電號碼到聯(lián)系人,而沒有立即回到短信編輯界面,導(dǎo)致了短信編輯界面被銷毀,當(dāng)用
戶重新進(jìn)入短信程序時他可能希望繼續(xù)上次的編輯。這種情況我們就可以覆寫Activity的void
onSaveInstanceStdte(BundleoulStale)事件,通過向outSlate中寫入,些我們需要在窗體銷毀前
保存的狀態(tài)或信息,這樣在窗體重新執(zhí)行onCreate的時候,則會通過savedlnstanceState將之
前保存的信息傳遞進(jìn)來,此時我們就可以有選擇的利用這些信息來初始化窗體,而不是-一切從頭
開始。
2.voidonStart()
onCreate事件之后執(zhí)行。或者當(dāng)前窗體被交換到后臺后,在用戶重新查看窗體前已經(jīng)過去了一段
時間,窗體已經(jīng)執(zhí)行了onStop事件,但是窗體和其所在進(jìn)程并沒有被銷毀,用戶再次重新查看
窗體時會執(zhí)行onRestart事件,之后會跳過onCreate事件,直接執(zhí)行窗體的onStart事件。
3.voidonResume()
onStart事件之后執(zhí)行?;蛘弋?dāng)前窗體被交換到后臺后,在用戶重新查看窗體時,窗體還沒有被銷
毀,也沒有執(zhí)行過onStop事件(窗體還繼續(xù)存在于Task中),則會跳過窗體的onCreate和onStart
事件,直接執(zhí)行onResume事件。
4.voidonPause()
窗體被交換到后臺時執(zhí)行。
5.voidonStop()
onPause事件之后執(zhí)行。如果一段時間內(nèi)用戶還沒有重新查看該窗體,則該窗體的onStop事件
將會被執(zhí)行;或者用戶直接按了Back鍵,將該窗體從當(dāng)前Task中移除,也會執(zhí)行該窗體的onStop
事件。
6.voidonRestart()
onStop事件執(zhí)行后,如果窗體和其所在的進(jìn)程沒有被系統(tǒng)銷毀,此時住戶又重新查看該窗體,則
會執(zhí)行窗體的onRestart事件,onRestart事件后會跳過窗體的onCreate事件直接執(zhí)行onStart
事件。
7.voidonDestroy()
Activity被銷毀的時候執(zhí)行。在窗體的onStop事件之后,如果沒有再次查看該窗體,Activity則會
被銷毀。
最后用一個實際的例子來說明Activity的各個生命周期。假設(shè)有一個程序由2個ActivityA和
B組成,A是這個程序的啟動界面。當(dāng)用戶啟動程序時,Process和默認(rèn)的Task分別被創(chuàng)建,接
著A被壓入到當(dāng)前的Task中,依次執(zhí)行了onCreate,onStart,onResume事件被呈現(xiàn)給了用戶;
此時用戶選擇A中的某個功能開啟界面B,界面B被壓入當(dāng)前Task遮蓋住了A,A的onPause事
件執(zhí)行,B的onCreate,onStart,onResume事件執(zhí)行,呈現(xiàn)了界面B給用戶;用戶在界面B操
作完成后,使用Back鍵回到界面A,界面B不再可見,界面B的onPause,onStop,onDestroy
執(zhí)行,A的onResume事件被執(zhí)行,呈現(xiàn)界面A給用戶。此時突然來電,界面A的onPause事件被
執(zhí)行,電話接聽界面被呈現(xiàn)給用戶,用戶接聽完電話后,又按了Home鍵回到桌面,打開另一個程
序“聯(lián)系人”,添加了聯(lián)系人信息又做了一些其他的操作,此時界面A不再可見,其onStop事件
被執(zhí)行,但并沒有被銷毀。此后用戶重新從菜單中點擊了我們的程序,由于A和其所在的進(jìn)程和
Task并沒有被銷毀,A的onRestart和onStart事件被執(zhí)行,接著A的onResume事件被執(zhí)行,A
又被呈現(xiàn)給了用戶。用戶這次使用完后,按Back鍵返回到桌面,A的cnPause,onSlop被執(zhí)行,
隨后A的onDestroy被執(zhí)行,由于當(dāng)前Task中己經(jīng)沒有任何Activity,A所在的Process的重要
程度被降到很低,很快A所在的Process被系統(tǒng)結(jié)束。
在Android中窗體與窗體之間如何互相調(diào)用和交換數(shù)據(jù)?窗體(Activity)和后臺的服務(wù)(Service)
如何通信?基于Unix(Linux)的系統(tǒng)都有一個很優(yōu)秀的傳統(tǒng),就是倡導(dǎo)非常輕便的進(jìn)程間通信
(IPC)機制;倡導(dǎo)進(jìn)程通過IPC來互相協(xié)作;倡導(dǎo)功能單一,小巧而強壯的進(jìn)程,而不是又大
又復(fù)雜的''萬金油〃。同樣,在Android中我們可以將我們的Activity和Service放在不同的進(jìn)程中
運行,我們可以在我們的Task中加載其他進(jìn)程的Activity,這些機制都鼓勵我們''盡量利用已有
的功能,利用IPC和包含這些己有功能的程序協(xié)作,來完成一個完整的應(yīng)用〃,例如在我們的程序
中充分利用GoogleMap的相關(guān)窗體和服務(wù)。所有這些都建立在一套輕更好用的IPC機制上。
Android的組件和進(jìn)程間通信都建立在一種基于稱為Intent的消息基礎(chǔ)之上。Intent就是一種消
息,它包含了兩個重要的內(nèi)容:1.消息的目的,即這個消息是發(fā)給哪個組件的?(消息的目的中
不會包含”消息是發(fā)給哪個進(jìn)程”這樣的信息,這里Android有意淡化進(jìn)程的概念,而只讓我們關(guān)
心組件,因為了解太多關(guān)于進(jìn)程的具體信息會加大復(fù)雜度,而又如何做到進(jìn)程間的消息傳遞呢?
下文會說到一種Android中關(guān)于這點比較特別的設(shè)計方式,我認(rèn)為是一種簡捷有用又符合手機特
點的設(shè)計);2.消息所攜帶的數(shù)據(jù)內(nèi)容,即需要傳遞給目標(biāo)的數(shù)據(jù)。下面是一個簡單的利用Intent
來啟動一個Service并向其傳遞數(shù)據(jù)的代碼示例:
Intentserviceintent=newIntent(contextzsvrMain.class);
serviceIntent.putExtra(''Network_Report^networkstatus);
context,startService(servicelntent);
上面的代碼首先構(gòu)造了一個Intent對象,并在構(gòu)造的時候指定了這個Intent的目的地,即
wsvrMain.class/z,表示這個Intent是要傳遞給一個類名叫svrMain的Service<.然后向這個Intent
中放入了一個數(shù)據(jù),數(shù)據(jù)的key為''Network_Report〃,value為一個叫networkstatus的int類型
變量,用來指明當(dāng)前網(wǎng)絡(luò)的狀態(tài)。最后我們使用系統(tǒng)提供的上下文API,將這個Intent傳遞給指
定的Serviceo
Intent的消息目的地分為兩種模式,一種是顯式的,一種是隱式的。我們上面的例子中看到的就
是一個顯式消息的例子。顯式消息直接指定消息目的地組件的類元信息,例如上面例子中svrMain
就是我們寫的一個類名為svrMain的Service,class操作符就是獲取其類元信息。這種模式的消
息由于己經(jīng)確切知道了消息目標(biāo)的確切信息,所以只適用于同一進(jìn)程內(nèi)的不同組件之間通信,例
如打開一個子窗體,和同一進(jìn)程中的service通信等。
對應(yīng)的,隱式消息就一般用于跨進(jìn)程的通信了,隱式消息沒有確定的消息目的地,除了數(shù)據(jù)
外,隱式消息只是包含了一些用于表征消息特征的描述字段。而一些需要收到某種特定特征消息
的某個程序中的某個組件,需要通過在其所在程序的AndroidMainifest.xml中注冊一種被稱為
intent-filte「的消息特征篩選器,然后Android系統(tǒng)會按照一定的匹配規(guī)則來匹配發(fā)出的消息特征
和所有擁有響應(yīng)這種特征的intent-filter的組件(無論是同一進(jìn)程內(nèi)的組件還是不同程序中的組
件),匹配到的組件就會接受到相應(yīng)的消息。前面的描述多少有些拗口,我們舉個實際的例子來說
明,如果我們想開啟一個子窗體(無論這個窗體來自同一進(jìn)程還是不同進(jìn)程),我們除了使用顯式
消息外,我們還可以使用隱式消息:
IntentopenSomeDiaglntent=newIntent();
openSomeDiagIntent.setAction(''edwin.demo.fooActivity,z);
this.startActivity(openSomeDiaglntent);
上面的隱式消息不包含具體的目的地,而是僅包含一個名位''Action〃的特征字符串,Action就是上
文所說的Intent特征的一種。從字面上來理解,可以理解為這個消息所代表的是完成某一個動作
的含義,由action來標(biāo)明動作的名字。所有能夠處理這種動作的Activity都可以收到該消息。對
應(yīng)的,可能在同?個程序或者另外的某個程序的AndroidMainifest.xml中聲明了下面這樣的?個
Activity:
<activityandroid:name=//.fooActivity/,>
<intent-fliter>
<actionandroid:name=//edwin.demo.fooActivity///>
</intent-filter>
</activity>
那么這就表示這個Activity能夠收到并處理action為"edwin.demo.fooActivity”的消息。所以上面
的代碼串起來的效果就是,打開了這個名為.fooActivity的窗口,無論這個窗口是在當(dāng)前的進(jìn)程中
還是另外的一個程序中。
除了Action這種消息特征外,Intent還有category,data這兩個特征描述屬性。Category同
樣是一個字符串,從字面上理解就是“消息的分類特征“。從程序上看其和Action的不同在于,一
個Intent只能有惟一的一個Action名稱,但是卻可以包含多個Category字符串;一個Intent-Filter
可以包含多個Action節(jié)點但至少要包含一個,另一方面一個Intent-Filter可以包含零到多個
Category節(jié)點。Android在做Intenr-Filter匹配的時候,Intent的Action屬性匹配到Intent-Filter
中的任何一個action節(jié)點,就表明擁有這個Intent-Filter的組件能夠處理這種消息;而對于
Category來講一個Intent中的所有的Category都必須存在于Intent-Filter中的Category節(jié)點中
時,才表明匹配成功。
Data屬性可以描述一個Intent所要傳遞的數(shù)據(jù)類型和URL每一個Intent只能包含一個Data
屬性。其中數(shù)據(jù)的類型使用MIME類型描述方式來描述,例如video/mpeg表示編碼格式為mpeg
的視頻,這里也可以使用通配符,例如video/*表示任意格式的視頻文件類型;數(shù)據(jù)的URI由
scheme(協(xié)議),host,port,path四部分組成:scheme:〃host:port/path,例如
:8080/file/filel或者
content://edwin.demo.contentProvider:100/forder/contentl,其中path部分也是可以支持通配
符的。Data屬性是一個很有用的描述特征,例如下面這樣的一個包含data節(jié)點的Intent-Filler:
<activityandroid:name=zz.actHttpVideoMan,/>
<intent-fliter>
<actionandroid:name=,<edwin.demo.actHttpVideoMan.Mainzz/>
<dataandroid:scheme=//http,zandroid:type=wvideo/*w/>
</intent-filter>
</activity>
它表示窗體actHttpVideoMan能夠處理來自web服務(wù)器的視頻文件。這樣的filter有什么作用呢?
最典型的情況就是配合瀏覽器工作。瀏覽器在打開一個鏈接的時候首先會嘗試顯示這個鏈接對應(yīng)
的html頁面,如果這個鏈接不是一個html頁面,而是一個視頻文件或者其他瀏覽器本身不能處
理的格式的話,瀏覽器會使用隱式消息嘗試開啟?個能夠處理這種數(shù)據(jù)格式的Activity求處理,
瀏覽器發(fā)出的隱式消息就是一個包含data屬性,其中URIscheme為http,數(shù)據(jù)類型為video/*
的消息,如果有能夠匹配這個inten:的組件,例如我們上面的那個activity,瀏覽器就會啟動這個
窗體,接著這個窗體會根據(jù)data屬性指定的URI去播放在線視頻,如果沒有可以處理這個intent
的Activity,瀏覽器才會調(diào)用下載管理器下載文件。
隱式消息這個設(shè)計簡單有效,它忽略了進(jìn)程的細(xì)節(jié),讓IPC在一個更高的更接近人腦思維模式的
層次工作,讓系統(tǒng)中的不同進(jìn)程協(xié)作看起來就像是同一程序中的協(xié)作一樣,這種簡單的IPC機制
在很大的程度上鼓勵我們和其他進(jìn)程協(xié)作,通過協(xié)作的進(jìn)程來完成一個復(fù)雜的任務(wù),而不是把什
么功能都做到一個大而全的程序里面。不過上文還有一些細(xì)節(jié)沒有提到,例如如果一個intent有
多個可匹配的處理組件,系統(tǒng)如何處理?這就要分響應(yīng)消息的組件類型來說了,如果是service,
那么這些service都可以啟動并處理消息,如果是Activity,則android會彈出一個對話框讓用戶
進(jìn)行選擇。比如我們安裝了多個可以處理在線視頻的軟件,當(dāng)我們在瀏覽器中點擊一個在線視頻
的鏈接時,系統(tǒng)會讓用戶選擇使用哪個軟件來觀看。另外大家一定會想到安全性的問題,如果不
同進(jìn)程間的組件可以通過隱式消息互相通信,那我們的程序不是可以輕易調(diào)用到其他的程序或者
系統(tǒng)中的一些敏感程序的組件,這樣會不會很不安全呢?其實Android在安全方面有一個統(tǒng)一,
完備和輕便的安全策略模型,Intent的安全自然是被考慮在內(nèi)的,關(guān)于android的安全模型我會
在后續(xù)的系列blog中專門說明。
最后,除了Intent這種基于消息的進(jìn)程內(nèi)和進(jìn)程間通信模型外,android中也有一種相比起來梢
顯笨重一些的IPC機制,它采用類似遠(yuǎn)程方法調(diào)用的方案,通過接口定義文件AIDL來定義一個
IPC接口,然后通過接收方實現(xiàn)接口,調(diào)用方調(diào)用接口的本地代理實現(xiàn)來完成IPCo這種模型只
適用于Activity和Service間的通信,之所以需要這種稍顯重量的模式,是因為Activity除了發(fā)送
intent去啟動一個service外,可能還需要能夠在Service的運行過程中連接到service,對Service
發(fā)送一些控制請求。例如音樂播放程序,其后臺的播放服務(wù)往往獨立運行,以方便我們在使用其
他程序界面時也能聽到音樂。同時這個后臺播放服務(wù)也會定義一個控制接口,包含比如播放,暫
停,快進(jìn)之類的方法,任何時候播放程序的界面都可以通過使用bindSer/iceAPI連接到播放服務(wù),
獲取這個接口的包含IPC細(xì)節(jié)的實現(xiàn)代理,通過這組控制接口方法對其進(jìn)行控制,這時這種IPC
的方案就顯的更方便更直觀一些了。有關(guān)使用AIDL這種IPC的更詳細(xì)描述,Gooqle的官方文檔
已做了詳細(xì)的講解。
apkAPK是AndroidPackage的縮寫,即Android安裝包(anapk)。APK是類似SymbianSis或Sisx
的文件格式。通過將APK文件直接傳到Android模擬器或Android手機中執(zhí)行即可安裝。apk
文件和sis一樣最終把androidsdk編譯的工程打包成一個安裝程序文件格式為apk。APK文件其
實是zip格式,但后綴名被修改為apk,通過UnZip解壓后,可以看到Dex文件,Dex是DalvikVM
executes的全稱,即AndroidDalvik執(zhí)行程序,并非JavaME的字節(jié)碼而是Dalvik字節(jié)碼。一個
APK文件結(jié)構(gòu)為:META-INF\Jar文件中??梢钥吹絩es\存放資源文件的目錄
AndroidManifest.xml程序全局配置文件classes.dexDalvik字節(jié)碼resources.arse編譯后的二進(jìn)制
資源文件總結(jié)下我們發(fā)現(xiàn)Android在運行一個程序時首先需要UnZip,然后類似Symbian那樣直
接,和WindowsMobile中的PE文件有區(qū)別,這樣做對于程序的保密性和可靠性不是很高,通過
dexdump命令可以反編譯,但這樣做符合發(fā)展規(guī)律,微軟的WindowsGadgets或者說WPF也采
用了這種構(gòu)架方式。在Android平臺中dalvikvm的執(zhí)行文件被打包為叩k格式,最終運行時加載
器會解壓然后獲取編譯后的andioidmanifest.xml文件中的permission分支相關(guān)的安全訪問,但仍
然存在很多安全限制,如果你將apk文件傳到/system/app文件夾下會發(fā)現(xiàn)執(zhí)行是不受限制的。最
終我們平時安裝的文件可能不是這個文件夾,而在androidrom中系統(tǒng)的apk文件默認(rèn)會放入這個
文件夾,它們擁有著root權(quán)限。
【三】組件入門
組件(Component),在談及所謂架構(gòu)和重用的時候,是一個重要的事情。很多時候都會說基
于組件的軟件架構(gòu),指的是期望把程序做樂高似的,有一堆接口標(biāo)準(zhǔn)封裝完整的組件放在哪里,
想用的時候取上幾個一搭配,整個程序就構(gòu)建完成了。
在開篇的時候就在說,Android是一個為組件化而搭建的平臺,它引入所謂Mash-Up的概念,
這使得你在應(yīng)用的最上層,想做的不組件化都是很困難的一件事情(底層邏輯,好吧,管不了…)。
具體說來,Android有四大組件四喜丸子;Activity>ServiceBroadcastReceiver^Content
Provider,
Activity
做一個完整的Android程序,不想用到Activity,真的是比較困難的一件事情,除非是想做綠葉
想瘋了。因為Activity是Android程序與用戶交互的窗口,在我看來,從這個層面的視角來看,
Android的Activity特像網(wǎng)站的頁面。
首先,一個網(wǎng)站,如果一張頁面都沒有,那…,真是一顆奇葩。而一張頁面往往都有個獨立的主
題和功能點,比如登錄頁面,注冊頁面,管理頁面,如是。
在每個頁面里面,會放一些鏈接,已實現(xiàn)功能點的串聯(lián),有的鏈接點了,刷,跑到同一站點的另
一個頁面去了;有的鏈接點了,啾,可能跳到其他網(wǎng)站的頁面去;還有的鏈接點了,恩…,這次
沒跑,但當(dāng)前頁面的樣子可能有所變化了。這些模式,和Activity給人的感覺很像,只不過實現(xiàn)
策略不同罷了,畢竟Android這套架構(gòu)的核心思想,本身就來自源于Web的Mash-Up概念,
視為頁面的客戶端化,也未嘗不可。
Activity,在四大組件中,無疑是最復(fù)雜的,這年頭,一樣?xùn)|西和界面掛上了勾,都簡化不了,
想一想,獨立做一個應(yīng)用有多少時間淪落在了界面上,就能琢磨清楚了。從視覺效果來看,一個
Activity占據(jù)當(dāng)前的窗口,響應(yīng)所有窗口事件,具備有控件,菜單等界面元素。從內(nèi)部邏輯來看,
Activity需要為了保持各個界面狀態(tài),需要做很多持久化的事情,還需要妥善管理生命周期,和
一些轉(zhuǎn)跳邏輯。對于開發(fā)者而言,就需要派生一個Activity的子類,然后埋頭苦干上述事情。對
于Activity的更多細(xì)節(jié),先可以參見:refe「ence/android/app/Activity.html。后續(xù),會獻(xiàn)上
更為詳盡的剖析。
Service
服務(wù),從最直白的視角來看,就是剝離了界面的Activity,它們在很多Android的概念方面比較
接近,都是封裝有一個完整的功能邏輯實現(xiàn),只不過Service不拋頭露臉,只是默默無聲的做堅
實的后盾。
但其實,換個角度來看,Android中的服務(wù),和我們通常說的Windows服務(wù),Web的后臺服
務(wù)又有一些相近,它們通常都是后臺長時間運行,接受上層指令,完成相關(guān)事務(wù)的模塊。用運行
模式來看,Activity是跳,從?個跳到?個,呃…,這有點像模態(tài)對話框(或者還像web頁面
好了…),給一個輸入(抑或沒有…),然后不管不顧的讓它運行,離開時返呵I輸出(同抑或沒
有…)。
而Service不是,它是等,等著上層連接上它,然后產(chǎn)生一段持久而纏綿的通信,這就像一個用
了Ajax頁面,看著沒啥變化,偷偷摸摸的和Service不知眉來眼去多少回了。
但和一般的Service還是有所不同,Android的Service和所有四大組件一樣,其進(jìn)程模型都是
可以配置的,調(diào)用方和發(fā)布方都可以有權(quán)利來選擇是把這個組件運行在同一個進(jìn)程下,還是不同
的進(jìn)程下。這句話,可以拿把指甲刀刻進(jìn)腦海中去,它凸顯了Android的運行特征。如果一個
Service,是有期望運行在于調(diào)用方不同進(jìn)程的時候,就需要利用Android提供的RPC機制,
為其部署?套進(jìn)程間通信的策略。
Android的RPC實現(xiàn),如上圖所示(好吧,也是從SDK中拿來主義的…),無甚稀奇,基于代
理模式的一個實現(xiàn),在調(diào)用端和服務(wù)端都去生成一個代理類,做一些序列化和反序列化的事情,
使得調(diào)用端和服務(wù)器端都可以像調(diào)用一個本地接口一樣使用RPC接口。
Android中用來做數(shù)據(jù)序列化的類是Parcel,參見:/「eference/android/os/Pa「cel.html,
封裝了序列化的細(xì)節(jié),向外提供了足夠?qū)ο蠡脑L問接口,Android號稱實現(xiàn)非常高效。
還有就是AIDL(AndroidInterfaceDefinitionLanguage),一種接口定義的語言,服務(wù)的
RPC接口,可以用AIDL來描述,這樣,ADT就可以幫助你自動生成一整套的代理模式需要用到
的類,都是想起來很乏力寫起來很苦力的那種。更多內(nèi)容,可以再看看:
guide/developing/tools/aidl.html,如果有興致,可以找些其他PRC實現(xiàn)的資料lou幾眼。
關(guān)于Service的實現(xiàn),還強推參看APIDemos這個Sample里面的RemoteService實現(xiàn)。
它完整的展示了實現(xiàn)一個Service需要做的事情:那就是定義好需要接受的Intent,提供同步
或異步的接口,在上層綁定了它后,通過這些接口(很多時候都是RPC的…)進(jìn)行通信。在RPC
接口中使用的數(shù)據(jù)、回調(diào)接口對象,如果不是標(biāo)準(zhǔn)的系統(tǒng)實現(xiàn)(系統(tǒng)可序列化的),則需要自定
義aidl,所有一切,在這個Sample里都有表達(dá),強薦。
Service從實現(xiàn)角度看,最特別的就是這些RPC的實現(xiàn)了,其他內(nèi)容,都會接近于Activity的
一些實現(xiàn),也許不再會詳述了。
BroadcastReceiver
在實際應(yīng)用中,我們常需要等,等待系統(tǒng)抑或其他應(yīng)用發(fā)出一道指令,為自己的應(yīng)用擦亮明燈指
明方向。而這種等待,在很多的平臺上,都會需要付出不小的代價。
比如,在Symbian中,你要等待一個來電消息,顯示歸屬地之類的,必須讓自己的應(yīng)用忍辱負(fù)
重偷偷摸摸的開機啟動,消隱圖標(biāo)陷藏任務(wù)項,潛伏在后臺,監(jiān)控著相關(guān)事件,等待轉(zhuǎn)瞬即逝的
出手機會。這是一件很發(fā)指的事情,不但白白耗費了系統(tǒng)資源,還留了個流氓軟件的罵名,這真
是賣力不討好的正面典型。
在Android中,充分考慮了廣泛的這類需求,于是就有了BroadcastReceive「這樣的一個組件。
每個BroadcastReceiver都可以接收一種或若干種Intent作為觸發(fā)事件(有不知道Intent的
么,后面會知道了…),當(dāng)發(fā)生這樣事件的時候,系統(tǒng)會負(fù)責(zé)喚醒或傳遞消息到該Broadcast
Receiver,任其處置。在此之前和這以后,BroadcastReceive「是否在運行都變得不重要了,
及其綠色環(huán)保。
這個實現(xiàn)機制,顯然是基于一種注冊方式的,BroadcastReceiver將其特征描述并注冊在系統(tǒng)
中,根據(jù)注冊時機,可以分為兩類,被我冠名為冷熱插拔。所謂冷插拔,就是BroadcastReceiver
的相關(guān)信息寫在配置文件中(求配置文件詳情?稍安,后續(xù)奉上…),系統(tǒng)會負(fù)責(zé)在相關(guān)事件發(fā)
生的時候及時通知到該BroadcastReceiver,這種模式適合于這樣的場景。某事件方式->通
知Broadcast,啟動相關(guān)處理應(yīng)用。比如,監(jiān)聽來電、郵件、短信之類的,都隸屬于這種模式。
而熱插拔,顧名思義,插拔這樣的事情,都是由應(yīng)用自己來處理的,通常是在OnResume事件
中通過registerReceiver進(jìn)行注冊,在OnPause等事件中反注冊,通過這種方式使其能夠在
運行期間保持對相關(guān)事件的關(guān)注。比如,一款優(yōu)秀的詞典軟件(比如,有道詞典…),可能會有
在運行期間關(guān)注網(wǎng)絡(luò)狀況變化的需求,使其可以在有廉價網(wǎng)絡(luò)的時候優(yōu)先使用網(wǎng)絡(luò)查詢詞匯,在
其他情況下,首先通過本地詞庫來查詞,從而兼顧腰包和體驗,一舉兩得一石二鳥一箭雙雕(注,
真實在有道詞典中有這樣的能力,但不是通過BroadcastReceive「實現(xiàn)的,僅以為例…)。而
這樣的監(jiān)聽,只需要在其工作狀態(tài)下保持就好,不運行的時候,管你是天大的網(wǎng)路變化,與我何
干。其模式可以歸結(jié)為:啟動應(yīng)用->監(jiān)聽事件?>發(fā)生時進(jìn)行處理。
除了接受消息的一方有多種模式,發(fā)送者也有很重要的選擇權(quán)。通常,發(fā)送這有兩類,一個就是
系統(tǒng)本身,我們稱之為系統(tǒng)Broadcast消息,在refe「ence/android/content/Intent.html
StandardBroadcastActions,可以求到相關(guān)消息的詳情。除了系統(tǒng),自定義的應(yīng)用可以放
出Broadcast消息,通過的接口可以是Context.sendBroadcast,抑或是
Context.sendOrderedBroadcasto前者發(fā)出的稱為Normalbroadcast,所有關(guān)注該消息的
Receiver,都有機會獲得并進(jìn)行處理;后者放出的稱作Orderedbroadcasts,顧名思義,接受
者需要按資排輩,排在后面的只能吃前面吃剩下的,前面的心情不好私吞了,后面的只能喝西北
風(fēng)了。
當(dāng)BroadcastReceiver接收至U相關(guān)的消息,它們通常做一些簡單的處理,然后轉(zhuǎn)化稱為一條
Notification,一次振鈴,一次震動,抑或是啟動一個Activity進(jìn)行進(jìn)一步的交互和處理。所以,
雖然Broadcast整個邏輯不復(fù)雜,卻是足夠有用和好用,它統(tǒng)一了Android的事件廣播模型,
讓很多平臺都相形見細(xì)了。更多BroadcastReceive「相關(guān)內(nèi)容,參見:
/reference/android/content/BroadcastReceiver.htmlo
ContentProvider
ContentProvider,聽著就和數(shù)據(jù)相關(guān),沒錯,這就是Android提供的第三方應(yīng)用數(shù)據(jù)的訪問
方案。在Android中,對數(shù)據(jù)的保戶是很嚴(yán)密的,除了放在SD卡中論數(shù)據(jù),一個應(yīng)用所持有的
數(shù)據(jù)庫、文件、等等內(nèi)容,都是不允許其他直接訪問的,但有時候,溝通是必要的,不僅對第三
方很重要,對應(yīng)用自己也很重要。
比如,一個聯(lián)系人管理的應(yīng)用。如果不允許第三方的應(yīng)用對其聯(lián)系人數(shù)據(jù)庫進(jìn)行增刪該查,整個
應(yīng)用就失去了可擴展力,必將被其他應(yīng)用拋棄,然后另立門戶,自個玩自個的去了。
Andorid當(dāng)然不會真的把每個應(yīng)用都做成一座孤島,它為所有應(yīng)用都準(zhǔn)備了一扇窗,這就是
ContentProvidero應(yīng)用想對外提供的數(shù)據(jù),可以通過派生Contentprovider類,封裝成一枚
ContentProvider,每個ContentProvider都用一個uri作為獨立的標(biāo)識,形如:
content://com.xxxxxo所有東西看著像REST的樣子,但實際上,它比REST更為靈活。和
REST類似,uri也可以有兩種類型,一種是帶id的,另一種是列表的,但實現(xiàn)者不需要按照這
個模式來做,給你id的uri你也可以返回列表類型的數(shù)據(jù),只要調(diào)用者明白,就無妨,不用苛求
所謂的RESTo
另外,ContentProvider不和REST一樣只有uri可用,還可以接受Projection,Selection,
OrderBy等參數(shù),這樣,就可以像數(shù)據(jù)庫那樣進(jìn)行投影,選擇和排序。查詢到的結(jié)果,以Cursor
(參見:reference/and「oid/database/Cu「sor.html)的形式進(jìn)行返回,調(diào)用者可以移動
Cursor來訪問各列的數(shù)據(jù)。
ContentProvider屏蔽了內(nèi)部數(shù)據(jù)的存儲細(xì)節(jié),向外提供了上述統(tǒng)一的接口模型,這樣的抽象
層次,大大簡化了上層應(yīng)用的書寫,也對數(shù)據(jù)的整合提供了更方便的途徑。ContentProvider
內(nèi)部,常用數(shù)據(jù)庫來實現(xiàn),Android提供了強大的Sqlite支持,但很多時候,你也可以封裝文件
或其他混合的數(shù)據(jù)。
在Android中,ContentResolvei■是用來發(fā)起ContentProvider的定位和訪問的。不過它僅
提供了同步訪問的ContentProvide「的接口。但通常,ContentProvider需要訪問的可能是
數(shù)據(jù)庫等大數(shù)據(jù)源,效率上不足夠快,會導(dǎo)致調(diào)用線程的擁塞。因此Android提供了一個
AsyncQueryHandler(參見:reference/android/content/AsyncQueryHandler.html),
幫助進(jìn)行異步訪問ContentProvidero
在各大組件中,Service和ContentProvider都是那種需要持續(xù)訪問的。Service如果是一個
耗時的場景,往往會提供異步訪問的接口,而ContentProvider不論效率如何,都提供的是約
定的同步訪問接口。我想這遵循的就是場景導(dǎo)向設(shè)計的原則,因為ContentProvider僅是提供
數(shù)據(jù)訪問的,它不能確信具體的使用場景如何,會怎樣使用它的數(shù)據(jù);而相比之下,Service包
含的邏輯更史雜更完整,可以抉擇大部分時候使用某接口的場景,從而確定最貼切的接口是同步
還是異步,簡化了上層調(diào)用的邏輯。
配置
四大組件說完了,四大組件幕后的英雄也該出場了,那就是每個應(yīng)用都會有一份的配置文件,名
稱是AndroidManifest.xml,在工程的根目錄下。在這個配置文件中,不僅會描述一些應(yīng)用相
關(guān)的信息,很重要的,會包含一個應(yīng)用中所有組件的信息。如果你派生Activity或者Service實
現(xiàn)了一個相關(guān)的類,這只是把它組件化的第一步,你需要把這個類的相關(guān)信息寫到配置文件中,
它才會作為一個組件被應(yīng)用到,否則只能默默無聞的黯淡度過余生。
擺了一幅圖出來,這次不是偷來的,是敝帚自珍原創(chuàng),所以沒有意外的畫的很丑,但基本還是可
以體現(xiàn)出一些意思。在InOthers的部分,這里是一般平臺應(yīng)用之間通信和交互的模型,每個應(yīng)
用都有很強烈的應(yīng)用邊界(往往表現(xiàn)為進(jìn)程邊界…),Appl的還是App2的,分得很是清楚。
每個應(yīng)用內(nèi)部,都有自己的邏輯去切分功能組件,這樣的切分通常沒有什么標(biāo)準(zhǔn),率性而為。應(yīng)
用間的交互邏輯也比較零散,Appl與App2交互,往往需要明確知道對方應(yīng)用的具體信息,
比如進(jìn)程ID,進(jìn)程名稱之類的,這樣使得應(yīng)用和應(yīng)用之間的聯(lián)系,變得很生硬。而上層應(yīng)用和系
統(tǒng)應(yīng)用的通信,往往有很多特定的模式,這種模式,很可能是無法直接應(yīng)用在普通應(yīng)用之間的,
換而言之,系統(tǒng)應(yīng)用是有一定特殊性的。
重點,在圖的下半部,描述的是Android的應(yīng)用情形。在Android中,應(yīng)用的邊界,在組件這
個層面,是極度模糊,什么進(jìn)程、什么應(yīng)用,都可以不必感知到。舉個例子,App1,實現(xiàn)了A
和B兩個組件,App2,實現(xiàn)了C這個組件。A和C,都想使用B這個組件,那么它們的使用方
式是完全一致的,都需要通過系統(tǒng)核心的組件識別和通信機制,找到和使用組件B。A,雖說和B
是一個娘胎里蹦出來的,很不好意思,沒有任何特殊的后面和捷徑,還是要跑規(guī)矩的途徑才能用
到,一片和諧社會的景象油然而生。
在Android中,所有組件的識別和消息傳遞邏輯都必須依賴底層核心來進(jìn)行(通信可以沒有底層
核心的參與,比如一旦Service找到了,就可以和它產(chǎn)生持久的通信…),沒有底層核心的牽線
搭橋,任何兩個組件都無法產(chǎn)生聯(lián)系。比如一個Activity,跳到另一個Activity,必須要向底層
核心發(fā)起?個Intent,有底層解析并認(rèn)可后,會找到另?個Activity,把相關(guān)消息和數(shù)據(jù)傳給它。
一個Activity想使用ContentProvider中的數(shù)據(jù),必須通過底層核心解析相關(guān)的uri,定位到
S4"ContentProvider,把參數(shù)傳遞給它,然后返回Activity需要的Cursor。這樣的設(shè)計,保
證了底層核心對所有組件的絕對掌控權(quán)和認(rèn)知權(quán),使得搭積木似的開發(fā)變成可能。
為了,使得核心系統(tǒng)能夠完整的掌握每個組件的信息,這就需要配置文件了。配置文件,就是將
組件插到底層核心上的這個插頭。只有通過這個插頭插在底層核心的插座上(不要亂想,非十八
禁…),組件才能夠發(fā)光發(fā)熱,閃耀光芒。
組件的配置信息在我看來主要包含兩個方面,一部分是描述如何認(rèn)知。比如,Activity.Service.
BroadcastReceiver都會有名字信息,和希望能夠把握的Intent信息(姑且看成消息好了…),
ContentProvide「會有一個描述其身份的uri。當(dāng)其他組件通過這樣的名字或者Intent,就可
以找到它。
另一部分是運行相關(guān)的信息。這個組件,期望怎么來運行,放在單獨的進(jìn)程,還是和調(diào)用者一個
進(jìn)程,還是找相關(guān)的其他組件擠在同一個進(jìn)程里面,這些內(nèi)容,都可以在配置的時候來決定(調(diào)
用者在這個約束范圍內(nèi),有進(jìn)一步的選擇權(quán)…)。更多配置項,請參見:
guide/topics/manifest/manifest-intro.htmL
通過前續(xù)內(nèi)容,也許可以幫助大家對Android組件有個初略的了解。但這些了解都還停留在靜態(tài)
層面,程序是個動態(tài)的概念,關(guān)于各個組件具體是怎么聯(lián)系在一起的,如何手拉手運行起來完成
一項功能的,這便是后話了。
【四】一一組件調(diào)用
Intent解析
基于組件的架構(gòu)體系,除了有定義良好的組件,如何把這些組件組裝在一起,也是一門藝術(shù)。在
Android中,Intent(貌似通常譯作:意圖…),就是連接各組件的橋梁。
前段時間看同事們做Symbian平臺的網(wǎng)易掌上郵(真的是做的用心,NB的一米,熱情歡迎所
有163郵箱的S60V3用戶,猛點擊之…),有個功能是為郵件添加附件,比如你想要通過郵件
發(fā)送一副圖片泡mm,可能需要有個很直觀的方式從本地選一副珍藏美圖,抑或是拿相機來個完
美自拍。在Symbian中,這樣的功能,都需要你用底層的API,自己一點點寫。為了讓選圖片
體驗更好,可能需要做一個類似于圖片瀏覽器之類的東西,為了把拍照做的更為順暢,甚至需要
實現(xiàn)從聚焦到調(diào)節(jié)亮度之類一整套的相機功能.
而其實呢,用戶的手機中可能本身就裝了其他的專業(yè)圖片瀏覽器、相機等應(yīng)用,這些應(yīng)用已經(jīng)非
常出色好用,而用戶也已然能很純屬使用它們,如果能進(jìn)行調(diào)用,對郵箱的開發(fā)者和用戶而言,
都會是個更好的選擇。但在Symbian這樣殘敗的系統(tǒng)里,應(yīng)用和應(yīng)用之間的結(jié)合能力奇弱無比,
想復(fù)用,基本比登天還難,作為開發(fā)者,只能忍住一次又一次的惡心,為了用戶,做這些重復(fù)造
輪子吃力不討好的附加工作。
還好還好,在Android中,一切變得美好多了,它將開發(fā)者從接口和對象的細(xì)節(jié)中解救出來,讓
我們有更多精力投入到核心功能的開發(fā)中去。在Android中,如果你需要選個圖拍個片,只需要
構(gòu)造一個描述你此項意愿的Intent,發(fā)送出去,系統(tǒng)會幫你選擇一個能夠處理該項業(yè)務(wù)的組件來
滿足你的需求,而不再需要糾結(jié)在具體的接口和實現(xiàn)上,PerfectWorld,便應(yīng)如此。
Intent構(gòu)成
Intent被譯作意圖,其實還是很能傳神的,Intent期望做到的,就是把實現(xiàn)者和調(diào)用者完全解
耦,調(diào)用者專心將以意圖描述清晰,發(fā)送出去,就可以夢想成真,達(dá)到目的。
當(dāng)然,這么說太虛了,庖丁解牛,什么東西切開來看看,乜許就清晰了。Intent
(reference/android/content/Intent.html),在Android中表現(xiàn)成一個類,發(fā)起一個意圖,
你需要構(gòu)造這樣一個對象,并為下列幾項中的一些進(jìn)行賦值:
Actiono當(dāng)日常生活中,描述一個意愿或愿望的時候,總是有一個動詞在其中。比如:我想做三
個俯臥撐;我要看一部x片;我要寫一部血淚史,之類云云。在Intent中,Action就是描述看、
做、寫等動作的,當(dāng)你指明了一個Action,執(zhí)行者就會依照這個動作的指示,接受相關(guān)輸入,表
現(xiàn)對應(yīng)行為,產(chǎn)生符合的輸出。在Intent類中,定義了一批量的動作,比如ACTION_VIEW,
ACTION_PICK,之類的,基本涵蓋了常用動作,整一個降龍十八掌全集。當(dāng)然,你也可以與時
俱進(jìn),創(chuàng)造新的動作,比如lou這樣的。與系統(tǒng)預(yù)定義的相比,這些自定義動作的流通范圍很是
有限,除非做了非常NB的應(yīng)用,大家都需要follow你,否則通常都是應(yīng)用內(nèi)部流通。
Data。當(dāng)然,光有動作還是不夠的,還需要有更確切的對象信息。比如,同樣是泡這個動作,但
泡咖啡,和泡妞,就差之千里了。Data的描述,在Android中,表現(xiàn)成為一個URI。用在內(nèi)部
通信中,可能描述是ContentProvider用的形如content:〃xxxx這樣的東東,抑或是外部的
一個形如tel:〃xxxx這樣的鏈接??偠灾悄軌蚯宄?zhǔn)確的描述一個數(shù)據(jù)地址的uri。
Type.說了Data,就必須要提Type,很多時候,會有人誤解,覺著Data和Type的差別,就
猶如泡妞和泡馬子之間的差別一樣,微乎其微。但其實不然,Type信息,是用MIME來表示的,
比如text/plain,這樣的東西。說到這里,兩者差別就很清晰了,Data就是門牌號,指明了具
體的位置,具體問題具體分析,而type,則是強調(diào)物以類聚,解決一批量的問題。實際的例子是
這樣的,比如,從某個應(yīng)用撥打一個電話,會發(fā)起的是action為ACTION_DIAL且data為
tel:xxx這樣的In
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 金融幫扶框架協(xié)議書
- 律師委托代理協(xié)議包干
- 2025版?zhèn)€人獨資企業(yè)股權(quán)置換及轉(zhuǎn)讓合同范本2篇
- 2025版二手房買賣退房條件協(xié)議書
- 2025-2030全球液體金合歡烯橡膠行業(yè)調(diào)研及趨勢分析報告
- 2025-2030全球變頻用移相變壓器行業(yè)調(diào)研及趨勢分析報告
- 2025-2030全球國防輕型戰(zhàn)術(shù)車輛行業(yè)調(diào)研及趨勢分析報告
- 2025-2030全球高性能碳纖維材料行業(yè)調(diào)研及趨勢分析報告
- 食堂炊事員聘用協(xié)議范本
- 2025年度個人自有房產(chǎn)租賃轉(zhuǎn)租委托協(xié)議3篇
- 電纜擠塑操作手冊
- 浙江寧波鄞州區(qū)市級名校2025屆中考生物全真模擬試卷含解析
- 2024-2025學(xué)年廣東省深圳市南山區(qū)監(jiān)測數(shù)學(xué)三年級第一學(xué)期期末學(xué)業(yè)水平測試試題含解析
- IATF16949基礎(chǔ)知識培訓(xùn)教材
- 【MOOC】大學(xué)生創(chuàng)新創(chuàng)業(yè)知能訓(xùn)練與指導(dǎo)-西北農(nóng)林科技大學(xué) 中國大學(xué)慕課MOOC答案
- 勞務(wù)派遣公司員工考核方案
- 基礎(chǔ)生態(tài)學(xué)-7種內(nèi)種間關(guān)系
- 2024年光伏農(nóng)田出租合同范本
- 《阻燃材料與技術(shù)》課件 第3講 阻燃基本理論
- 2024-2030年中國黃鱔市市場供需現(xiàn)狀與營銷渠道分析報告
- 新人教版九年級化學(xué)第三單元復(fù)習(xí)課件
評論
0/150
提交評論