绪论
在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
可以看到确实运行在不同进程。