安卓開發(fā) Binder連接池

綜述

????安卓IPC(進程間通信)可以利用AIDL(Android Interface definition language)來實現(xiàn),通過Service返回一個IBinder來實現(xiàn)進程間通信。但是隨著我們項目需求的增加,我們總不能每個模塊都開啟一個service吧?那么有沒有一種方案可以讓一個service同時管理我們所有的IPC業(yè)務(wù)呢?
????答案當(dāng)然是肯定的,《Android開發(fā)藝術(shù)探索》給出了一個Binder連接池的概念,我們都知道利用AIDL進行進程間通信原理其實是Service端為我們創(chuàng)建了一個Binder,并把這個Binder的實例返回給客戶端,我們就可以用這個Binder跟service層通信了。我們只需要讓service返回不同的Binder就可以實現(xiàn)連接池的功能。

實現(xiàn)

我們先定義一個IBinderPool實現(xiàn)連接池的AIDL:

// IBinderPool.aidl
package com.liujiakuo.learnmvp;

interface IBinderPool {

    IBinder getBinder(int binderCode);

}

這個AIDL定義了一個接口方法,它通過傳入的BinderCode來獲取一個IBinder。
接下來我們定義兩個不同的AIDL來實現(xiàn)不同的功能,定義一個ISum.aidl來實現(xiàn)求和的功能,一個IMax.aidl實現(xiàn)求最大值的功能。

// ISum.aidl
package com.liujiakuo.learnmvp;

interface ISum {

    int sum(int a,int b);
}
// IMax.aidl
package com.liujiakuo.learnmvp;

interface IMax {

    int max(in int[] values);
}

我們實現(xiàn)上面兩個接口:

public class SumImpl extends ISum.Stub {

    @Override
    public int sum(int a, int b) throws RemoteException {
        return a+b;
    }
}
public class MaxImpl extends IMax.Stub {
    @Override
    public int max(int[] values) throws RemoteException {
        int max = Integer.MIN_VALUE;
        for (int v :values) {
            if(v>max)
                max=v;
        }
        return max;
    }
}

Service的寫法:BinderPoolService.java

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

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

    class BinderPoolImpl extends IBinderPool.Stub {
        @Override
        public IBinder getBinder(int binderCode) {
            IBinder binder = null;
            switch (binderCode) {
                case BinderPoolUtils.BINDER_MAX:
                    Log.d("TAG", "getBinder: "+BinderPoolUtils.BINDER_MAX);
                    binder = new MaxImpl();
                    break;
                case BinderPoolUtils.BINDER_SUM:
                    Log.d("TAG", "getBinder: "+BinderPoolUtils.BINDER_SUM);
                    binder = new SumImpl();
                    break;
            }
            return binder;
        }
    }
}

我們來寫一個工具類來為我們綁定Service并拿到我們想要的Binder。

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import java.util.concurrent.CountDownLatch;

public class BinderPoolUtils {
    public static final int BINDER_SUM = 1;
    public static final int BINDER_MAX = 2;

    private static BinderPoolUtils poolUtils;
    private Context context;
    private CountDownLatch countDownLatch;
    private IBinderPool mBinderPool;


    private BinderPoolUtils(Context context) {
        this.context = context;
        bindServicePool();
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBinderPool = IBinderPool.Stub.asInterface(service);
            try {
                mBinderPool.asBinder().linkToDeath(deathRecipient, 0);//監(jiān)聽Binder的存貨狀態(tài)
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            countDownLatch.countDown();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {}
    };
    private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {//Binder死掉之后重新綁定
            mBinderPool.asBinder().unlinkToDeath(deathRecipient, 0);//重置死亡狀態(tài)
            mBinderPool = null;
            bindServicePool();//重新連接
        }
    };

    private void bindServicePool() {
        countDownLatch = new CountDownLatch(1);//同步
        Intent intent = new Intent(context, BinderPoolService.class);
        context.bindService(intent, connection, Context.BIND_AUTO_CREATE);
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static BinderPoolUtils getInstance(Context context) {
        if (poolUtils == null) {
            synchronized (BinderPoolUtils.class) {
                if (poolUtils == null) {
                    poolUtils = new BinderPoolUtils(context);
                }
            }
        }
        return poolUtils;
    }

    public IBinder getBinder(int binderCode) {
        IBinder binder = null;
        try {
            binder = mBinderPool.getBinder(binderCode);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return binder;
    }
}

代碼很簡單,就是實現(xiàn)了一個單例模式的工具類,bindServicePool負(fù)責(zé)綁定service,countDownLatch負(fù)責(zé)阻塞線程,因為bindService()是異步的,onServiceConnected方法不會馬上回調(diào),這樣我們?nèi)绻诨卣{(diào)之前執(zhí)行g(shù)etBinder會有空指針問題,所以利用CountDownLatch在綁定時阻塞,在onServiceConnected回調(diào)拿到Binder之后釋放。但是這里要注意的是在activity里面調(diào)用的時候要考慮線程阻塞的問題。

用法

我是在MainActivity的onCreate里面這樣寫的:

new Thread(new Runnable() {
            @Override
            public void run() {
                BinderPoolUtils pool = BinderPoolUtils.getInstance(MainActivity.this);
                //try {
                    //IMax maxBinder = IMax.Stub.asInterface(pool.getBinder(BinderPoolUtils.BINDER_MAX));
                    //ISum sumBinder = ISum.Stub.asInterface(pool.getBinder(BinderPoolUtils.BINDER_SUM));
                    //Log.d("TAG", "max: "+maxBinder.max(new int[]{1,2,3,-1}));
                    //Log.d("TAG", "sum: "+sumBinder.sum(1,7));
               //} catch (Exception e) {
                    //e.printStackTrace();
                //}
            }
        }).start();

為了不阻塞UI線程,我開啟一個新的線程去執(zhí)行。注釋部分是獲取相應(yīng)的Binder,這部分可能要跟控件的事件綁定,當(dāng)getInstance執(zhí)行完之后,IBinderPool實例就拿到了,這時候可以利用handler通知主線程綁定點擊事件,要不然會出現(xiàn)上面提到的空指針。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、IPC簡介 (1)IPC是Inter-Process Communication的縮寫,含義為進程間通信或者跨...
    遙遙的遠方閱讀 7,332評論 0 3
  • 本文介紹Service與Activity之間的通信,文章包含以下內(nèi)容: 一、Service基本用法 二、通過AID...
    developerzjy閱讀 11,035評論 7 27
  • 【Android Service】 Service 簡介(★★★) 很多情況下,一些與用戶很少需要產(chǎn)生交互的應(yīng)用程...
    Rtia閱讀 3,237評論 1 21
  • 若人生是一場旅行,那么無論繁華與落寂,都是過眼煙云,留下的是看風(fēng)景的心情,有時候,讓我們念念不忘的,也僅僅只是路過...
    bj淺笑安然閱讀 549評論 0 1
  • 晚上在單位加班,獸醫(yī)盆友急急忙忙打過電話來,說邯鄲親戚家吃涮羊肉中毒,老公加班回來發(fā)現(xiàn)老婆孩子頭暈嘔吐不止,立即拉...
    劉會芳閱讀 1,066評論 1 1

友情鏈接更多精彩內(nèi)容