Android AIDL
下面是三个类Post.class(用上面Parcelable的Post作为实例,主要是得实现Parcelable序列化),Post.aidl和IPostManager.aidl
//Post.aidl
package com.gss.aidl
prarcelable Post;
//IPostManager.aidl
package com.gss.aidl
import com.gss.aidl.Post
interface IPostManager{
List<Post> getBookList();
void addBook(in Book book);
}
注意每个类所在位置,post类和post.aidl必须同包名,同名字,分别在aidl和java目录下。
然后就是一键生成ADIL的代码,系统会为我们生成IPostManager.java这个类,他继承了IInterface接口,所有binder传输接口都要继承
IInterface接口。声明了IPostManager的方法,生成id标识这两个方法。接着声明内部类Stub,这就是一个binder类,当服务端和客户端处于同一个进程,方法调用不会走跨进程的transact过程,当两者不一样的时候,就需要了。这个逻辑,由Stub的内部代理类Proxy来完成。
下面介绍Stub和Proxy类的方法含义:
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package com.gss.aidl;
public interface IPostManager extends android.os.IInterface
{
/** Default implementation for IPostManager. */
public static class Default implements com.gss.aidl.IPostManager
{
@Override public java.util.List<com.gss.aidl.Post> getBookList() throws android.os.RemoteException
{
return null;
}
@Override public void addBook(com.gss.aidl.Post book) throws android.os.RemoteException
{
}
@Override public com.gss.aidl.Post getBook() throws android.os.RemoteException
{
return null;
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.gss.aidl.IPostManager
{
private static final java.lang.String DESCRIPTOR = "com.gss.aidl.IPostManager";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.gss.aidl.IPostManager interface,
* generating a proxy if needed.
*/
public static com.gss.aidl.IPostManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.gss.aidl.IPostManager))) {
return ((com.gss.aidl.IPostManager)iin);
}
return new com.gss.aidl.IPostManager.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
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getBookList:
{
data.enforceInterface(descriptor);
java.util.List<com.gss.aidl.Post> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(descriptor);
com.gss.aidl.Post _arg0;
if ((0!=data.readInt())) {
_arg0 = com.gss.aidl.Post.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getBook:
{
data.enforceInterface(descriptor);
com.gss.aidl.Post _result = this.getBook();
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.gss.aidl.IPostManager
{
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<com.gss.aidl.Post> getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.gss.aidl.Post> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getBookList();
}
_reply.readException();
_result = _reply.createTypedArrayList(com.gss.aidl.Post.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.gss.aidl.Post 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);
}
boolean _status = mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().addBook(book);
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public com.gss.aidl.Post getBook() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
com.gss.aidl.Post _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getBook, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getBook();
}
_reply.readException();
if ((0!=_reply.readInt())) {
_result = com.gss.aidl.Post.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public static com.gss.aidl.IPostManager sDefaultImpl;
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_getBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
public static boolean setDefaultImpl(com.gss.aidl.IPostManager impl) {
// Only one user of this interface can use this function
// at a time. This is a heuristic to detect if two different
// users in the same process use this function.
if (Stub.Proxy.sDefaultImpl != null) {
throw new IllegalStateException("setDefaultImpl() called twice");
}
if (impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static com.gss.aidl.IPostManager getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
public java.util.List<com.gss.aidl.Post> getBookList() throws android.os.RemoteException;
public void addBook(com.gss.aidl.Post book) throws android.os.RemoteException;
public com.gss.aidl.Post getBook() throws android.os.RemoteException;
}
DESCRIPTOR
Binder的唯一标识,一般用当前Binder类名标识。
asInterface(android.os.IBinder obj)
用于将服务端的Binder对象转换成客户端所需的AIDL接口类型对象,如果同进程调用Stub本身,不同调用系统封装的Stub.proxy对象
asBinder
此方法用于返回当前的Binder对象
onTransact
这个方法运行在Binder线程池中,当客户端法强跨进程请求是,远程请求会通过系统封装后交给此方法处理。
其他就是Proxy的方法了,里面基本就是实现AIDL接口代码。
注意:AIDL是同步的,如果远程方法很耗时,不能UI线程中请求。其次,服务端的Binder方法运行在Binder的线程池中,所有Binder方法无论是否耗时都采用同步的方式实现,因为它已经运行在一个线程中了。
从上面看,我们完全可以不用AIDL文件可以实现Binder,之所以使用AIDL,是为了方便,系统自动帮生成代码,我们自己可以手动写一个Binder,主要是是一个Binder的接口,继承了IInterface接口,然后是内部Stub类,这个类就是Binder,内部实现了IBookManager接口中的方法,在Service中调用这个Stub对象。手动实现步骤:
1.声明AIDL接口,只需要继承IInterface接口,里面只有一个asBinder方法。
2.实现Stub类和Stub类中的Proxy代理类。
3.远程调用
接下来介绍Binder的linkToDeath和unlinkToDeath方法,处理Binder连接断裂的问题,设置一个死亡代理。
首先需要声明一个DeathRecipient接口,实现这个接口,当Binder死亡的时候会回调里面的BinderDied方法。
private IBinder.DeathRecipient mDeathRecipient=new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if(mBookManager==null){
return;
}
mBookManager.asBinder().unlinkToDeath(mDeathRecipient,0);
mBookManager=null;
//这里重新绑定远程服务
}
};
客户端设置代理
mServiec= IMessageBoxManager.Stub.asInterface(binder);
binder.linkToDeath(mDeathRecipient,0);