Android基礎(chǔ)知識資料_第1頁
Android基礎(chǔ)知識資料_第2頁
Android基礎(chǔ)知識資料_第3頁
Android基礎(chǔ)知識資料_第4頁
Android基礎(chǔ)知識資料_第5頁
已閱讀5頁,還剩27頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論