前言
首先,这篇文章主要是基于上一篇文章aidl的学习记录来继续学习的,所以没看过上一篇文章的可以先看看。
AidlBookManager文件
上一篇文章通过aidl在 build/generated/source/aidl/你的 flavor/
下生成一个 Java 文件AidlBookManager.java。
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: D:\\workspace\\aidlTestClient\\app\\src\\main\\aidl\\kanghb\\com\\aidltest\\AidlBookManager.aidl
*/
package kanghb.com.aidltest;
public interface AidlBookManager extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements kanghb.com.aidltest.AidlBookManager {
private static final java.lang.String DESCRIPTOR = "kanghb.com.aidltest.AidlBookManager";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an kanghb.com.aidltest.AidlBookManager interface,
* generating a proxy if needed.
*/
public static kanghb.com.aidltest.AidlBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof kanghb.com.aidltest.AidlBookManager))) {
return ((kanghb.com.aidltest.AidlBookManager) iin);
}
return new kanghb.com.aidltest.AidlBookManager.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_getBooks: {
data.enforceInterface(DESCRIPTOR);
java.util.List<kanghb.com.aidltest.Book> _result = this.getBooks();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
kanghb.com.aidltest.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = kanghb.com.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 kanghb.com.aidltest.AidlBookManager {
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;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*///所有的返回值前都不需要加任何东西,不管是什么数据类型
@Override
public java.util.List<kanghb.com.aidltest.Book> getBooks() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<kanghb.com.aidltest.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBooks, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(kanghb.com.aidltest.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
//传参时除了Java基本类型以及String,CharSequence之外的类型
//都需要在前面加上定向tag,具体加什么量需而定
@Override
public void addBook(kanghb.com.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_getBooks = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*///所有的返回值前都不需要加任何东西,不管是什么数据类型
public java.util.List<kanghb.com.aidltest.Book> getBooks() throws android.os.RemoteException;
//传参时除了Java基本类型以及String,CharSequence之外的类型
//都需要在前面加上定向tag,具体加什么量需而定
public void addBook(kanghb.com.aidltest.Book book) throws android.os.RemoteException;
}
客户端服务端根据这个系统生成的Binder来进行进程间通讯。。
AidlBookManager文件结构
0.DESCRIPTOR,Binder的唯一标识,当前Binder的类名表示
private static final java.lang.String DESCRIPTOR = "kanghb.com.aidltest.AidlBookManager";
1.AidlBookManager继承了android.os.IInterface
这个接口,自己也是个接口。
2.声明了两个在AidlBookManager.aidl
中定义的方法
public java.util.List<kanghb.com.aidltest.Book> getBooks() throws android.os.RemoteException;
public void addBook(kanghb.com.aidltest.Book book) throws android.os.RemoteException;
3.声明两个整形id标识上面两个方法,用于在transact
过程中客户端所请求的到底是哪个方法
static final int TRANSACTION_getBooks = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
4.声明一个内部类Stub继承Binder类,Stub内部声明一个代理类Proxy,接口的核心实现就是由Stub和Stub.Proxy组成。
AidlBookManager重要方法
Stub相关
asInterface(android.os.IBinder obj)
public static kanghb.com.aidltest.AidlBookManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof kanghb.com.aidltest.AidlBookManager))) { return ((kanghb.com.aidltest.AidlBookManager) iin); } return new kanghb.com.aidltest.AidlBookManager.Stub.Proxy(obj); }
用于将服务端的Biner对象转化为客户端需要的aidl接口类型的对象。如果客户端服务端属于同一个进程,返回Stub对象本身,否则返回Stub.Proxy对象。
asBinder
@Override public android.os.IBinder asBinder() { return this; }
用于返回当前Binder对象
onTransact
@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_getBooks: { data.enforceInterface(DESCRIPTOR); java.util.List<kanghb.com.aidltest.Book> _result = this.getBooks(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addBook: { data.enforceInterface(DESCRIPTOR); kanghb.com.aidltest.Book _arg0; if ((0 != data.readInt())) { _arg0 = kanghb.com.aidltest.Book.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addBook(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); }
运行在服务端的Binder线程池中,服务端通过参数code判断请求的目标方法,从data中取出方法所需要的参数(如果目标方法有参数的话),然后执行目标方法,执行完毕后向reply中写入返回值(如果目标方法有返回值的话)。如果
onTransact
返回false,则客户端请求失败。
Stub.Proxy相关
1.getBooks
@Override
public java.util.List<kanghb.com.aidltest.Book> getBooks() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<kanghb.com.aidltest.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBooks, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(kanghb.com.aidltest.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
运行在客户端,客户端调用此方法时,首先创建Parcel对象:输入型_data和输出型_reply,返回值对向List,把参数写入_data中,调用transact
方法发起远程过程调用请求,线程挂起等待,服务端的onTransact
方法被调用,一直到RPC结束后,继续执行当前线程,从_reply中取出返回的结果,最后返回_result数据。
2.addBook(kanghb.com.aidltest.Book book)
@Override
public void addBook(kanghb.com.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();
}
}
和getBooks执行逻辑一样。
注意点
客户端发起远程请求时,由于当前线程会被挂起至服务器端进程返回数据,所以如果一个远程方法是耗时的,那么不能再UI线程中发起远程请求;其次,由于服务端的Binder方法运行在Binder的线程池中,所以不管Binder是否耗时,都应该才用同步方法实现,因为它已经运行在一个线程中了。
Binder 死亡处理
在进程间通信过程中,很可能出现一个进程死亡的情况。如果这时活着的一方不知道另一方已经死了就会出现问题。那我们如何在 A 进程中获取 B 进程的存活状态呢?
Android 肯定给我们提供了解决方式,那就是 Binder
的 linkToDeath
和 unlinkToDeath
方法, linkToDeath
方法需要传入一个 DeathRecipient
对象, DeathRecipient
类里面有个 binderDied
方法,当 binder
对象的所在进程死亡, binderDied
方法就会被执行,我们就可以在 binderDied
方法里面做一些异常处理,释放资源等操作了。
声明一个DeathRecipient
对象,实现binderDied()
方法,移除之前绑定的binder代理并重新绑定远程服务。
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
Log.e(getLocalClassName(), "服务死亡了,要开始重连了");
if(aidlBookManager == null)
return;
aidlBookManager.asBinder().unlinkToDeath(mDeathRecipient,0);
aidlBookManager = null;
//重新绑定远程services
attemptToBindService();
}
};
在客户端绑定远程服务成功后,给binder设置死亡代理
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(getLocalClassName(), "service connected");
aidlBookManager = AidlBookManager.Stub.asInterface(service);
try {
aidlBookManager.asBinder().linkToDeath(mDeathRecipient,0);
} catch (RemoteException e) {
e.printStackTrace();
}
。。。。省略
}
这样就给Binder设置了死亡代理,当Binder死亡的时候我们就可以收到通知了。当客户点app连接到服务端app后,杀死服务店app然后看到如下效果。