• 使用BinderPool管理AIDL


    个人博客:
    http://www.milovetingting.cn

    使用BinderPool管理AIDL

    前言

    平时我们用到AIDL,一般的流程可能是这样:

    • 定义AIDL接口

    • 定义服务,在onBind方法中返回实现了AIDL接口的Stub类的实例

    • 调用bindService方法,在ServiceConnectiononServiceConnected回调中获取到Binder对象

    • 通过Binder对象调用接口中的方法

    如果我们只是用到比较少的AIDL调用,那么上面的方法的确是可行的,但是,如果需要调用数量较多的AIDL,那么可以通过先访问一个BinderPool,然后再由BinderPool来查询相关的Binder服务,再将Binder服务返回。通过这种统一管理的方式,可以方便地管理AIDL。

    下面详细介绍BinderPool具体的定义

    定义IBinderPool

    定义IBinderPoolqueryBinder方法返回IBinder对象

    interface IBinderPool {
        IBinder queryBinder(int queryCode);
    }
    

    定义BinderPool

    BinderPool定义为单例模式。通过getInstance获取到BinderPool的实例,并在构造方法中连接BinderPoolService

    private static class BinderPoolHolder {
            static final BinderPool INSTANCE = new BinderPool();
        }
    
    public static BinderPool getInstance(Context context) {
            mContext = context.getApplicationContext();
            return BinderPoolHolder.INSTANCE;
        }
    
    private BinderPool() {
            connectBinderPoolService();
        }
    
    private synchronized void connectBinderPoolService() {
            countDownLatch = new CountDownLatch(1);
            Intent intent = new Intent(mContext, BinderPoolService.class);
            mContext.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    

    BinderPoolService返回IBinderPool对象

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

    BinderPoolImpl实现IBinderPool接口方法,queryBinder根据queryCode返回对应的Binder

    static class BinderPoolImpl extends IBinderPool.Stub {
    
            @Override
            public IBinder queryBinder(int queryCode) throws RemoteException {
                IBinder binder = null;
                switch (queryCode) {
                    case QUERY_CODE_BINDER_A:
                        binder = new BinderA();
                        break;
                    case QUERY_CODE_BINDER_B:
                        binder = new BinderB();
                        break;
                    default:
                        break;
                }
                return binder;
            }
        }
    

    ServiceConnectiononServiceConnected返回Binder对象,并绑定DeathRecipient

    private ServiceConnection serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                binderPool = IBinderPool.Stub.asInterface(service);
                try {
                    binderPool.asBinder().linkToDeath(deathRecipient, 0);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    

    DeathRecipient

    private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
            @Override
            public void binderDied() {
                binderPool.asBinder().unlinkToDeath(deathRecipient, 0);
                binderPool = null;
                connectBinderPoolService();
            }
        };
    

    完整的BinderPool代码

    public class BinderPool {
    
        public static final int QUERY_CODE_BINDER_A = 1;
    
        public static final int QUERY_CODE_BINDER_B = 2;
    
        private static Context mContext;
    
        private CountDownLatch countDownLatch;
    
        private IBinderPool binderPool;
    
        public static BinderPool getInstance(Context context) {
            mContext = context.getApplicationContext();
            return BinderPoolHolder.INSTANCE;
        }
    
        private BinderPool() {
            connectBinderPoolService();
        }
    
        private synchronized void connectBinderPoolService() {
            countDownLatch = new CountDownLatch(1);
            Intent intent = new Intent(mContext, BinderPoolService.class);
            mContext.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public IBinder queryBinder(int queryCode) {
            IBinder binder = null;
            if (binderPool != null) {
                try {
                    binder = binderPool.queryBinder(queryCode);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            return binder;
        }
    
        private static class BinderPoolHolder {
            static final BinderPool INSTANCE = new BinderPool();
        }
    
        private ServiceConnection serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                binderPool = IBinderPool.Stub.asInterface(service);
                try {
                    binderPool.asBinder().linkToDeath(deathRecipient, 0);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    
        private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
            @Override
            public void binderDied() {
                binderPool.asBinder().unlinkToDeath(deathRecipient, 0);
                binderPool = null;
                connectBinderPoolService();
            }
        };
    
        static class BinderPoolImpl extends IBinderPool.Stub {
    
            @Override
            public IBinder queryBinder(int queryCode) throws RemoteException {
                IBinder binder = null;
                switch (queryCode) {
                    case QUERY_CODE_BINDER_A:
                        binder = new BinderA();
                        break;
                    case QUERY_CODE_BINDER_B:
                        binder = new BinderB();
                        break;
                    default:
                        break;
                }
                return binder;
            }
        }
    }
    

    定义IBinderA及实现类

    interface IBinderA {
        int calc(int a,int b);
    }
    
    public class BinderA extends IBinderA.Stub {
        @Override
        public int calc(int a, int b) throws RemoteException {
            return a + b;
        }
    }
    

    定义IBinderB及实现类

    interface IBinderB {
        String getInfo(String info);
    }
    
    public class BinderB extends IBinderB.Stub {
        @Override
        public String getInfo(String info) throws RemoteException {
            return info + "-handled";
        }
    }
    

    客户端调用BinderPool

    由于在连接BinderPoolService时,是通过调用CountDownLatch.await(),等待onServiceConnected的回调,因此如果直接在主线程调用BinderPool的方法,会导致主线程阻塞,发生ANR,因此需要放到子线程去处理。

    new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        IBinder binder = BinderPool.getInstance(getApplicationContext()).queryBinder(BinderPool.QUERY_CODE_BINDER_A);
                        final int calc = IBinderA.Stub.asInterface(binder).calc(1, 2);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(getApplicationContext(), "calc:" + calc, Toast.LENGTH_SHORT).show();
                            }
                        });
                        IBinder binderB = BinderPool.getInstance(getApplicationContext()).queryBinder(BinderPool.QUERY_CODE_BINDER_B);
                        final String info = IBinderB.Stub.asInterface(binderB).getInfo("hello");
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(getApplicationContext(), "info:" + info, Toast.LENGTH_SHORT).show();
                            }
                        });
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    

    总结

    通过定义BinderPool来管理所有的AIDL连接,当需要新增AIDL时,只需要增加对应的AIDL接口及对应的实现Binder,然后在BinderPool的queryBinder增加对应的queryCode处理即可。

  • 相关阅读:
    实战项目-网易
    iOS-Code-Snippet
    iOS父子控制器详解
    (Java) AES-128 数据加密
    (Java) byte[] 和 base64 字符串之间的转换
    关于 mybatis 报invalid comparison: java.util.Arrays$ArrayList and java.lang.String异常
    MUI 混合开发移动app应用开发 --- app版本升级
    MUI错误信息:系统已经存在较高版本,些安装包无法安装。
    找不到 cucumber.api.cli.Main 的报错解决方案
    Mysql 索引类型+索引方法
  • 原文地址:https://www.cnblogs.com/milovetingting/p/13203266.html
Copyright © 2020-2023  润新知