Demo详细地址
AIDL是Android中一种特有的进程间通信手段,看完AIDL的使用后,感觉和当前比较流行的RPC框架比较相似。RPC也需要使用接口定义语言去声明接口对象和接口定义。以便生成相应的远程调用代码。
假设有这么一个场景,进程A提供了两个服务:
a. 查询图书列表
b. 添加图书
1. 我们首先需要声明一个图书类,由于这个图书类Book的对象需要在两个进程之前传递,所以我们需要实现Android中特有的序列化接口Parcelable。
package com.alipay.aidl.test;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by tianbei on 2016/1/31.
*/
public class Book implements Parcelable {
public int bookId;
public String bookName;
public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
public Book(Parcel in) {
bookId = in.readInt();
bookName = in.readString();
}
@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];
}
};
}
2. 定义aidl文件
对于aidl接口中要使用的自定义类,必须要在aidl文件中进行声明。下面是Book.aidl。
package com.alipay.aidl.test;
parcelable Book;
图书管理接口aidl文件
// IBookManager.aidl
package com.alipay.aidl.test;
import com.alipay.aidl.test.Book;
import com.alipay.aidl.test.IOnNewBookArrivedListener;
// Declare any non-default types here with import statements
interface IBookManager {
List getBookList();
void addBook(in Book book);
void registerListener(in IOnNewBookArrivedListener listener);
void unregisterListener(in IOnNewBookArrivedListener listener);
}
图书订阅消息推送接口:
// IOnNewBookArrivedListener.aidl
package com.alipay.aidl.test;
import com.alipay.aidl.test.Book;
// Declare any non-default types here with import statements
interface IOnNewBookArrivedListener {
void onNewBookArrived(in Book book);
}
上面的代码需要在客户端进程和服务端进程中同时存在。因为客户端和服务端都需要使用到IBookManager接口和Book类。
服务端代码需要实现IBookManager.Stub接口,以执行具体的业务逻辑。比如添加图书:服务端需要将图书保存起来,可以保存到数据库持久化,这就是服务端的业务逻辑。在实现具体的业务逻辑之前,我们先看下Android studio为我们生成的接口文件IBookManager.java。这个Java类看起来很复杂,其实结构比较简单,它继承了类IInterface。
a. 接口方法定义,比如我们在aidl文件中声明的addBook方法,getBookList方法。
b. 内部类Stub。这个类集成了IBinder,它就是我们所说的Binder类,运行在服务端。服务端代码通过集成这个类会进行具体的业务逻辑。
c. Proxy类:运行于客户端,跟我们些http通讯时的逻辑一样,它会把入参序列化,然后远程调用,然后将返回的结果反序列化。
接下来,我们看下服务端的代码:
package com.alipay.aidl.test;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Created by tianbei on 2016/1/31.
*/
public class BookManagerService extends Service {
private static final String TAG = "BMS";
private List mBookList = new CopyOnWriteArrayList();
private RemoteCallbackList mListenerList =
new RemoteCallbackList();
private Binder mBinder = new IBookManager.Stub(){
@Override
public List getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
onNewBookArrived(book);
}
@Override
public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
mListenerList.beginBroadcast();
boolean result = mListenerList.register(listener);
Log.d(TAG, "register listener :" + result);
mListenerList.finishBroadcast();
}
@Override
public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
mListenerList.beginBroadcast();
boolean result = mListenerList.unregister(listener);
Log.d(TAG, "unregister listener :" + result);
mListenerList.finishBroadcast();
}
};
public void onNewBookArrived(Book book) {
mBookList.add(book);
int N = mListenerList.beginBroadcast();
for(int i = 0; i < N; i++) {
IOnNewBookArrivedListener listener = mListenerList.getBroadcastItem(i);
try {
listener.onNewBookArrived(book);
} catch (RemoteException e) {
e.printStackTrace();
}
}
mListenerList.finishBroadcast();
}
@Override
public void onCreate() {
super.onCreate();
mBookList.add(new Book(1, "ARM体系结构与编程"));
mBookList.add(new Book(2, "Android开发艺术探索"));
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
BookManagerService是运行在服务端的一个Service类,它里面有一个内部匿名类,实现了IBookManager.Stub接口,这就是我们上面说的运行于服务端的代码,它会实现aidl接口定义文件中声明的四个方法。添加图书、获取图书列表、添加图书时,调用注册到Manager中的各个listener通知其他进程有新书上架。
为什么需要Binder线程池呢?按照上面的写法,服务器端进程每声明一个Binder接口供客户端进程调用,就需要声明一个Service组件。而如果一个客户端端有100个Binder类的话,就需要定义100个Service组件,并且需要在Manifest文件中声明。这样是很消耗系统资源的。
在上面的实现中,我们可以发现,服务端返回Binder类到客户端的方法是:在onBind的实现中返回一个IBookManager.Stub对象。
那么我们可不可以定义一个统一的Service,然后客户端进程传一个标识进来,服务端进程通过不同的标识返回不同的Binder对象呢?答案是可以的。
这里就不详细说了,直接上Demo。Demo详细地址