参考书籍《Android开发艺术探索》,《Android内核剖析》
案例源码
AIDL中支持的数据类型
- 基本数据类型:int,long,char,boolean,double等
- String和CharSequence
- ArrayList,但是ArrayList中存入的元素必须被AIDL支持
- HashMap,但是HashMap中存入的元素都必须被AIDL支持
- 所有实现了Parcelable接口的对象
使用AIDL注意事项
- 编译时可能找不到自定义实现Parcelable接口的java类,需要在App Module的
build.gradle
中添加以下代码。参考
android {
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
java.srcDirs = ['src/main/java', 'src/main/aidl']
resources.srcDirs = ['src/main/java', 'src/main/aidl']
aidl.srcDirs = ['src/main/aidl']
res.srcDirs = ['src/main/res']
assets.srcDirs = ['src/main/assets']
}
}
}
- 每一个实现了
Parcelable
接口的Java类,如果AIDL文件中用到了该类,必须新建一个同名的.aidl文件.
// Book.java
// 自定义Java类,实现了Parcelable接口.
package com.yey.ok;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable {
}
// IBookManager.aidl
// 假如它被另外一个AIDL文件用到了.
package com.yey.ok;
import com.yey.ok.Book;
interface IBookManager{
void addBook(in Book book);
}
// 必须新建一个同名的.aidl文件.
package com.yey.ok;
parcelable Book;
- AIDL对象被另一个AIDL文件使用, 就算他们位于同一包下,使用
aidl
文件也需要显示的import
进来.
// Book.aidl
// Book.aidl如果被另外一个AIDL文件使用
package com.yey.ok;
parcelable Book;
// IBookManager.aidl
// 使用Book.aidl文件,需要显示的import.
package com.yey.ok;
// 显示的import
import com.yey.ok.Book;
interface IBookManager{
void addBook(in Book book);
}
- AIDL中只支持方法,不支持声明静态常量.
// IBookManager.aidl
package com.yey.ok;
import com.yey.ok.Book;
interface IBookManager{
// String name; //声明静态常量是不允许的.
List<Book> getBookList();//方法是可以的
}
- 方法参数必须标记好方向
// IBookManager.aidl
package com.yey.ok;
import com.yey.ok.Book;
interface IBookManager{
// in:输入型参数
// out:输出型参数
// inout:输入输出型参数
void addBook(in Book book);
}
- 客户端发起远程请求时,当前线程会被挂起直到服务端进程返回数据,这个过程是一个耗时操作,所以不要在UI线程发起请求.
- 被请求的服务端方法是运行在Binder线程池中(另一个线程中),onTransact()应该采用同步方式实现.
分析通过AIDL自动生成的Java类
IBookManager.java
由IBookManager.aidl
文件自动生成,首先来分析IBookManager.Stub
// IBookManager.Stub.java
public interface IBookManager extends android.os.IInterface {
// Stub:Binder本地对象,也就是服务端进程持有它.
public static abstract class Stub extends android.os.Binder implements IBookManager {
// 该Binder本地对象的唯一标识符,一般用当前Binder类名称表示.
private static final String DESCRIPTOR = "com.yey.ok.笔记.IBookManager";
public Stub() {
// mOwner = this
// mDescriptor = DESCRIPTOR
// 传入之后,就可以使用queryLocalInterface()返回相应的Binder对象了.
// attachInterface()是使用queryLocalInterface()的前提.
this.attachInterface(this, DESCRIPTOR);
}
// 用于返回Binder对象, 是返回Binder本地对象还是Binder代理对象视进程而定。
public static IBookManager asInterface(android.os.IBinder obj) {
if ((obj==null)) {
return null;
}
// queryLocalInterface() 该方法上面讲过, 通过描述符来查找Binder本地对象。
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
// 如果查找的Binder对象不为空,且是在同一个进程(iin instanceof 笔记.IBookManager)
if (((iin!=null)&&(iin instanceof IBookManager))) {
// 那么就将查到当前进程中的Binder本地对象直接返回就行了。
return ((IBookManager)iin);
}
// 如果不是同一个进程中的(iin instanceof 笔记.IBookManager)
// 那么就返回这个Binder本地对象对应的Binder代理对象。
// obj 是BpBinder类型的Binder代理对象,内部包含有Binder引用对象的句柄值.通过该句柄值就可以找到Binder引用对象再找到Binder实体对象,最后找到Binder本地对象.
return new Stub.Proxy(obj);
}
// 返回当前Binder本地对象。
@Override
public android.os.IBinder asBinder() {
return this;
}
/**
* 这个方法是运行在服务端的Binder线程池中,客户端发起跨进程请求,最终会交由此方法处理。
* @param code 用来确认客户端请求的目标方法是什么。
* @param data 用来存放目标方法中的参数
* @param reply 用来存入目标方法执行完成的返回值
* @param flags
* @return false 代表客户端请求失败,true代表客户端请求成功。
* @throws android.os.RemoteException
*/
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{
String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(descriptor);
// getBookList()由服务端实现.
java.util.List<com.yey.ok.Book> _result = this.getBookList();
reply.writeNoException();
// 写入返回值
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(descriptor);
com.yey.ok.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.yey.ok.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
// 该方法由服务端实现
this.addBook(_arg0);
reply.writeNoException();
// 没有返回值就无需写入
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
}
}
- 分析
IBookManager.Stub.Proxy
// IBookManager.Stub.Proxy.java
public interface IBookManager extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements IBookManager {
//Binder代理类
private static class Proxy implements IBookManager {
// mRemote 是BpBinder类型的Binder代理对象,内部包含有Binder引用对象的句柄值.通过该句柄值就可以找到Binder引用对象再找到Binder实体对象,最后找到Binder本地对象.
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
// 返回Binder代理对象
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public String getInterfaceDescriptor() {
return DESCRIPTOR;
}
/**
* 该方法运行在客户端,当客户端调用该方法时,最终会调用服务端的onTransact().
* @return
* @throws android.os.RemoteException
*/
@Override
public java.util.List<com.yey.ok.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<com.yey.ok.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
// 开始RPC(远程过程调用),最终调用的就是服务端的onTransact()。
// 执行该方法后,当前线程会被挂起,等待服务端进程onTransact()调用完成并返回返回值,然后唤醒客户端线程继续执行。
boolean _status = mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
// 假如RPC失败,则通过IBookManager类型对象调用当前进程中getBookList(),
// getBookList()它是接口方法,需要当前进程自己该方法。
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getBookList();
}
_reply.readException();
// RPC成功,从_reply中取出返回值并返回。
_result = _reply.createTypedArrayList(com.yey.ok.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
* 该方法运行在客户端,当客户端调用该方法时,最终会调用服务端的onTransact().
* @param book
* @throws android.os.RemoteException
*/
@Override
public void addBook(com.yey.ok.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);
}
// RPC开始,当前线程会被挂起。
// RPC完成唤醒线程,继续下面代码执行。
boolean _status = mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
// 如果RPC失败,尝试调用当前进程中的方法,但是当前进程需要实现该方法。
getDefaultImpl().addBook(book);
// addBook() 不需要返回值, 所以return就行了。
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
public static IBookManager sDefaultImpl;
}
}
}
AIDL使用
- 客户端
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding mainBinding;
private final String TAG = this.getClass().getName();
private boolean isBind;
// 定义一个死亡接收者, 当服务进程挂了这里会收到通知
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (iBookManager == null) return;
// 取消设置的代理
// iBookManager如果是Stub.Proxy类型, 就返回Binder代理对象.
// iBookManager如果是Stub类型, 将返回Binder本地对象.
iBookManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
iBookManager = null;
Log.e(TAG, "收到死亡通知,已经接触绑定");
}
};
// Stub.Proxy类型对象或者Stub类型对象.
private IBookManager iBookManager;
// 服务链接
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// service Binder代理对象.
// asInterface()返回Stub.Proxy类型对象或者Stub类型对象.
iBookManager = IBookManager.Stub.asInterface(service);
try {
// 设置死亡代理
service.linkToDeath(mDeathRecipient, 0);
printBookList();
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
// 绑定远程服务
mainBinding.button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent service = new Intent("com.yey.app_server.bookmanagerserver");
service.setPackage("com.yey.app_server");
bindService(service, connection, BIND_AUTO_CREATE);
isBind = true;
}
});
// 解绑远程服务
mainBinding.button3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isBind) {
unbindService(connection);
isBind = false;
}
}
});
}
- 服务端
public class BookManagerServer extends Service {
// CopyOnWriteArrayList写是同步的, 支持并发读取.
public CopyOnWriteArrayList mBookList = new CopyOnWriteArrayList();
@Override
public void onCreate() {
super.onCreate();
mBookList.add(new Book(0,"Android开发艺术探索"));
mBookList.add(new Book(1,"Android内核剖析"));
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
// Binder本地对象
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
};
}