Binder线程池

3 篇文章 0 订阅
3 篇文章 0 订阅

上一篇水文介绍了IPC的几种方式,几乎都是一对一的方式。本节,再次探讨AIDL的使用,例如多个业务都需要使用AIDL时,我们不能对每个都写一个Service吧,10个也许能写,那100个呢?所以,换种思路。
前方高能,又是一篇“水”文,O(∩_∩)O哈哈~,主要是简单的Binder线程池用法和IPC各种方式的优缺点。
详细代码见Binder线程池

线程池机制

大致流程

每个业务模块创建自己的AIDL接口并实现此接口,这个时候不同业务模块之间不能有耦合,所有实现细节单独开来,然后向服务端提供自己的唯一标识和其对应的Binder对象;对于服务端而言,只需要一个Service就可以了,服务端提供一个queryBinder接口,这个接口能够根据业务模块的特征来返回相应的Binder对象给它们,不同的业务模块拿到所需的Binder对象后就可以进程远程方法调用了。由此可见,Binder线程池的主要作用就是将每个业务模块的Binder请求统一转发到远程Servie中去执行,从而避免了重复创建Service的过程,工作原理如图

Binder线程池工作原理.png

下面用代码模拟实现下。
我们创建两个AIDL接口(ISecurityCenter和ICompute)来模拟两个业务,多个时类似,增加对应接口即可。
ISecurityCenter.aidl

// ISecurityCenter.aidl
package com.breezehan.ipc.binderpool;

interface ISecurityCenter {
    String encrypt(String content);
    String decrypt(String password);
}

ICompute.aidl

// ICompute.aidl
package com.breezehan.ipc.binderpool;

interface ICompute {
    int add(int a,int b);
}

简单实现实现上述接口:

public class SecurityCenterImpl extends ISecurityCenter.Stub {
    private static final char SECRET_CODE = '^';

    @Override
    public String encrypt(String content) throws RemoteException {
        char[] chars = content.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            chars[i] ^= SECRET_CODE;
        }
        return new String(chars);
    }

    @Override
    public String decrypt(String password) throws RemoteException {
        return encrypt(password);
    }
}
public class ComputeImpl extends ICompute.Stub {
    @Override
    public int add(int a, int b) throws RemoteException {
        return a + b;
    }
}

业务模块都有了,我们要创建一个Binder连接池需要的AIDL,这里是一个代理或工厂,根据标识返回对应Binder

// IBinderPool.aidl
package com.breezehan.ipc.binderpool;

interface IBinderPool {
    IBinder queryBinder(int binderCode);
}

在连接池中实现,根据标识返回不同Binder

static class BinderPoolImpl extends IBinderPool.Stub {
    @Override
    public IBinder queryBinder(int binderCode) throws RemoteException {
        IBinder binder =null;
        switch (binderCode) {
            case BINDER_COMPUTE:
                binder = new ComputeImpl();
                break;
            case BINDER_SECURITY_CENTER:
                binder = new SecurityCenterImpl();
                break;
        }
        return binder;
    }
}

Service比较简单,逻辑处理都放在Binder线程池中

package com.breezehan.ipc.binderpool;

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

public class BinderPoolService extends Service {
    private static final String TAG = "BinderPoolService";
    private IBinder binderPool = new BinderPool.BinderPoolImpl();
    public BinderPoolService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");
        return binderPool;
    }

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

Binder线程池的具体实现,同时需处理Binder死亡代理问题。

public class BinderPool {
    private static final String TAG = "BinderPool";
    public static final int BINDER_NONE = -1;
    public static final int BINDER_COMPUTE = 0;
    public static final int BINDER_SECURITY_CENTER = 1;
    private static volatile BinderPool sInstance;//确保并发取值正确性
    private final Context mContext;
    //控制多个线程时,某一线程中代码执行顺序;是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行
    private CountDownLatch mConnectBinderPoolCountDownLatch;
    private IBinderPool mBinderPool;

    public BinderPool(Context context) {
        mContext = context.getApplicationContext();
        connectBinderPoolService();
    }

    private void connectBinderPoolService() {
        mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
        Intent service = new Intent(mContext, BinderPoolService.class);
        mContext.bindService(service, mServiceConnection, Context.BIND_AUTO_CREATE);
        try {
            mConnectBinderPoolCountDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

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


    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBinderPool = IBinderPool.Stub.asInterface(service);
            try {
                mBinderPool.asBinder().linkToDeath(mBinderDeathRecipient, 0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            mConnectBinderPoolCountDownLatch.countDown();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
    private IBinder.DeathRecipient mBinderDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            Log.w(TAG, "binderDied: ");
            mBinderPool.asBinder().unlinkToDeath(mBinderDeathRecipient, 0);
            mBinderPool = null;
            connectBinderPoolService();
        }
    };

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

    static class BinderPoolImpl extends IBinderPool.Stub {


        @Override
        public IBinder queryBinder(int binderCode) throws RemoteException {
            IBinder binder =null;
            switch (binderCode) {
                case BINDER_COMPUTE:
                    binder = new ComputeImpl();
                    break;
                case BINDER_SECURITY_CENTER:
                    binder = new SecurityCenterImpl();
                    break;
            }
            return binder;
        }
    }
}

Activity中模拟使用。此处我只使用了其中一个Binder。

public class BinderPoolActivity extends AppCompatActivity {

    private static final String TAG = "BinderPoolActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_binder_pool);
        new Thread(new Runnable() {
            @Override
            public void run() {
                doWork();
            }
        }).start();
    }

    private void doWork() {
        BinderPool binderPool = BinderPool.getInstance(BinderPoolActivity.this);
        IBinder securityBinder = binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER);
//        ISecurityCenter iSecurityCenter = ISecurityCenter.Stub.asInterface(securityBinder);
        ISecurityCenter iSecurityCenter = SecurityCenterImpl.asInterface(securityBinder);
        Log.d(TAG, "visit ISecurityCenter");
        String msg = "helloworld-安卓";
        try {
            String encrypt = iSecurityCenter.encrypt(msg);
            Log.d(TAG, "doWork,encrypt:"+encrypt);
            Log.d(TAG, "doWork,decrypt:"+iSecurityCenter.decrypt(encrypt));
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        IBinder computeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTE);
        ICompute iCompute = ComputeImpl.asInterface(computeBinder);
        try {
            Log.d(TAG, "doWork,compute: "+iCompute.add(1,2));
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

基本思想如上,改进或者多个Binder根本不变,添枝加叶即可。

选中合适的IPC方式

每种IPC方式都有优缺点和适用场景。

名称优点缺点适用场景
Bundle简单易用只能传输Bundle支持的数据类型四大组件间的进程间通信
文件共享简单易用不适合高并发场景,并且无法做到进程间的即时通信无并发访问情形,交换简单的数据,实时性不高的场景
AIDL功能强大,支持一对多并发通信,支持实时通信使用稍复杂,需要处理好线程同步一对多通信且有RPC需求
Messenger功能一般,支持一对多串行通信,支持实时通信不能很好处理高并发情形,不支持RPC,数据通过Message进行传输,因此只能传输Bundle支持的数据类型低并发的一对多即时通信,无RPC需求,或者无需要返回结果的RPC请求
ContentProvider在数据源访问方便功能强大,支持一对多并发数据共享,可通过Call方法扩展其他操作可以理解为受约束的AIDL,主要提供数据源的CRUD操作一对多的进程间的数据共享
Socket功能强大,可以通过网络传输字节流,支持一对多并发实时通信实现细节稍微有点儿繁琐,不支持直接的RPC网络数据交换
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值