純Native的Service
純Native的Service表示代碼都在Native層。Native層有很多Service,前面的MS不就是一個重量級的嗎?
假設Service叫ITest,我們該如何實現呢?完全可以模仿MS!具體實現過程如下所示:
Test是怎麼定義的呢?我們是跨進程的C/S,所以本地需要一個BnTest,對端需要提供一個代理BpTest。爲了不暴露Bp的身份,Bp的定義和實現在放在BnTest.cpp中了。
1. 我能幹什麼
ITest接口表明了它所提供的服務,例如getTest和setTest等,這個與業務邏輯相關,代碼如下所示:
2. 定義BnTest和BpTest
爲了把ITest融入到Binder系統,需要定義BnTest和對客戶端透明的BpTest。BnTest定義既可以與上面的Test定義放在一塊,也可以分開,如下所示:
另外,我們還要使用IMPLEMENT宏。參考BnMediaPlayerService的方法,把BnTest的BpTest的實現都放在ITest.cpp中,如下所示:
BpTest也在這裏實現。如下所示:
純Native的Service寫起來量大一些,上面的代碼還只是把C/S的框架寫好了,真正的業務處理尚未開始,不過感覺卻很踏實,很厚重。那麼Java層的Service該怎麼寫呢?
扶得起的“阿斗”(aidl)
阿斗(aidl的諧音)本來是扶不起的,可是我們有了AIDL工具,就有可能將他扶起!
1. 我能幹什麼?
在Java層中,如果想要利用Binder進行跨進程的通信,也得定義一個類似ITest的接口,不過這是一個aidl文件。現在假設服務端程序都在com.test.service包中。
ITest.aidl文件的內容如下:
定義完後。如果使用Eclipse進行編譯,會在gen目錄下生成一個com.test.ITest.java文件(也會生在對應包結構的目錄)。
2. 實現服務端:
com.test.ITest.java只是實現了類似BnTest的一個東西,具體的業務實現還需要從ITest.Stub派生,實現代碼如下所示:
這時,你的Eclipse下會有如下目錄:
1. src下有一個com.test.service包結構目錄
2. gen下也有一個com.text.service包結構目錄,其中的內容是由aidl工具生存的。
3. 實現代理端
代理端往往在另外一個程序中使用。假設是com.test.client包,把剛纔com.test.service工程中的gen下的com.test.service目錄全部複製到com.test.client中了。這樣,client工程也就有兩個包結構目錄了:
1. com.test.client
2. com.test.service。 不過這個目錄中僅有aidl生成的Java文件。
服務端一般駐留在Service進程中,所以可以在Client端的onServiceConnected函數中獲得代理對象,實現代碼如下:
4. 傳遞複雜的數據結構
AIDL支持簡單數據結構與Java中String類型的數據進行跨進程傳遞,如果向做到跨進程傳遞複雜的數據結構,還需另做一些工作。
以ITest.aidl文件中使用的complicatedDataStructure爲例:
1. 它必須實現implements Parcelable接口
2. 內部必須有一個靜態的CREATOR類。
3. 定義一個coplicatedDataStructure.aidl文件
可參考Android API文檔的parcelable類,裏面有一個很簡單的例子。
來看着個Java文件的實現:
complicatedDataStructure.aidl該怎麼寫呢?如下所示:
然後在使用它的aidl文件中添加下行代碼即可:
有了AIDL,再看我們的阿斗是不是能扶得起了呢?當然,想讓上面的程序正確工作,還得再努力,把未盡的業務層事業完成。另外,還要經得起殘酷環境的考驗(即通過測試來檢驗自己的程序)。