Android進階筆記:AIDL內部實現詳解 (二)

來源:互聯網
上載者:User

標籤:protect   parcel   connected   targe   先來   content   nec   method   return   

接著上一篇分析的aidl的流程解析。知道了aidl主要就是利用Ibinder來實現跨進程通訊的。既然是通過對Binder各種方法的封裝,那也可以不使用aidl自己通過Binder來實現跨進程通訊。那麼這篇部落格就主要就寫一下通過上篇(Android進階筆記:AIDL詳解(一))總結的知識來自己實現跨進程通訊從而更加透徹的瞭解aidl的核心邏輯。

首先上一篇部落格(Android進階筆記:AIDL詳解(一))中總結出一個結論————“onTransact方法是提供給server端用的,transact方法(內部類proxy封裝了transact方法)和asInterface方法是給client端用的。”因此很清楚,只要我們在Server端實現跨進程需要調用的方法(類似aidl的介面實現)和onTransact方法,而服務端只要通過獲得的IBinder對象來調用transact方法就可以代替aidl來實現跨進程通訊了。既然思路已經整理清楚了,那就一步一步來實現它。

Server端

首先Server端是要通過Service的onBind方法來給Client端一個Binder對象,那就先從這個Binder對象入手。那就先來建立了一個MyBinder類,代碼如下:

MyBinder.java

public class MyBinder extends Binder {    //標記方法的    private static final int METHOD_ADD_CODE = 1001;    //標識binder對象的    private static final String DESCRIPTION = "not use aidl";    @Override    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {        if (code == METHOD_ADD_CODE) {            //驗證一下binder            data.enforceInterface(DESCRIPTION);            //從parcel對象中讀取參數            int arg0 = data.readInt();            int arg1 = data.readInt();            //寫入結果            reply.writeInt(add(arg0, arg1));            return true;        }        return super.onTransact(code, data, reply, flags);    }    private int add(int arg0, int arg1) {        return arg0 + arg1;    }}

代碼非常簡單,只是重新寫了一下onTransact方法。其實一共只有4步:

  1. 根據code的值來判斷client端具體想要調用哪個方法;
  2. 讀取parcel對象(data)中傳入的參數;
  3. 調用自己本地的方法(add)並將參數傳入;
  4. 把結果寫入parcel對象(reply)中;

接著只要把這個自己定義的MyBinder類的執行個體通過Service.onBInder方法返回給Client端就可以了。

MyService.java

public class MyService extends Service {    private MyBinder myBinder;    public MyService() {    }    @Override    public void onCreate() {        super.onCreate();        //建立執行個體        myBinder = new MyBinder();    }    @Override    public IBinder onBind(Intent intent) {        //返回自訂的binder對象        return myBinder;    }}

Client端

client端的代碼無非就是把之前寫在aidl中的proxy內部類的方法拿出來了。具體看代碼:

WithoutAidlActivity.java

public class WithoutAidlActivity extends AppCompatActivity {    private ServiceConnection serviceConnection;    private IBinder binder;    //以下兩個參數要和server端保持一致    //標記方法的(告知server端調用哪個方法)    private static final int METHOD_ADD_CODE = 1001;    //標識binder對象的    private static final String DESCRIPTION = "not use aidl";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_without_aidl);        serviceConnection = new ServiceConnection() {            @Override            public void onServiceConnected(ComponentName name, IBinder service) {                Log.d("onServiceConnected", "onServiceConnected: connected success!");                binder = service;                //這裡就代替aidl中的proxy來直接調用transact方法                //先準備參數                Parcel data = Parcel.obtain();                Parcel reply = Parcel.obtain();                data.writeInterfaceToken(DESCRIPTION);                data.writeInt(123);                data.writeInt(456);                try {                    //調用transact方法                    binder.transact(METHOD_ADD_CODE, data, reply, 0);                    //獲得結果                    int result = reply.readInt();                    Log.d("onServiceConnected", "result = " + result);                } catch (RemoteException e) {                    e.printStackTrace();                } finally {                    data.recycle();                    reply.recycle();                }            }            @Override            public void onServiceDisconnected(ComponentName name) {                binder = null;            }        };        bindService(new Intent("com.coder_f.aidlserver.MyService"), serviceConnection, BIND_AUTO_CREATE);    }    @Override    protected void onDestroy() {        super.onDestroy();        unbindService(serviceConnection);    }}

首先串連成功後在serviceConnection.onServiceConnected方法中獲得了IBinder執行個體,然後總共做了3個事情:

  1. 建立兩個parcel對象分別存放參數(data)和傳回值(reply)
  2. 調用transact方法,傳入data,reply,和你要調用的方法code。最後的flag傳入0表示有傳回值(1表示沒有又傳回值)
  3. 從reply中獲得結果

完成以上工作就可以不通過aidl實現跨進程通訊了。但是還是要說一下,這裡我們server端調用的只是一個簡單的add方法不耗時的,而transact方法則是在onServiceConnected方法中被調用的其實是在主線程中執行的。如果add方法換成一個耗時方法,那麼主線程(UI線程)是會卡死的,調用transact方法時當前線程會被掛起知道結果被返回(有興趣可以去試試,只要在add方法裡面加一個Thread.sleep就可以了)。所以最好的辦法就是起一個線程來調用transact方法。

Android進階筆記:AIDL內部實現詳解 (二)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.