Android — Activity與Service交互之Binder總結

最近在複習Android跨進程調用,整理了一下自己對Binder的一些理解,希望能對大家也有所幫助,如有錯誤歡迎指正~
爲了加深理解,希望看完後能自己操練驗證一下,要不真的很容易眼高手低哦
ps:不想細看,可以只看裏面的3張圖片即可~ ^_^

好了,迴歸主題,我們現在寫個AIDL文件:

#IController.aidl
// Declare any non-default types here with import statements
interface IController {
    void showMessage(String msg);
}

我們先來看一下默認生成文件的註釋:

意思是說:如果不是默認類型,需要進行相應的import,類似java導包一樣

那默認類型有哪些呢?
int、long、boolean、float、double、String、in/out/inout List
Parcelable的實現類、aidl接口類這個是需要進行import的


添加完AIDL文件後,我們編譯一下,然後找到IController.java類,這個類是系統幫我們把AIDL文件轉化爲一個Java類,便於我們進行使用,當然我們自己也可以寫~~
我們來看一下這個類的代碼:

public interface IController extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.example.yukai.test.IController {
        private static final java.lang.String DESCRIPTOR = "com.example.yukai.test.IController";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.example.yukai.test.IController interface,
         * generating a proxy if needed.
         */
        public static com.example.yukai.test.IController asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.yukai.test.IController))) {
                return ((com.example.yukai.test.IController) iin);
            }
            return new com.example.yukai.test.IController.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_showMessage: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    this.showMessage(_arg0);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.example.yukai.test.IController {
            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 showMessage(java.lang.String msg) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(msg);
                    mRemote.transact(Stub.TRANSACTION_showMessage, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        static final int TRANSACTION_showMessage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }

    public void showMessage(java.lang.String msg) throws android.os.RemoteException;
}

這是格式化之後的樣子,我對這個類做了一個初步的結構圖繪製如下:
aidl結構圖1
可以比較明顯的看到類的嵌套結構,一個接口類:IController,裏面包含了接口方法(即我們聲明的那個方法)和 一個Stub類:

爲屏蔽客戶調用遠程主機上的對象,必須提供某種方式來模擬本地對象,這種本地對象稱爲存根(stub),存根負責接收本地方法調用,並將它們委派給各自的具體實現對象

我覺得上面這個解釋還可以,基本表達了Stub的作用~


看完上面的圖,覺得還是有點亂,既然是static class 靜態內部類,那其實我們可以把裏面的class抽離出來,作爲一個新的文件,參考下圖結構:
2
其中IController、Stub、Proxy類可以看成三個獨立的類/接口
繼承關係圖也可以很清晰的看出來,那這三者是如何相互合作使用的呢?下面這個圖可以很好的表達出具體的Activity與本地/遠程Service交互邏輯和對應上面幾個類的使用:
3

圖注:
左面的Service是跟Activity處於同一個進程下的
右面的Service是跟Activity非同一個進程下的,可能是remote或其他
“所以測試的時候需要分別測這兩種情況,有process:remote和什麼都不寫默認進程的。”

1.與當前進程的Service交互

在bind Service後,onServiceConnected會返回對應的binder對象,我們可以調試發現這個對象跟Service裏面的binder對象其實是 同一個對象,因此我們可以直接轉成我們Service的Binder,然後直接調用;當然如果用的是AIDL的方式,我們可以調用Stub的靜態方法:asInterface,可以做相應的轉化。
說到這裏,我們還需要看一下這個asInterface方法實現,先只看一半:

public static com.test.IController asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof com.test.IController))) {
        return ((com.test.IController) iin);
    }
    --------other return-------
}

關鍵在這裏:
queryLocalInterface,查看源碼可以發現,裏面判斷的是參數的IBinder對象的描述符是否是DESCRIPTOR,如果是,就會返回IController這個owner對象,所以就可以進行相應的強轉並返回。
那remote返回什麼呢?那看一下第二條吧~

2.與remote進程的Service交互

我們來看一下上面省略的那行代碼:

return new com.test.IController.Stub.Proxy(obj);

看到這裏原來返回的是個Proxy對象,那個obj會是什麼呢?通過調試發現類名是BinderProxy對象,這個類我們的SDK裏看不到,但是我們能在源碼裏找到,發現這個類是也是繼承IBinder類,這個類負責與底層binder進行傳遞數據,然後會調用遠程的Stub.onTransact,進行真實的Service方法調用。參照圖片可以更好的理解一下~

3. 對應的Service與Activity進行交互

我們可以通過RemoteCallbackList這個類進行相關注冊並進行回調,這個實現起來像是Activity是服務端,Service是客戶端,大家可以實現一下看看~ 發現Stub是在Activity裏新建並傳遞給Service端,由Service進行相應回調。當然還可以通過其他方式,比如廣播(LocalBroadcast)也是可以的~~

就先寫到這,如果有不對的地方,歡迎指正,多謝~~


原文地址:http://blog.csdn.net/yk3372/article/details/53295704

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章