Android 进程通信机制之 AIDL(3)

@Override public void addBook(net.bingyan.library.Book book) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR) if ((book != null)) { _data.writeInt(1); book.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override /* */ public java.util.List<net.bingyan.library.Book> getBookList() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<net.bingyan.library.Book> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(net.bingyan.library.Book.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; }

它们是编译器自动实现的,这两个方法有很多类似之处,可以现在这里透露下:这两个方法就是客户端进程调用服务端进程的窗口。在这两个方法的开始,它们都定义了两个 Parcel(中文译名:包裹)对象。Parcel 这个类我们看上去很眼熟,是的,Book 类中的 writeToParcel() 和 CREATOR中的 createFromParcel() 的参数就是 Parcel 类型的,关于这个类文档中解释如下:

Container for a message (data and object references) that can be sent through an IBinder. A Parcel can contain both flattened data that will be unflattened on the other side of the IPC (using the various methods here for writing specific types, or the general {@link Parcelable} interface), and references to live {@link IBinder} objects that will result in the other side receiving a proxy IBinder connected with the original IBinder in the Parcel.

翻译一下:Proxy 是一个可以通过 IBinder 进行消息传递的一个容器。一个 Parcel 可以包含可序列化的数据,这些数据会在 IPC 的另一端被反序列化;它也可以包含指向 IBinder 对象的引用,这会使得另一端接收到一个 IBinder 类型的代理对象,这个代理对象连接着 Parcel 中的原始 IBinder 对象。

下面用图来直观的说明:

Android 进程通信机制之 AIDL

如图,我们可以很直观的看到服务端以 Parcel 作为数据包裹依靠 Binder 和客户端进行通信。数据包裹就是序列化之后的对象。

如上所述,这两个方法都定义了两个 Parcel 对象,分别叫做 _data 和 _reply,形象的来说,从客户端的角度来看,_data 就是客户端发送给服务端的数据包裹,_reply 服务端发送给客户端的数据包裹。

之后便开始用这两个对象来和服务端进行通信了,我们能够观察到,两个方法中都有这么个方法调用 mRemote.transact(),它有四个参数,第一个参数的意义我们后面再讲,第二个参数 _data 负责向服务端发送数据包裹比如接口方法的参数,第三个参数 _reply 负责从服务端接收数据包裹比如接口方法的返回值。这行代码只有一句简单的方法调用,但是却是 AIDL 通信的最核心部分,它其实进行了一次远程方法调用(客户端通过本地代理 Proxy 暴露的接口方法调用服务端 Stub 同名方法),所以能想到它是一个耗时操作。

在我们的例子中:

void addBook(Book book) 需要借助 _data 向服务端发送参数 Book:book,发送的方式就是把 Book 通过其实现的 writeToParcel(Parcel out) 方法打包至 _data 中,正如你能想到的,_data 其实就是参数 out,还记得 Book 中的这个方法的实现吗? 我们是将 Book 的字段一个个打包至 Parcel 中的。

List<Book> getBookList() 需要借助 _reply 从服务端接收返回值 List<Book>:books,方法中的做法是将 Book 中的 CREATOR 这个静态字段作为参数传入 _reply 的 createTypedArrayList() 方法中,还记得 Book 中的 CREATOR 吗?当时你是不是好奇这个静态字段应该怎么用呢?现在一切明了了,我们需要靠这个对象(便于理解我们可以叫它”反序列化器“)来对服务端的数据反序列化从而重新生成可序列化的对象或者对象数组。很明显 CREATOR 借助 _reply 生成了 List<Book>:books。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/633ceaacfd10c53714a976eb5608e6de.html