|
第一步 創(chuàng)建 aidl 接口文件 AndroidStudio 中直接右鍵創(chuàng)建,或者自己一步步建目錄嘍。 創(chuàng)建完成后會(huì)生成一個(gè) 在看接口怎么寫前,先記住以下三點(diǎn): 支持的參數(shù)類型
自定義引用類型使用如果要使用自定義的數(shù)據(jù)類型,需要先為它也生成一個(gè)aidl文件,里面內(nèi)容只需兩行: AIDL的包名;
parcelable 類名;例如: package com.coorchice.coorchicelibone;
parcelable Role;接著就可以創(chuàng)建對(duì)應(yīng)的java數(shù)據(jù)類了,然后實(shí)現(xiàn)Parcelable接口,注意包名需要和aidl一模一樣!如果你對(duì)自定義類型使用了in或者inout標(biāo)識(shí)符的話,你必須再給自定義類實(shí)現(xiàn) public void readFromParcel(Parcel in) {
name = in.readString();
skill = in.readString();
}然后在定義 aidl 接口時(shí),一定要記得手動(dòng)寫一下自定義引用類的import! 參數(shù)修飾符
定義服務(wù)接口現(xiàn)在,我們可以開始定義服務(wù)接口了!這里定義的服務(wù)接口就是后面我們需要在客戶端調(diào)用的。 CoorChice 定義了3個(gè)接口,接著編譯一下。然后編譯器會(huì)自動(dòng)根據(jù)我們定義的接口生成對(duì)應(yīng)的類。
編譯后生成的類解析編譯之后編譯器自動(dòng)幫我們生成了一個(gè) 其實(shí),Android 的 AIDL 就是讓編譯器幫助我們生成一個(gè)實(shí)現(xiàn)了我們接口的 Binder,以幫助我們簡化開發(fā)。當(dāng)然,如果你了解原理的話,也可以自己寫。 下面我們一步一步來看看這編譯器生成的類都有些什么? 1. 服務(wù)接口實(shí)現(xiàn)IInterfacepublic interface AIDLDemo extends android.os.IInterface
{
...
}編譯器根據(jù)我們寫的服務(wù)接口,重新生成了一個(gè)接口,唯一的區(qū)別就是新的接口繼承了 public interface IInterface
{
public IBinder asBinder();
}可以看到,它只有一個(gè)接口方法。這個(gè)方法用來定義將實(shí)現(xiàn)接口的類應(yīng)該具備返回一個(gè)與之相關(guān)聯(lián)的Binder的功能,以提供通訊能力。一般實(shí)現(xiàn)這個(gè)方法的類自己本身就會(huì)去繼承Binder。 這樣的設(shè)計(jì)使得Binder機(jī)制不用關(guān)心具體的接口是什么,只要是 2. 繼承Binder,實(shí)現(xiàn)服務(wù)接口要進(jìn)行 Binder 通訊,我們自然需要一個(gè) Binder;要實(shí)現(xiàn)我們定義的服務(wù)接口功能,自然就需要實(shí)現(xiàn)服務(wù)接口。那么需要滿足這兩個(gè)條件怎么辦?很簡單,繼承 Binder,然后實(shí)現(xiàn)服務(wù)接口就行。 編譯器為我們生成的類中有一個(gè)內(nèi)部類 public static abstract class Stub extends android.os.Binder implements com.coorchice.coorchicelibone.AIDLDemo3. Binder需要綁定服務(wù)接口,定義DESCRIPTOR描述為了一個(gè)Binder和一個(gè)特定服務(wù)接口綁定,以對(duì)外提供功能,需要給Binder定義一個(gè) 通常, 4. 實(shí)現(xiàn)asInterface()供客戶端調(diào)用作為一個(gè)服務(wù)提供者,為了能夠給調(diào)用者提供遠(yuǎn)程功能,自然需要能夠提供和遠(yuǎn)程服務(wù)關(guān)聯(lián)的 Binder 來通訊,請(qǐng)求服務(wù)。獲取 Binder 的接口就是 IInterface 中定義的。 先查詢一下獲取到的和遠(yuǎn)程 Service 通訊的 Binde 中是否已經(jīng)添加了功能接口的實(shí)現(xiàn),如果沒有則創(chuàng)建代理,通過代理間接的操作 Binder 和遠(yuǎn)程 Service 通訊,實(shí)現(xiàn)功能。 思考:既然我們已經(jīng)獲取到了能夠直接和遠(yuǎn)程 Service 通訊的Binder,為什么不直接操作它去向遠(yuǎn)程 Service 請(qǐng)求服務(wù)呢?確實(shí),我們可以直接操作 Binder 向遠(yuǎn)程 Service 請(qǐng)求服務(wù),但這過程中有很多繁瑣的操作,還有一些 code碼的區(qū)別,如果不封裝隔離的話,隨著功能的擴(kuò)展,我們將很難再去維護(hù)這段通訊邏輯。還有就是通過這種方式統(tǒng)一的管理通訊邏輯使得它可以隨處使用,而不用沒一個(gè)要用的地方都去寫一遍。 既然是要代理和遠(yuǎn)程服務(wù)通訊,而且通訊的目的是為了請(qǐng)求服務(wù)接口定義的功能,那么很自然就能想到去實(shí)現(xiàn)服務(wù)接口,然后再對(duì)應(yīng)的接口方法中實(shí)現(xiàn)邏輯即可。這樣就可以分開來維護(hù)客戶端和服務(wù)端的對(duì)應(yīng)的每個(gè)功能了。 所以,我們的代理也需要實(shí)現(xiàn)服務(wù)接口,然后在代理中操作遠(yuǎn)程通訊的Binder進(jìn)行通訊。 5. 重寫onTransact()在Binder通訊中,一個(gè)和遠(yuǎn)程端通訊的 public boolean transact(int code, Parcel data, Parcel reply, int flags){}
對(duì)應(yīng)的我們?cè)诳纯?code>Binder::transact()方法: public boolean transact(int code, Parcel data, Parcel reply, int flags){}
可以看出來,兩個(gè)是成對(duì)的操作。 這個(gè)過程可以大概抽象成這個(gè)樣子: 在編譯器自動(dòng)幫我們生成的 第二步. 創(chuàng)建一個(gè)遠(yuǎn)程 Service 我們正常創(chuàng)建一個(gè)支持其它應(yīng)用調(diào)用的 Service,Service 怎么創(chuàng)建就不說。主要看看在 Service 最重要的一步,就是繼承上面生成的Stub,然后自定義一個(gè) Binder。 接著,在 第三步. 客戶端鏈接Binder 首先重要的一步是,我們必須把這個(gè)aidl文件夾拷貝到客戶端工程的對(duì)應(yīng)目錄下。 包名不能變! 包名不能變! 包名不能變! 然后通過綁定的方式啟動(dòng)這個(gè)Service。 總結(jié) 恭喜你!現(xiàn)在你已經(jīng)掌握AIDL了! 實(shí)際上,從上面的分析可以看出,AIDL其實(shí)就是對(duì)Binder機(jī)制的簡化封裝。Android這一套封裝使得我們?cè)谧约憾xService時(shí)方便了許多!你可以不用去編寫繁雜的交互,看看編譯器自動(dòng)生成的文件有多不堪入目吧。 但是不管怎么封裝,Binder通訊機(jī)制的靈魂是不變的,所以要更好的理解這個(gè)過程,你可以看看CoorChice的這幾篇文章: 《從getSystemService()開始,開擼Binder通訊機(jī)制》http://www.jianshu.com/p/1050ce12bc1e; 《能用【白話文】來分析Binder通訊機(jī)制?》http://www.jianshu.com/p/fe816777f2cf; 《Binder機(jī)制之一次響應(yīng)的故事》 http://www.jianshu.com/p/4fba927dce05 這幾篇文章從我們接觸最多的上層入手,一步步分析到了 Binder 內(nèi)核層,描述了內(nèi)核的 Bidner 驅(qū)動(dòng)是如何實(shí)現(xiàn)一次完整的 c/s 通訊的。 與之相關(guān) 日 更 精 彩 微信號(hào):code-xiaosheng 公眾號(hào) 「code小生」 |
|
|