Android 理解Binder機制(一) AIDL+Service的簡單使用
本文主要分成以下幾個部分:
簡單介紹remote 和 local?Service
介紹啟動Service的兩種api的異同
AIDL + remote service的實踐

Remote 和 Local Service
Android中存在兩種Service,一種是local service,一種是remote service。remote service主要使用于進程間通信的場景。
進程之間的數(shù)據(jù)是被隔離的,不能相互訪問。假設(shè)目前存在兩個進程,分別是客戶端和服務(wù)端。客戶端進程需要獲取某些數(shù)據(jù),這些數(shù)據(jù)的處理邏輯只能由服務(wù)端來處理。在這種情況下,我們可以在服務(wù)端進程中定義一個Remote Service,通過服務(wù)端調(diào)用Remote Service中的方法的方式來返回數(shù)據(jù)。
AIDL的作用
上述的說法存在一個問題:因為客戶端和服務(wù)端的內(nèi)存空間是隔離的,從客戶端的視角來看,它并不知道服務(wù)端中返回數(shù)據(jù)的邏輯。對于這個問題,我們可以使用【接口】來完成:只要服務(wù)端和客戶端都持有這個【接口】,服務(wù)端中實現(xiàn)接口的業(yè)務(wù)邏輯,客戶端中跨進程調(diào)用這個接口即可。
在這種情況下,Android提出了一種【接口】也就是AIDL,舉個例子:
在里面定義了兩個接口。AIDL會通過Android SDK生成同名的Java文件,這樣就幫助了開發(fā)些寫template code。具體的生成AIDL對應(yīng)的Java文件的分析會在下一篇文章中給出。大概的類結(jié)構(gòu)是這樣:

啟動兩種API的異同
startService & stopService
這一對api需要傳入一個intent即可
bindService & unbindService
這一對api的語義更強調(diào)【綁定】的性質(zhì),并且除了intent還需要傳入一個serviceConnection,如果在組件被onDestroy時沒有表用unbindService,會拋出異常。
因為bindService需要傳入一個ServiceConnection,ServiceConnection需要實現(xiàn)的回調(diào)中函數(shù)onServiceConnected中會給出一個IBinder,所以我們可以借助這個IBinder做跨進程調(diào)用。
通過這兩種方法表現(xiàn)的和Service周期變化如圖:

不管調(diào)用哪個方法,都會調(diào)用Service的構(gòu)造函數(shù),但是后面走了不太一樣的道路。需要有兩條值得注意的地方:
startService會調(diào)用onStartCommand回調(diào)。如果一個Service已經(jīng)start,再調(diào)用startService,還會走一遍onStartCommand。
bindService調(diào)用中,因為一個Service可能和多一個組件進行綁定,只有當(dāng)綁定Service全都unbindService,才會調(diào)用Service#onUnbind回調(diào)。
AIDL + remoteService的實踐
需求說明:
客戶端App中需要請求服務(wù)端中定義的返回書籍Book list,同時可以addBook
服務(wù)端需要提供返回Book list和add Book的具體實現(xiàn)
服務(wù)端
Book對象
首先定義Book類型。這里需要注意,因為操作系統(tǒng)只能識別一些傳輸?shù)幕绢愋?,對于?fù)合類型Book需要實現(xiàn)Parcelable才可以在跨進程中傳輸:
以上的代碼需要注意實現(xiàn):
writeToParcel,即將數(shù)據(jù)寫入Parcel中的方法。
需要提供解包的方法,這里具體是需要實現(xiàn)CREATOR對象,這個對象在AIDL生成的對應(yīng)接口類中會有使用到。
我個人感覺在Parcel中存儲的數(shù)據(jù)是通過一個native數(shù)組,將一些數(shù)據(jù)都連續(xù)地存在數(shù)組中。所以在CREATOR中createFromParcel也需要和writeToParcel對應(yīng)的順序讀?。ㄌ貏e是對于同種類型的數(shù)據(jù),因為不像一個Map,可以通過鍵值對取出)。
IBookManager.aidl
這個就是待會交給Android Studio 通過 make project會生成同名Java文件的【接口】:
這里需要注意,需要導(dǎo)入對應(yīng)的Book類,同時這個Book類也需要寫一個Book.aidl:
主要是指定Book是一個parcelable。
然后我們還需要定義一個Service,并且在AndroidManifest中注冊。注冊的時候記得寫上intent-filter:
定義的Service具體是為了實現(xiàn)具體的業(yè)務(wù)邏輯:
之所以需要實現(xiàn)IBookManager.Stub是因為這個Stub才是涉及到具體的Binder相關(guān)的邏輯的類,這個后面文章再解釋。
服務(wù)端就是這樣:文件路徑是這樣:

客戶端
客戶端需要注意:
重新在Android Studio建立新的包,放置Book.java Book.aidl, IBookManager。包名不能錯,否則會出現(xiàn)調(diào)用錯誤的interface異常,路徑如下:

2. 主要就是調(diào)用就完事了哦,但是需要使用顯式Intent。
在MainActivity中的代碼如下: