深刻理解Binder(二),Binder是什麼?

上篇文章深刻理解Binder(一),從AIDL談起咱們介紹了AIDL的基本使用,用AIDL兩個App的通訊是實現了,但是又有小夥伴疑惑了,爲何使用AIDL就可以實現兩個App之間的通訊?本文咱們就來詳細說說這個問題。java

Binder單從字面上理解,它有活頁夾,粘合劑的意思,活頁夾能夠用來把兩個東西夾在一塊兒。在咱們的Android系統中,Binder主要用來實現進程之間的通訊(IPC),它的主要做用就是把多個App夾在一塊兒。那麼這個Binder究竟是個什麼東西呢?其實它是一個工做在Linux層面的驅動,這一段驅動運行在內核態。咱們在客戶端調用Binder都是經過系統調用最終完成的。Binder自己又是一種架構,這種架構提供了服務端、Binder驅動和客戶端三個模塊。咱們用AIDL在服務端和客戶端生成的文件都是爲了完成服務端和客戶端的相關功能,OK,那麼接下來咱們就從服務端、Binder驅動、客戶端三個方面來分別分析Binder的工做原理。android

1.服務端架構

Binder服務端實際上就是一個Binder類的對象,當咱們建立一個Binder對象的時候,Binder內部就會啓動一個隱藏線程,該線程的主要做用就是接收Binder驅動發送來的消息,那麼Binder驅動爲何會給Binder服務端的線程發送消息呢?緣由很簡單,咱們在客戶端調用服務端的時候並不能直接調用服務端相應的類和方法,只能經過Binder驅動來調用。當服務端的隱藏線程收到Binder驅動發來的消息以後,就會回調服務端的onTransact方法,咱們來看看這個方法的方法頭:ide

protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException

剛方法接收四個參數,這四個參數都是客戶端的Binder傳來的,第一個參數用來指定客戶端要調用服務端的哪個方法,第二個參數是客戶端傳來的參數,第三個參數表示服務端返回的參數,最後一個flags表示客戶端的調用是否有返回值,0表示服務端執行完成以後有返回值,1表示服務端執行完後沒有返回值。OK,基於對服務端這樣的理解,我來自定義一個類,繼承自Binder ,實現和 上一篇博文相似的功能:

public class MyAddBinder extends Binder {
    private final static int ADD = 1;
    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code) {
            case ADD:
                data.enforceInterface("MyAddBinder");
                int a = data.readInt();
                int b = data.readInt();
                int add = add(a, b);
                reply.writeInt(add);
                return true;
        }
        return super.onTransact(code, data, reply, flags);
    }

    public int add(int a, int b) {
        return a + b;
    }
}

小夥伴們請看,假設個人服務端依然是提供一個加法服務,當Binder驅動調用onTransact方法的時候,我先根據code來判斷客戶端是想調用哪一個方法,而後從data中讀出客戶端傳遞來的全部數據,注意讀取順序要和客戶端的寫入順序一致(若是小夥伴們對Parcel的使用還不熟悉的話,能夠參考這篇文章 android開發之Parcelable使用詳解 ),讀出來以後調用相應的方法獲取兩個數的和,而後再將結果寫入到reply中便可。寫好以後,在服務端的Service中再將該BInder返回便可,以下:

public class MyService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyAddBinder();
    }
}

OK,這就是一個簡單的Binder服務端。

2.Binder驅動工具

Binder驅動是Binder服務端和Binder客戶端之間鏈接的一個橋樑,當一個服務端Binder被建立出來的時候,系統同時會在Binder驅動中建立另一個Binder對象,當客戶端想要訪問遠程的Binder服務端的時候, 都是經過這個Binder對象來完成的。那麼Binder驅動中的這個對象要怎麼樣獲取呢?其實很簡單,這個BInder對象就是咱們用綁定的方式啓動一個Service服務時,在綁定成功時所獲取的那個IBinder對象。以下:google

boolean b = bindService(intent, new ServiceConnection() {

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                //這個service就是Binder驅動中建立的Binder對象
                mRemote = service;
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        }, Service.BIND_AUTO_CREATE);

客戶端和服務端之間的交互就是經過這個Binder對象來進行的。

3.客戶端
spa

客戶端就簡單了,咱們首先須要在客戶端獲取Binder驅動中的Binder對象,而後調用該對象中的transact方法進行數據傳遞。客戶端在向服務端發送消息的時候是以線程間通訊的模式來進行的,並且調用服務端代碼是同步進行的,也就是說線程會阻塞。OK,基於此,咱們就來看看客戶端代碼該怎麼寫:.net

int code = 1;
        //向服務端發送的數據
        Parcel data = Parcel.obtain();
        //接收服務端返回的數據
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken("MyAddBinder");
        data.writeInt(10);
        data.writeInt(9);
        try {
            mRemote.transact(code, data, reply, 0);
            int i = reply.readInt();
            Log.d("google.sang", "add: " + i);
            reply.recycle();
            data.recycle();
        } catch (RemoteException e) {
            e.printStackTrace();
        }

第10行,在客戶端調用Binder驅動中的transact方法進行消息發送,傳遞的四個參數就是咱們在第一小節中所說的四個參數,這裏再也不贅述。第6行代碼其實是一個驗證字符串,對應了第一小節中的data.enforceInterface("MyAddBinder");行代碼。OK,就這樣寫了以後,在不使用AIDL工具的狀況下,咱們依然實現了跨進程通訊。


OK,通過上文的講解相信小夥伴們對Binder的工做機制已經有了一個大體的瞭解。線程


以上。
code



代碼下載http://download.csdn.net/detail/u012702547/9646948

相關文章
相關標籤/搜索