当然这两个方法中的 _data 和 _reply 不仅传递了对象,还传递了一些校验信息,这个我们可以不必深究,但应注意的是,Parcel 打包顺序和解包顺序要严格对应。例如,第一个打包的是 int:i,那么第一解包的也应该是这个整型值。也即打包时第一次调用的如果是 Parcel.writeInt(int),解包时第一次调用的应该是 Parcel.readInt()。
到此,客户端的 Proxy 讲解完了,下面我们看看服务端的 Stub。
Stub 中实现了 IBookManager 的其中一个方法,这个很简单,就是简单的将自身返回,因为 Stub 本身就继承自 Binder,而 Binder 继承自 IBinder,所以没有任何问题。你会问:还有两个方法没实现呢?这两个方法就是我们定义的接口方法,它们留给服务端进程去实现,也就是说,到时候我们在服务端进程中需要定义一个 Stub 的实现者。下面对 Stub 中的两个重要方法进行分析:
IBookManager asInterface(IBinder obj)
public static net.bingyan.library.IBookManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof net.bingyan.library.IBookManager))) { return ((net.bingyan.library.IBookManager) iin); } return new net.bingyan.library.IBookManager.Stub.Proxy(obj); }
这个方法的作用是将 Stub 类转换成 IBookManager 这个接口,方法中有个判断:如果我们的服务端进程和客户端进程是同一进程,那么就直接将 Stub 类通过类型转换转成 IBookManager;如果不是同一进程,那么就���过代理类 Proxy 将 Stub 转换成 IBookManager。为什么这么做,我们知道如果服务端进程和客户端进程不是同一进程,那么它们的内存就不能共享,就不能通过一般的方式进行通信,但是我们如果自己去实现进程间通信方式,对于普通开发者来说成本太大,因此编译器帮我们生成了一个封装了了进程间通信的工具,也就是这个 Proxy,这个类对底层的进程通信机制进行了封装只同时暴露出接口方法,客户端只需要调用这两个方法实现进程间通信(其实就是方法的远程调用)而不需要了解其中的细节。
有了这个方法,我们在客户端可以借助其将一个 IBinder 类型的变量转换成我们定义的接口 IBookManager,它的使用场景我们会在后面的实例中进行讲解。
onTransact(int code, Parcel data, Parcel reply, int flags)
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_addBook: { data.enforceInterface(DESCRIPTOR); net.bingyan.library.Book _arg0; if ((0 != data.readInt())) { _arg0 = net.bingyan.library.Book.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addBook(_arg0); reply.writeNoException(); return true; /* */ } case TRANSACTION_getBookList: { data.enforceInterface(DESCRIPTOR); java.util.List<net.bingyan.library.Book> _result = this.getBookList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } } return super.onTransact(code, data, reply, flags); }
这个方法我们是不是也很熟悉呢?我们在 Proxy 中也看到一个类似得方法 transact(int, Parcel, Parcel, int),它们的参数一样,而且它们都是 Binder 中的方法,那么它们有什么联系呢?