概述
AIDL (Android Interface Definition Language)是Android内部进程通信(IPC)的接口定义语言,通过它可以定义客户端与服务器端的通信接口,实现跨进程通信。
只有当需要允许来自不同应用的客户端跨进程通信访问Service,且想要在Service中处理多线程的时候AIDL才是必要的。如果不需要执行不同应用之间的IPC并发,可以通过实现Binder建立接口;如果需要执行IPC,但不需要处理多线程,可以使用Messenger实现接口。
在使用AIDL之前,需要先了解Bound Services。
使用AIDL三部曲
1. 创建.aidl文件
在src/main/aidl/%packagename%/下创建.aidl文件,定义接口方法。
.aidl文件中只能定义方法,不能定义静态变量。
.aidl文件支持的数据类型:
- 基本数据类型(int, byte, char, float, boolean, ...)
- String
- CharSequence
- Array
- List
- Map
- Parcelable
特殊关键字in, out, inout :
in表示由客户端设置,修饰输入参数,非基本类型的输入参数必须使用in修饰
out表示由服务器端设置,修饰输出参数,非基本类型的输出参数必须使用out修饰
-
inout表示既是输入参数,也是输出参数
void copyArray(in byte[] source, out byte[] dest); void sort(inout int[] source);
示例
// IRemoteService.aidl
package com.example.android;
// Declare any non-default types here with import statements
/** Example service interface */
interface IRemoteService {
/** Request the process ID of this service, to do evil things with it. */
int getPid();
/** Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
2. 实现接口
build项目,Android SDK tools会自动生成.java文件,实现其内部抽象类Stub。
抽象类Stub继承Binder,并实现了.aidl文件中定义的接口。
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
public int getPid() {
return Process.myPid();
}
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString) {
}
};
注意:
- RPC调用是同步的,执行耗时操作时,不应该在主线程调用其方法
- 抛出的异常不会发送给客户端
3. 公开接口
创建一个Service,实现其onBind(intent)方法,返回实现接口的对象。
public class RemoteService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
// Return the interface
return mBinder;
}
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
public int getPid(){
return Process.myPid();
}
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString) {
}
};
}
客户端绑定Service时,通过ServiceConnection对象获取返回的IBinder对象,即可调用远程方法。
IRemoteService mIRemoteService;
private ServiceConnection mConnection = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
// Following the example above for an AIDL interface,
// this gets an instance of the IRemoteInterface, which we can use
// to call on the service
mIRemoteService = IRemoteService.Stub.asInterface(service);
}
// Called when the connection with the service disconnects unexpectedly
public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "Service has unexpectedly disconnected");
mIRemoteService = null;
}
};
相关类
Parcelable(自定义数据类型)
Parcelable接口是Android特有的,实现该接口的对象可以被序列化,可以用于进程间通信。
如果想通过远程服务传递自定义的类对象,则该类必须实现Parcelable接口,过程如下:
-
创建.aidl文件,声明类
//Rect.aidl package com.thea.aidl; parcelable Rect;
实现其writeToParcel()方法
-
初始化类型为Parcelable.Creator
的静态变量CREATOR。 //Rect.java import android.os.Parcel; import android.os.Parcelable; public final class Rect implements Parcelable { public int left; public int top; public int right; public int bottom; public static final Parcelable.Creator
CREATOR = new Parcelable.Creator () { public Rect createFromParcel(Parcel in) { return new Rect(in); } public Rect[] newArray(int size) { return new Rect[size]; } }; public Rect() { } private Rect(Parcel in) { readFromParcel(in); } public void writeToParcel(Parcel out) { out.writeInt(left); out.writeInt(top); out.writeInt(right); out.writeInt(bottom); } public void readFromParcel(Parcel in) { left = in.readInt(); top = in.readInt(); right = in.readInt(); bottom = in.readInt(); } }
RemoteCallbackList(远程接口回调)
客户端通过ServiceConnection对象获取返回的IBinder对象,从而调用远程Service的方法。
Service通过客户端注册的回调来调用客户端的方法。RemoteCallbackList就是用来保存注册进来的回调实例,它自动处理了Link-To-Death的问题,当客户端意外退出时,自动删掉对应的实例。
注册回调过程如下:
-
创建.aidl文件,声明回调接口
// ICallback.aidl package com.thea.aidl; interface ICallback { void onSuccess(in Bundle data); void onFail(int errCode); }
-
在Service中定义RemoteCallbackList变量,在IBinder里实现回调注册方法
public class RemoteService extends Service { ... private RemoteCallbackList
mCallbacks = new RemoteCallbackList<>(); private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { ... @Override public void registerCallback(ICallback cb) throws RemoteException { mCallbacks.register(cb); } @Override public void unregisterCallback(ICallback cb) throws RemoteExceptio { mCallbacks.unregister(cb); } @Override public void call(Bundle data) throws RemoteException { final int len = mCallbacks.beginBroadcast(); for (int i = 0; i < len; i++) { try { // 通知回调 mCallbacks.getBroadcastItem(i).onSuccess(data); } catch (RemoteException e) { e.printStackTrace(); } } mCallbacks.finishBroadcast(); } }; } -
客户端实现回调接口,并注册到RemoteService
public class MainActivity extends AppCompatActivity { private final ICallback.Stub mCallback = new ICallback.Stub() { public void onSuccess(Bundle data) { } public void onFail(int errCode) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); registerCallback(); } @Override public void onDestroy() { super.onDestroy(); unregisterCallback(); } public void click(View v) { mIRemoteService.call(new Bundle()); //会触发onSuccess(Bundle) } public void registerCallback() { mIRemoteService.registerCallback(mCallback); } public void unregisterCallback() { mIRemoteService.unregisterCallback(mCallback); } }
参考资料
Android Interface Definition Language (AIDL)
Android AIDL使用详解
与Sevice实现双向通信