Android(2)进程通信之连接池

本文介绍了一种在Android中利用BinderPool实现跨进程通信的方法。通过创建BinderPool,可以集中管理多个服务,并通过统一接口获取指定的服务Binder。文章详细解释了BinderPool的设计思路及其实现步骤。

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

绪论

在Android(1)中介绍了基本概念,现在正是开始进程通信实质内容。
将后台服务单独放到一个进程中,如果一个Service对应一个Binder显然会使代码臃肿,同时打开进程面板发现多个后台服务都在运行。为了防止多个Servcie出现,设置不同Binder放在同一个Service,暴露一个BinderPool(其本身也是一个Binder)接口用于获取Service的特定Binder。
实现:多个ADIL业务实现,一个ADIL用于获取Binder(此即为连接池),重写queryBinder()方法通过case语句生成特定的Binder,在Service的onBind()方法中返回该连接池Binder即可。

1.新建AIDL

Itest1.aidl
代表多种业务处理

 interface ITest1 {
    void getName();
}

Itest.aidl
代表多种业务处理

interface ITest2 {
   void getName();
}

IBinderPool.aidl
Service真正返回的Binder


interface IBinderPool {
    IBinder queryBinder(int binderCode);
}

2.对AIDL进行实例化

Test1Impl.class

public class Test1Impl extends ITest1.Stub {
    @Override
    public void getName() throws RemoteException {
        Log.d("AIDL", "Test1"+Thread.currentThread().getName());
    }
}

Test2Impl.class

public class Test2Impl extends ITest2.Stub
{
    @Override
    public void getName() throws RemoteException {
        Log.d("AIDL", "Test2"+Thread.currentThread().getName());
    }
}

BinderPoolImpl.class


public class BinderPoolImpl extends IBinderPool.Stub{

    public BinderPoolImpl() {
        super();
    }

    @Override
    public IBinder queryBinder(int binderCode) throws RemoteException {
        IBinder iBinder=null;
        switch (binderCode)
        {
            case BinderPool.BINDER_ITEST1:
                {
                    iBinder=new Test1Impl();
                    break;
                }
            case BinderPool.BINDER_ITEST2:
                {
                    iBinder=new Test2Impl();
                    break;
                }
        }
        return iBinder;
    }
}

3.在Service中返回带有连接池接口的Binder

别忘了在xml中声明此Service

public class MyService extends Service {
    public MyService() {
    }

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

4.创建连接池对象

调用接口方法返回特定Binder则有可能BinderPoolImpl还未初始化会报错,这时就要用到java的同步变量强制当前线程阻塞,止到bindService成功返回BinderPoolImpl。

  • CountDownLatch:变量:通过CountDownLatch.await()方法和CountDownLatch.countDown()强制将将线程从异步执行变为同步执行,await()方法会判断当前count是否为0,若为0则执行,否则阻塞,如果该方法放在Android UI Thread会导致白屏等,所有线程同步一定要放在子线程中 。
  • volatile:关键字:确保变量每次加载的都是最新的值。
  • synchronized:关键字:用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。

此时BinderPool使用单例模式成员如下:

    public static final int BINDER_ITEST1=0;
    public static final int BINDER_ITEST2=1;

    private Context context;
    private IBinderPool iBinderPool;//用于接受服务器端返回的Binder
    private volatile static BinderPool binderPool;
    private CountDownLatch countDownLatch;//同步辅助类      

当调用bindSevice是使用ServiceConnection

private ServiceConnection serviceConnection= new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            iBinderPool=IBinderPool.Stub.asInterface(service);
            try
            {
                iBinderPool.asBinder().linkToDeath(deathRecipient, 0);
            }catch (RemoteException e)
            {
                e.printStackTrace();
            }
            countDownLatch.countDown();

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

绑定服务的的方法,在单例被初始化的时候调用一次

 private synchronized void connectBinderPoolService()
    {
        countDownLatch=new CountDownLatch(1);
        Intent services =new Intent(context,MyService.class);
        context.bindService(services, serviceConnection, Context.BIND_AUTO_CREATE);

        try {
            countDownLatch.await();
        }catch (InterruptedException e){
            e.printStackTrace();
        }

    }

当服务异常终止时提供回复

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

最后就是获取特定Binder服务的方法

    public IBinder getServiceBinder(int binderCode)
    {
        IBinder iBinder=null;

        try
        {
            if (iBinderPool!=null)
            {
                iBinder=iBinderPool.queryBinder(binderCode);
            }
        }catch (RemoteException e)
        {
            e.printStackTrace();
        }
        return iBinder;
    }

至此,BinderPool构建完毕。


5.在Activity中使用该连接池

这时必须要开启子线程,否则在bindSerivce的时候阻塞的就是UI线程(主线程)这样会导致白屏。


 new Thread()
        {
            @Override
            public void run() {
                BinderPool binderPool=BinderPool.getInstance(MainActivity.this);

                ITest1 test1=(ITest1)Test1Impl.
                        asInterface(binderPool.getServiceBinder(BinderPool.BINDER_ITEST1));
                ITest2 test2=(ITest2)Test2Impl.
                        asInterface(binderPool.getServiceBinder(BinderPool.BINDER_ITEST2));

                try {
                    test1.getName();
                    test2.getName();
                }catch (RemoteException e)
                {
                    e.printStackTrace();
                }

            }
        }.start();

运行结果如下:
在主进程中:

03-15 02:29:26.193 8428-8428/com.example.a29149.adilbinder D/AIDL: main

在另一个进程中;mytest:

03-15 02:29:27.320 8472-8486/com.example.a29149.adilbinder:mytest D/AIDL: Test1Binder_2
03-15 02:29:27.320 8472-8488/com.example.a29149.adilbinder:mytest D/AIDL: Test2Binder_3

可以看到确实运行在不同进程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值