先上代码结构图:
可以看到在main目录下新建了aidl包,里面建立了一个类和两个aidl文件:
Book.java
package com.games.lwp.aidltest;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by 10747 on 2017/10/6.
*/
public class Book implements Parcelable{
public int bookId;
public String bookName;
public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
@Override
public int describeContents() {
return 0;
}
//序列化
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(bookId);
dest.writeString(bookName);
}
//反序列化
public static final Parcelable.Creator CREATOR=new Parcelable.Creator(){
@Override
public Book createFromParcel(Parcel source) {
return new Book(source);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
private Book(Parcel source){
bookId = source.readInt();
bookName=source.readString();
}
}
上面Book类实现了序列化,具体不细说,有注解.
Book.aidl
package com.games.lwp.aidltest;
parcelable Book;
这是Book类在aidl中的声明.
BookManager.aidl
package com.games.lwp.aidltest;
// Declare any non-default types here with import statements
import com.games.lwp.aidltest.Book;
interface IBookManager {
List getBookList();
void addBook(in Book book);
}
需要注意的是,尽管Book.java和IBookManager.aidl位于同一个包下,还是需要显示的将Book类导入.
ok,完毕,接着run一下,发现出错,原因是系统生成的IBookManager无法发现Book这个类,我们需要在修改 build.gradle 文件:在 android{} 中间加上下面的内容:
sourceSets {
main {
java.srcDirs = ['src/main/java', 'src/main/aidl']
}
}
具体原因,这个博客给出了解释:
http://blog.csdn.net/kururunga/article/details/61414033
然后运行就不报错了,然后我们看系统生成的IBookManager.java
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: F:\\Android_WorkSpace\\AidlTest\\app\\src\\main\\aidl\\com\\games\\lwp\\aidltest\\IBookManager.aidl
*/
package com.games.lwp.aidltest;
//asInterface只有一个方法asBinder
public interface IBookManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.games.lwp.aidltest.IBookManager
{
private static final java.lang.String DESCRIPTOR = "com.games.lwp.aidltest.IBookManager";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.games.lwp.aidltest.IBookManager interface,
* generating a proxy if needed.
*/
//将IBinder对象obj转换成aidl接口
public static com.games.lwp.aidltest.IBookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
//IBinder对象查询DESCRIPTOR是否和客户端位于同进程
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.games.lwp.aidltest.IBookManager))) {
return ((com.games.lwp.aidltest.IBookManager)iin);
}
return new com.games.lwp.aidltest.IBookManager.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@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_getBookList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(DESCRIPTOR);
com.games.lwp.aidltest.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.games.lwp.aidltest.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.games.lwp.aidltest.IBookManager
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public java.util.List getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.games.lwp.aidltest.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.games.lwp.aidltest.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();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public java.util.List getBookList() throws android.os.RemoteException;
public void addBook(com.games.lwp.aidltest.Book book) throws android.os.RemoteException;
}
我们从上往下看:
1.首先看到该IBookManager类是一个接口,这个接口继承了android.os.IInterface,那这是个什么鬼?点进去看看:
package android.os;
/**
* Base class for Binder interfaces. When defining a new interface,
* you must derive it from IInterface.
*/
public interface IInterface
{
/**
* Retrieve the Binder object associated with this interface.
* You must use this instead of a plain cast, so that proxy objects
* can return the correct result.
*/
public IBinder asBinder();
}
这也是个接口,里面只有一个asBinder方法,返回IBinder类型,这里需要补充一下,Binder是Android的一个类,实现了IBinder接口,那这个方法谁实现的,看下:
@Override public android.os.IBinder asBinder()
{
return this;
}
返回的是当前的Binder对象.
2.往下看,里面定义了一个抽象类Stub 继承了android.os.Binder 并且实现了com.games.lwp.aidltest.IBookManager,那很显然,内部是要实现IBookManager.aidl中定义的两个方法,
public static com.games.lwp.aidltest.IBookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
//IBinder对象查询DESCRIPTOR是否和客户端位于同进程
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.games.lwp.aidltest.IBookManager))) {
return ((com.games.lwp.aidltest.IBookManager)iin);
}
return new com.games.lwp.aidltest.IBookManager.Stub.Proxy(obj);
}
这里面通过IBinder对象判断服务器和客户端是否位于同一个进程,在queryLocalInterface方法中有如下说明:
/**
* Attempt to retrieve a local implementation of an interface
* for this Binder object. If null is returned, you will need
* to instantiate a proxy class to marshall calls through
* the transact() method.
*/
public IInterface queryLocalInterface(String descriptor);
如果是那么就返回((com.games.lwp.aidltest.IBookManager)iin,通过这个对象就能调用IBookManager里面的方法,如果是多进程,则返回的是new com.games.lwp.aidltest.IBookManager.Stub.Proxy(obj),这个就是内部代理类Proxy,我们可以看下:
private static class Proxy implements com.games.lwp.aidltest.IBookManager
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public java.util.List getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.games.lwp.aidltest.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.games.lwp.aidltest.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();
}
}
}
当位于不同进程的时候调用的此代理类,这里会把IBinder对象obj传给mRemote,这个时候,当客户端调用方法时,就是通过Proxy来调用其中的方法.那我们可以看看Proxy里面方法的实现
@Override public java.util.List getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.games.lwp.aidltest.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.games.lwp.aidltest.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();
}
}
getBookList和addBook都是运行在客户端,当客户的调用此方法时候,创建该方法所需要的输入型Parcel对象_data,输出型Parcel对象_reply,和返回值对象list,然后把该方法的参数信息写入_data中,接着调用transact方法来发起远程过程调用请求,同时当前线程挂起;然后服务器端的onTransact方法会被调用直到RPC过程返回后,当前线程继续执行,从_reply中取出RPC过程的返回结果;
而onTransact是运行在Binder线程池中,服务器端可以通过code区分客户端所请求的方法是什么,接着从data中取出目标方法所需要的参数,然后执行目标方法,