Binder连接池的原理及使用方法

       在这篇博客中将重点介绍一下Binder连接池的使用方法。

       首先,说明一下Binder连接池出现的原因以及使用目的。为什么会有Binder连接池这个概念,这需要从AIDL说起,正常来说,服务端新建一个AIDL接口后,都会同时创建一个Service,这个Service对象用于返回AIDL接口的底层调用对象Binder给客户端,试想一下,如果有10个不同的AIDL接口,那是不是要创建10个不同的Service,这肯定是不太合理的,为了避免这种情况的出现,就有了Binder连接池的概念。Binder连接池的最大目的就是减少Service的数量,实现只要通过一个Service就可以管理所有不同的AIDL。关于Binder连接池的更多介绍,可以参考一下《Android开发艺术探索》中关于Binder连接池的讲解。

       如何使用好Binder连接池,下面通过代码来介绍一下,我会分别创建服务端和客户端的代码,通过这个简单直接的demo,让读者能够直接抓住binder连接池的使用要领。

       服务端代码:

       对服务端来说,最重要的是提供一个能够返回相应Binder对象的queryBinder接口,这个接口可以根据不同的标志返回不同AIDL接口所对应的Binder对象。这个queryBinder接口是Binder连接池的精髓所在,客户端在绑定远程Service后,可以先通过不同的标志获取服务端中相应AIDL接口所对应的Binder对象,再通过这个Binder就可以获取到服务端的AIDL接口,进而使用服务端AIDL接口中的方法了。

       在服务端新建两个简单的AIDL接口,ICalculate提供加减运算,IStringAppend用于字符串的拼接。

interface ICalculate {
    int add(int a,int b);//加法
    int sub(int a,int b);//减法
}  
interface IStringAppend {
    String append(String str1,String str2);//字符串拼接
}

       为了能够返回上面两个接口对应的binder对象,服务端还需要新建一个AIDL接口提供根据不同标志返回相应binder对象的功能。

interface IBinderPool {
    IBinder queryBinder(int binderCode);
}

       下面创建两个类分别继承ICalculate接口和IStringAppend接口中的Stub类并实现Stub中的抽象方法:

public class CalculateImpl extends ICalculate.Stub {
    @Override
    public int add(int a, int b) throws RemoteException {
        return a+b;
    }

    @Override
    public int sub(int a, int b) throws RemoteException {
        return a-b;
    }
}
public class StringAppendImpl extends IStringAppend.Stub {
    @Override
    public String append(String str1, String str2) throws RemoteException {
        return str1+str2;
    }
}

        创建一个Service并在Service的onBind方法中返回相应的binder对象,这里可以根据业务需求进行约定,比如当标志为0时返回ICalculate接口对应的binder对象,当标志为1时返回IStringAppend对应的Binder对象:

public class BinderPoolService extends Service {

    private static final int BINDER_CALCULATE=0;
    private static final int BINDER_STRING_APPEND=1;

    private Binder binder= new IBinderPool.Stub() {
        @Override
        public IBinder queryBinder(int binderCode) throws RemoteException {
            IBinder iBinder=null;
            switch (binderCode){
                case BINDER_CALCULATE:
                    iBinder=new CalculateImpl();
                    break;
                case BINDER_STRING_APPEND:
                    iBinder=new StringAppendImpl();
                    break;
            }
            return iBinder;
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}
​

       不要忘了在AndroidManefest中service配置Service,这里说明一下,由于我的aidl文件所在包名为com.aidl.binderpool,故action为com.aidl.binderpool.IBinderPool,即包名+类名,其实只要客户端能够正确绑定到服务端Service就OK了。

<service android:name=".BinderPoolService">
     <intent-filter>
          <action android:name="com.aidl.binderpool.IBinderPool"/>
     </intent-filter>
</service>

       至此服务端的代码就结束了。

      服务端代码在AS中的目录如下:

       客户端代码:

       首先需要先将服务端中aidl包下所有的aidl文件连同目录拷贝至客户端代码,之后客户端做的工作就比较简单了,首先绑定服务端Service,然后通过Service返回的IBinder对象获取IBinderPool接口,通过queryBinder方法获取所需要的AIDL接口所对应的Binder对象,最后获取相应的AIDL接口并调用相应的方法即可,客户端的MianActivity如下:

public class MainActivity extends AppCompatActivity {

    private static final String TAG="BinderActivity";
    private static final int BINDER_CALCULATE=0;
    private static final int BINDER_STRING_APPEND=1;

    IBinderPool mBinderPool;
    ICalculate mCalculate;
    IStringAppend mStringAppend;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent=new Intent(IBinderPool.class.getName());
        bindService(intent,conn,BIND_AUTO_CREATE);
    }

    private ServiceConnection conn=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            mBinderPool=IBinderPool.Stub.asInterface(iBinder);
            try {
                IBinder calculateBinder=mBinderPool.queryBinder(BINDER_CALCULATE);
                mCalculate=ICalculate.Stub.asInterface(calculateBinder);
                Log.i(TAG,"1+2="+mCalculate.add(1,2));
                Log.i(TAG,"10-6="+mCalculate.sub(10,6));
                IBinder stringAppendBinder=mBinderPool.queryBinder(BINDER_STRING_APPEND);
                mStringAppend=IStringAppend.Stub.asInterface(stringAppendBinder);
                String result=mStringAppend.append("hello","world");
                Log.i(TAG,"\"hello\"与\"world\"拼接=="+result);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Intent intent=new Intent(IBinderPool.class.getName());
            bindService(intent,conn,BIND_AUTO_CREATE);
        }
    };

    @Override
    public void onDestroy(){
        unbindService(conn);
        super.onDestroy();
    }
}

       查看一下控制台输出,如下:

       客户端代码目录如下:

       项目Demo地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值