android的Binder

來源:互聯網
上載者:User

標籤:

Binder:別針,回形針。生活中,我們用回形針將兩張紙“別”在一起。android中,Binder用於處理序間通訊,即將兩個進程“別”在一起。

 

Binder是一種架構,有3個模組(服務端介面,Binder驅動,客服端介面),如:

 

Binder服務端,實際上就是一個Binder類的對象,該對象一旦建立內部就會啟動一個隱藏線程。

 

根據上面的架構,說說我所理解的。

客服端程式要想訪問遠程服務,那麼它就需要擷取到服務端的Binder引用---mRemote。Android工程師提供了一個解決方案,那就是Service。對於客服端來講,可以使用兩種方式來和服務端建立串連。

public ComponentaName startService(Intent intent)public boolean bindService(Intent service, ServiceConnection conn, int flags)

第一種方式啟動後,客服端暫時沒有服務端Binder的引用。

而第二種方式啟動後,ServiceConnection介面的onServiceConnected方法會被回調。

ServiceConnection代碼如下:

public interface ServiceConnection {       public void onServiceConnected(ComponentName name, IBinder service);       public void onServiceDisconnected(ComponentName name);}

onServiceConnected方法中的IBinder對象service就是遠程服務的引用。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

我所理解的Binder機制到這裡就結束了,那麼AIDL的出現是為瞭解決什嗎?

編寫一個aidl檔案,看看它到底做了什麼。如下所示:

package com.aprz.aidl;interface IAidlTest{    void test();}

 

interface是關鍵字,有時在interface之前加上oneway表示service提供的方法都沒有傳回值,檔案名稱以“I”開頭是為了統一規範。檔案編寫完之後,android的開發環境會自動產生以下代碼:

/*___Generated_by_IDEA___*/ /* * This file is auto-generated.  DO NOT MODIFY. * Original file: F:\\workspace\\AIDLService\\src\\com\\aprz\\aidl\\AidlTest.aidl */package com.aprz.aidl; public interface AidlTest extends android.os.IInterface {    /**     * Local-side IPC implementation stub class.     */    public static abstract class Stub extends android.os.Binder implements com.aprz.aidl.AidlTest {        private static final java.lang.String DESCRIPTOR = "com.aprz.aidl.AidlTest";         /**         * Construct the stub at attach it to the interface.         */        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }        /**         * Cast an IBinder object into an com.aprz.aidl.AidlTest interface,         * generating a proxy if needed.         */        public static com.aprz.aidl.AidlTest asInterface(android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.aprz.aidl.AidlTest))) {                return ((com.aprz.aidl.AidlTest) iin);            }            return new com.aprz.aidl.AidlTest.Stub.Proxy(obj);        }         @Override        public android.os.IBinder asBinder() {            return this;        }        @Override        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {            switch (code) {                case INTERFACE_TRANSACTION: {                    reply.writeString(DESCRIPTOR);                    return true;                }                case TRANSACTION_test: {                    data.enforceInterface(DESCRIPTOR);                    this.test();                    reply.writeNoException();                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }         private static class Proxy implements com.aprz.aidl.AidlTest {            private android.os.IBinder mRemote;             Proxy(android.os.IBinder remote) {                mRemote = remote;            }            @Override            public android.os.IBinder asBinder() {                return mRemote;            }            public java.lang.String getInterfaceDescriptor() {                return DESCRIPTOR;            }            @Override            public void test() throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    mRemote.transact(Stub.TRANSACTION_test, _data, _reply, 0);                    _reply.readException();                } finally {                    _reply.recycle();                    _data.recycle();                }            }        }        static final int TRANSACTION_test = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);    }     public void test() throws android.os.RemoteException;}

 

這些程式碼完成了三個任務:

1、這個檔案本身是一個java interface,包含了aidl檔案所聲明的服務函數(檔案最下面)。

 

2、定義了一個Proxy類,該類作為客服端訪問服務端的代理,主要是為了統一包裹內寫入參數的順序(當我們在客服端使用Stub的asInterface將IBinder轉換為具體的介面以便調用服務端的方法時,其實返回的Proxy對象,代理做的主要工作就是統一包裹內寫入參數的順序)。

這裡需要詳情解釋一下這句話的意思。我們知道服務端是一個Binder對象,假設讓我們來設計一個Service端,這個Service只提供兩個方法:start(String filePath)和stop()。

那麼其代碼大致如下:

public class MusicPlayService extends Binder{       public void start(String filePath) {       }       public void stop(){    }    //服務端必須要實現onTransact()方法    @override    protected boolean onTransact(int code, Parcel data, Pacel reply, int flags) throws RemoteException {         return super.onTransact(code, data, reply, flags);    }}

 

onTransact的第二個參數data,就是客服端傳遞過來的參數,那麼我如何正確讀取這個參數呢(假設這裡有多個參數)?

正確的讀取方式應該是這樣的:

data.enforceInterface(“MusicPlayService”);String filePath = data.readString();start(filePath);

enforceInterface()是為了某種校正,與客服端的writeInterfaceToken()方法對應。由於我寫的aidl檔案並沒有帶參數,從它產生的程式碼中也無法看出什麼,你可以自己做測試,給aidl的檔案的方法加上多個參數,看看產生的程式碼中Stub和Proxy類的方法,對比一下。

 

3、定義一個Stub類,主要由服務端來使用。這個類之所以是抽象類別,是因為具體的函數服務必須由程式員來實現,如下:

public class AIDLService extends Service {    @Override    public IBinder onBind(Intent intent) {        return mBinder;    }    private final AidlTest.Stub mBinder = new AidlTest.Stub() {        public void test() throws RemoteException {            Log.e("aidl", "輸出從服務端");        }    };}

 

我們需要返回一個IBinder對象,這個mBinder對象是Stub的一個執行個體對象,需要實現其抽象方法,Binder與IBinder的關係:public class Binder implements IBinder 。

另外,Stub中的一些常量,如TRANSACTION_test,這些常量與服務函數相對應,因為服務端收到調用訊息之後,就會執行onTransact()方法,這個時候,就根據這個常量來判斷,該執行哪個方法(TRANSACTION_test表示需要執行服務端的test方法)。Stub中還有一個asInterface函數,該方法返回一個Binder對象,需要注意的是,如果是從遠程來擷取服務端的Binder引用,會返回Binder驅動中的對象,如果是從服務端進程內部擷取,則會返回服務端本身的Binder對象(當建立一個Binder對象的時候,服務端會建立一個,Binder驅動也會建立一個)。

android的Binder

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.