Binder是一套基于CS的架构。下面以一个极简的例子来学习Binder。
1.首先定义一个IMedia.aidl文件。
interface IMedia {
boolean start();
boolean stop();
}
2.然后IDE会帮我们自动生成一个IMedia.java文件
public interface IMedia extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements com.cmeiyuan.pluginstudy.IMedia {
public android.os.IBinder asBinder(){
return this;
}
public static com.cmeiyuan.pluginstudy.IMedia asInterface(android.os.IBinder obj) {
...
}
public boolean onTransact(...){
...
start();
...
}
private static class Proxy implements com.cmeiyuan.pluginstudy.IMedia {
...
}
}
}
public boolean start() throws android.os.RemoteException;
}
IMedia是一个继承于android.os.IInterface的接口,它的内部类Stub实现了android.os.IInterface的asBinder()方法,直接返回了Sub类实例。我们继续看Sub类的asInterface()方法
public static com.cmeiyuan.pluginstudy.IMedia asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.cmeiyuan.pluginstudy.IMedia))) {
return ((com.cmeiyuan.pluginstudy.IMedia) iin);
}
return new com.cmeiyuan.pluginstudy.IMedia.Stub.Proxy(obj);
}
这个方法的作用是将远程Binder对象转换为方便使用的IMedia接口对象,这个远程Binder对象是我们bindService()时返回的。首选通过obj.queryLocalInterface(DESCRIPTOR)查询是否有本地接口对象,这种情况是当Server端和Client端处于同一进程,没有必要进行多进程通信。如果没有本地接口对象,那么直接new一个Stub.Proxy(obj)实例返回。我们来看一下这个Proxy类的具体实现
private static class Proxy implements com.cmeiyuan.pluginstudy.IMedia {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public boolean start() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
boolean _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_start, _data, _reply, 0);
_reply.readException();
_result = (0 != _reply.readInt());
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
这个Proxy类是Stub类的内部类,其实就是对obj的一层封装(代理),那么我们通过这个代理类,就很容易和Server端进行通信了。具体实现也很简单,就是调用远程Binder对象mRemote的transact()方法,将数据发送给Server端。
Stub是一个抽象类,继承于Binder类,实现了父类的onTransact()方法,onTransact()方法的作用是执行Server端的操作,并将操作的结果返回给Client端。一般情况,我们需要写一个子类继承于Stub类,然后实现IMedia的接口方法,这些方法会被父类onTransact()方法调用到。
3.总结一下多进程通信过程:
(1)通过bindService()得到远程Binder对象obj
(2)通过IMedia.Stub.asInterface(obj)得到一个远程代理类Sub.Proxy对象mediaRemoteProxy
(3)调用mediaRemoteProxy.start()方法,事实上是调用了其内部远程Binder对象mRemote的transact()方法,将数据发送给Server端
(4)服务端收到Client端发送过来的数据时onTransact()会被调用,有一个子类继承于IMedia.Stub类,实现了start()方法,onTransact()被调用时,自然调用到了子类里的start()方法。换言之,Server端的操作被Client调用执行了。
4.start()方法是在哪个线程被执行的
private IMedia.Stub stub = new IMedia.Stub() {
@Override
public boolean start() throws RemoteException {
Log.d("cmy", "media start:" + Thread.currentThread().getId());
return true;
}
};
通过调试程序发现start()方法被执行在名为binder1或binder2的线程中,而不是主线程。这也解释了系统的ActivityManagerService向应用进程发送消息时,需要使用H类把消息转发到UI线程,而且也必须这么做,因为UI线程调用了Looper.loop()开启了循环,线程是被阻塞的。












网友评论