Android通過繼承Binder類實現多程式通訊

_小馬快跑_發表於2017-12-15

上一篇講到用AIDL實現程式間通訊,地址:Android程式間通訊之AIDL

AIDL的底層是通過Binder進行通訊的,通過追蹤.aidl編譯後自動生成的檔案我們知道,檔案中的Stub類用於服務端,Proxy類用於客戶端呼叫,那麼可否直接通過繼承Binder類實現多程式通訊呢?下面就來試一試。

本文例子中的原始碼地址:程式間通訊之Binder

效果圖:

binder.gif

服務端程式碼,BinderService.java:

首先繼承Binder 類,實現onTransact()供客戶端呼叫,同樣通過onBind()返回Binder例項:

private static final java.lang.String DESCRIPTOR = "org.ninetripods.mq.multiprocess_sever.IAidlCallBack";
private static final int KEY_FLAG = 0x110;

private class MyBinder extends Binder {
        /**
         * @param code  唯一標識,客戶端傳遞標識執行服務端程式碼
         * @param data  客戶端傳遞過來的引數
         * @param reply 伺服器返回回去的值
         * @param flags 是否有返回值 0:有 1:沒有
         * @return
         * @throws RemoteException 異常
         */
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch (code) {
                case KEY_FLAG:
                    //標識伺服器名稱
                    data.enforceInterface(DESCRIPTOR);
                    Apple apple = new Apple("紅星蘋果", 15f, getString(R.string.response_binder_info));
                    reply.writeNoException();
                    reply.writeInt(1);
                    apple.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    return true;
            }

            return super.onTransact(code, data, reply, flags);
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }
複製程式碼

在AndroidManifest.xml中宣告一下:

 <service
    android:name=".BinderService"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.mq.binder.service" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</service>
複製程式碼

客戶端程式碼:BinderActivity.java:

首先編寫ServiceConnection 類來獲得Binder例項,來傳送和接收資料:

private ServiceConnection binderConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            isBound = true;
            mService = service;
            if (mService != null) {
                //宣告兩個Parcel型別資料(_data和_reply) 一個用於傳輸資料 一個用於接收資料
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                Apple apple;
                try {
                    //與伺服器端的enforceInterface(DESCRIPTOR)對應
                    _data.writeInterfaceToken(DESCRIPTOR);
                    //呼叫服務端的transact()傳輸資料
                    mService.transact(KEY_FLAG, _data, _reply, 0);
                    _reply.readException();
                    if (0 != _reply.readInt()) {
                        //接收服務端響應資料
                        apple = Apple.CREATOR.createFromParcel(_reply);
                    } else {
                        apple = null;
                    }
                    showMessage(apple != null ? ("\n" + apple.getNoticeInfo() + "\n名稱:"
                            + apple.getName() + "\n價格:" + apple.getPrice() + " 元") : "未獲得伺服器資訊", R.color.red_f);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    _data.recycle();
                    _reply.recycle();
                }
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isBound = false;
            mService = null;
        }
    };
複製程式碼

然後就是繫結服務了:

 Intent intent = new Intent();
 intent.setAction("android.mq.binder.service");
 intent.setPackage("org.ninetripods.mq.multiprocess_sever");
 bindService(intent, binderConnection, BIND_AUTO_CREATE);
複製程式碼

程式碼也挺簡單,裡面用到的Apple類已經實現了Pacelable介面序列化,程式間傳輸資料就是一個資料序列化和反序列化的過程~

最後貼一下原始碼地址:程式間通訊之Binder,如果對您有幫助,給個star吧,多謝~(注:專案中有兩個專案,請確保先啟動Server端,否則看不到效果)

相關文章