Android知识点总结(五)进程间通信之Binder连接池

本文总结了Android进程间通信中的Binder连接池技术。在面对多个AIDL接口时,通过Binder连接池,可以在一个Service中返回不同业务模块的Binder对象,避免创建多个Service。详细介绍了如何创建AIDL接口、实现Stub类,以及Binder池的工作机制和具体实现。最后通过客户端验证了该技术的可行性,强调了在主线程中避免耗时操作的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android知识点总结(四)进程间通信
上一篇文章记录了Messenger及AIDL的使用。其中AIDL的使用是最广泛的,其大致流程:

  • 首先创建一个Service和一个AIDL接口
  • 接着创建一个类继承自AIDL接口中的Stub类并实现Stub中的抽象方法(也可以直接使用匿名内部类的方式实现),在Service的onBind方法中返回这个类的对象
  • 然后客户端就可以绑定服务端Service,建立连接后就可以访问远程服务端的方法了。

但是如果项目业务越来越大,需要10个AIDL来进行进程间通信时,创建10个Service显然不太现实,这时就需要Binder连接池技术,该模式工作机制是这样的:

  • 每个业务模块创建自己的AIDL接口
  • 同时提供一个Binder池接口,提供queryBinder,这个接口能根据业务需求,返回对应的Binder对象,这样不同业务模块就能根据自己的Binder进行远程调用
  • 此时只需一个Service,在其onBind方法里返回Binder池对应的Binder类,客户端就能获取不同的Binder实现所需功能。
    在这里插入图片描述
    下面写一个例子,首先建立两个AIDL接口,模拟多个业务模块的情况:
// ISecurityCenter.aidl
package com.scy.component.testlaunteractivity;

// Declare any non-default types here with import statements

interface ISecurityCenter {
   String encrypt(String content);
   String decrypt(String psd);
}
// ICompute.aidl
package com.scy.component.testlaunteractivity;

// Declare any non-default types here with import statements

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

接着创建类继承各自AIDL接口中的Stub类并实现Stub中的抽象方法:

public class SecurityCenterImpl extends ISecurityCenter.Stub{
    private static final char SECRET = '*';
    @Override
    public String encrypt(String content) throws RemoteException {
        char[] chars = content.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            chars[i] ^= SECRET;
        }
        return new String(chars);
    }

    @Override
    public String decrypt(String psd) throws RemoteException {
        return encrypt(psd);//两次异或算法达到解密效果
    }
}
public class IComputeImpl extends ICompute.Stub {
    @Override
    public int add(int a, int b) throws RemoteException {
        return a + b;
    }
}

接下来为Binder连接池创建AIDL接口,并创建类继承接口实现其Stub:

// IBinderPool.aidl
package com.scy.component.testlaunteractivity;

// Declare any non-default types here with import statements

interface IBinderPool {
   IBinder queryBinder(int code);
}

public class IBinderPoolImpl extends IBinderPool.Stub {
    @Override
    public IBinder queryBinder(int code) throws RemoteException {
        IBinder binder = null;
        switch (code){
            case 0:
                binder = new SecurityCenterImpl();
                break;
            case 1:
                binder = new IComputeImpl();
                break;
            default:break;
        }
        return binder;
    }
}

Service比较简单:

public class BinderPoolService extends Service {


    public BinderPoolService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new IBinderPoolImpl();
    }
}

下面是Binder连接池的具体实现,在它的内部实现要去绑定远程服务,绑定成功后,客户端就可以通过它的queryBinder方法,获取各自对应的Binder进行各自的操作了。

public class BinderPool {
    public static final int BINDER_COMPUTE = 1;
    public static final int BINDER_SECURITY = 0;
    public static final int BINDER_NONE = -1;
    private Context context;
    private IBinderPool mBinderPool;
    private static volatile BinderPool mInstance;
    private CountDownLatch mCountDownLatch;

    public BinderPool(Context context) {
        this.context = context.getApplicationContext();
        connectService();
    }

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

    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            mBinderPool.asBinder().unlinkToDeath(mDeathRecipient, 0);
            mBinderPool = null;
            connectService();
        }
    };
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBinderPool = IBinderPool.Stub.asInterface(service);
            try {
                mBinderPool.asBinder().linkToDeath(mDeathRecipient, 0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            //计时器的值减一 变为0 mCountDownLatch.await()造成的阻塞解除 一般放到finally语句执行
            mCountDownLatch.countDown();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

    private synchronized void connectService() {
        Log.e("--==", "connect.....");
        //限定闭锁需要等待的线程数量
        mCountDownLatch = new CountDownLatch(1);
        Intent intent = new Intent(context, BinderPoolService.class);
        context.bindService(intent, connection, Context.BIND_AUTO_CREATE);
        try {
            //阻塞当前线程,直到计时器的值为0
            mCountDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

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

最后可以去客户端验证一下:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    doWork();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }

    private void doWork() throws RemoteException {
        BinderPool binderPool = BinderPool.getInstance(this);
        IBinder securityBinder = binderPool.queryBinder(0);
        ISecurityCenter iSecurityCenter = SecurityCenterImpl.asInterface(securityBinder);
        String psd = iSecurityCenter.encrypt("我爱你中国");
        String decrypt = iSecurityCenter.decrypt(psd);
        Log.e("--==", psd + " -- " + decrypt);

        IBinder computeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTE);
        ICompute iCompute = IComputeImpl.asInterface(computeBinder);
        int num = iCompute.add(3, 5);
        Log.e("--==", "" + num);
    }
  }

输出日志如下:

04-11 14:33:22.207 13310-13335/com.scy.component.testlaunteractivity E/--==: connect.....
04-11 14:33:22.281 13310-13335/com.scy.component.testlaunteractivity E/--==: 戻爛佊万囗 -- 我爱你中国
04-11 14:33:22.283 13310-13335/com.scy.component.testlaunteractivity E/--==: 8

在Binder连接池的实现中,我们通过CountDownLatch将bindService这一异步操作同步化,这就意味着它是耗时的,然后就是Binder方法的调用也可能是耗时的,因此不建议在主线程中去执行。
如果业务模块需要新加一个AIDL,那么在它实现了自己的AIDL接口后,只需修改BinderPoolImpl中的queryBinder方法,添加一个新的binderCode并返回对应的Binder对象即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值