一、Bindr框架
Binder是一种架构,这种架构提供了服务器端口、Binder驱动、客户端接口三个模块。如下图:
客户端:客户端通过Ixxx.Stub.asInterface()来获得代理,同时将BinderProxy传给Proxy对象,其中BinderProxy即为要获得的mRemote。
Binder驱动:通过获得的mRemote引用,调用transact()方法,向远程服务发送消息,并挂起当前线程等待服务端处理,服务端处理完后,返回消息。
Binder服务端:当获得Binder驱动发送的消息,调用onTransact()来处理,将处理结果返回给Binder驱动。
从以上可以看出,客户端通过Binder驱动的中转,然后调用远程服务的Binder。即在整个过程中,存在两个Binder,一个是服务端的Binder,另一个是驱动中的Binder对象。
二、Service
1.客户端如何获得服务端的Binder对象
首先,当调用binderService(Intentservice,ServiceConnection conn,int flags),启动服务时,服务器端启动一个Binder对象,通过Service的onBinder()方法获得,最终会调用ServiceConnection的onServiceConnected(ComponentNamename,IBinder service),其中参数service是一个IBinder对象,其实的得到的是一个BinderProxy对象,当使用上述步骤时,最终能够在客户端的任何地方调用远程服务。
2.aidl
aidl文件的语法基本类似java,需要注意的是,只能写入以下三种类型
(1) java的原子类型,如int,long,String等
(2) Binder引用
(3) 实现了Parcelable的对象
aidl文件会自动生成一个java文件,该java文件主要完成三个任务。
(1) 定义一个Java interface,该类基于IInterface接口,提供函数asBinder().
(2) 定义一个Proxy类,该类将作为客户端访问服务端的代理。
(3) 定义一个Stub类,这是一个abstract类,基于Binder类,并且实现(1)中的接口,主要有服务端来使用。
三、一个远程调用的例子
场景:模拟WmS(IWindowManager,IWindowSession,IWindow),客户端通过IWindowManager获得远程连接,然后在客户端获得IWindowSession,客户端通过它调用远程服务,同时客户端将自身的IWindow对象通过IWindowSession传给服务端,然后服务端通过IWindow对象来回调客户端。
实现:三个aidl文件:IStockQuoteService.aidl,IHM.aidl,IClient.aidl,和上述场景对应。
IStockQuoteService.aidl
package com.hm.service;
import com.hm.service.IHM;
import com.hm.service.IClient;
interface IStockQuoteService
{
double getQuote(String ticker);
IHM getIHM();
void setClient(IClient client);
}
IHM.aidl
package com.hm.service;
import com.hm.service.IClient;
interface IHM {
String getName();
void setClient(IClient client);
}
IClient.aidl
package com.fx.hm.service;
interface IClient
{
String getClassName();
}
在服务端实现IStockQuoteService: StockQuoteServiceImpl
public class StockQuoteServiceImpl extends IStockQuoteService.Stub
{
IClient mClient;
public double getQuote(String ticker) throws RemoteException {
Log.e(TAG,"getQuote() called for "+ticker);
return 20;
}
public IHM getIHM() throws RemoteException {
return new HM(this);
}
public void setClient(IClient client) throws RemoteException {
// TODO Auto-generated method stub
mClient = client;
Log.e("service", mClient.getClassName());
}
}
在服务端实现IHM:HM
import android.os.RemoteException;
import com.hm.service.IClient;
import com.hm.service.IHM;
public class HM extends IHM.Stub
{
IStockQuoteService mService;
HM(IStockQuoteService service)
{
mService = service;
}
public String getName() throws RemoteException {
return mService.toString();
}
public void setClient(IClient client) throws RemoteException {
mService.setClient(client);
}
}
在客户端实现IClient:
private IClient mClient = new IClient.Stub() {
public String getClassName() throws RemoteException {
return MainActivity.this.toString();
}
};
调用过程:
首先调用binderService(intent,conn,flags),
在ServiceConnection的onServiceConnected(name,service)方法中获得代理:
IStockQuoteServicemService = IStockQuoteService.Stub.asInterface(service);
IHM ihm =mService.getHM();
ihm.setClinet(mClient);