一、概述
AIDL 是Android的进程间通信(IPC)比较常用的一种方式,AIDL 是 Android Interface Definition Language 的缩写,即Android接口定义语言。
Android中,每一个进程都有自己的Dalvik VM实例,拥有一个独立的内存空间,进程与进程之间是不共享内存的,每个进程都在自己的内存空间内进程数据存储,有时候我们需要两个进程之间进行数据交互,这就产生了进程间通信的需求。
AIDL优点:
1.进程间通信不止有AIDL,我们还有其他选择,例如 BroadcastReceiver , Messenger 等,但是 BroadcastReceiver 存在占用的系统资源比较多和存在延迟问题,在频繁的跨进程通信时是无法满足需求的;Messenger 进行跨进程通信时请求队列是同步进行的,无法并发执行,不能进行多进程通信,局限性比加大,这个时候就需要使用 AIDL 了。
2.编译器通过*.aidl文件的描述信息生成符合通信协议的Java代码,我们无需自己去写这段繁杂的代码,只需要在需要的时候调用即可,通过这种方式我们就可以完成进程间的通信工作。
二、AIDL的基本使用
AIDL的底层是基于Binder实现的,而Binder机制也是一种请求-响应式的通信模型,请求方一般称为Client,响应方称为Server。
这里我提供一个Demo,Demo中AIDLServiceClient为服务端,AIDLClient为客户端,这里需要AIDLServiceClient对外提供接口,方便AIDLClient在需要向AIDLServiceClient传递数据或者使用AIDLServiceClient的存储数据。
首先分别创建AIDLServiceClient(服务端)和AIDLClient(客户端)两个项目,作为服务端和客户端使用。
服务端
在AIDLServiceClient项目中创建AIDL接口。
src\main 目录 右键new一个AIDL文件。
输入自定义AIDL名字,点击OK,即可创建出AIDL接口文件,文件中会默认生出一个basicTypes方法,该方法描述了AIDL中可以使用的基本类型(int, long, boolean, float, double, String)。
自定义自己的方法名,可以删除不需要的basicTypes方法,定义后需要Sync Project。
// IAidlServiceInterface.aidl
package com.fanxb.aidlserviceclient;
// Declare any non-default types here with import statements
interface IAidlServiceInterface {
String getMessages();
}
创建一个实现类,继承刚才创建的AIDL的名称里的Stub类,并实现接口方法。
public class IAidlInterfaceImpl extends IAidlServiceInterface.Stub {
@Override
public String getMessages() throws RemoteException {
return "This is the AIDL ServiceClient message!";
}
}
创建AIDLService类,并初始化IAidlInterfaceImpl实现类,在onBind方法中返回IAidlInterfaceImpl 实现类的实例。
public class AidlService extends Service {
private IAidlInterfaceImpl mIAidlInterface;
@Override
public void onCreate() {
super.onCreate();
mIAidlInterface = new IAidlInterfaceImpl();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mIAidlInterface;
}
}
创建ServiceAppliction类,在这里启动AIDLService。
public class ServiceApplication extends Application {
public static Context sContext;
@Override
public void onCreate() {
super.onCreate();
sContext = this;
startService(new Intent(this, AidlService.class));
}
public static Context getContext() {
return sContext;
}
}
在AndroidManifest.xml文件里配置Application 标签 name属性,指向所创建的ServiceAppliction类。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fanxb.aidlserviceclient">
<application
android:name=".ServiceApplication"
在AndroidManifest.xml文件里配置service,其中< intent-filter > 标签中的 action name 自定义,在客户端需要绑定服务端时设置同样的action,指向该服务建立连接。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fanxb.aidlserviceclient">
<application
//
<service
android:name="com.fanxb.aidlserviceclient.AidlService"
android:enabled="true">
<intent-filter>
<action android:name="com.fanxb.aidlserviceclient.service"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
</application>
</manifest>
客户端
将服务端AIDL文件拷贝到客户端相同包的位置,然后Sync Project。
注意:客户端和服务端AIDL的文件和路径要一致。
新建ClientAppliction类,这里演示在这里绑定服务端,简历进程通信。通过隐式意图来绑定service, ServiceConnection可以获取连接回调,有两个方法,onServiceConnected 连接成功,onServiceDisconnected连接失败,我们可以根据实际的需求在不同的方法里处理业务逻辑。
public class ClientAppliction extends Application {
private static Context sContext;
private static IAidlServiceInterface sIAidlServiceInterface;
@Override
public void onCreate() {
super.onCreate();
sContext = this;
bindService();
}
/**
* bind AIDL Service
*/
private void bindService() {
Intent intent = new Intent();
intent.setAction("com.fanxb.aidlserviceclient.service");
intent.setPackage("com.fanxb.aidlserviceclient");
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
}
/**
* Service Connection callback
*/
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
sIAidlServiceInterface = IAidlServiceInterface.Stub.asInterface(iBinder);
Log.i("===========>", "Server connected successfully!!!");
try {
String message = sIAidlServiceInterface.getMessages();
Log.i("===========>", "the message:" + message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
sIAidlServiceInterface = null;
}
};
public static Context getContext() {
return sContext;
}
public static void setContext(Context context) {
sContext = context;
}
public static IAidlServiceInterface getIAidlServiceInterface() {
return sIAidlServiceInterface;
}
public static void setIAidlServiceInterface(IAidlServiceInterface IAidlServiceInterface) {
sIAidlServiceInterface = IAidlServiceInterface;
}
}
在onServiceConnected方法中通过IAidlServiceInterface.Stub.asInterface(service)获取IAidlServiceInterface对象,然后在onClick中调用IAidlServiceInterface.getMessage()。
三、AIDL的进阶使用
客户端向服务端发送数据
在服务端的AIDL文件里添加void sendMessageToService(String message)方法,记得Sync Project
// IAidlServiceInterface.aidl
package com.fanxb.aidlserviceclient;
// Declare any non-default types here with import statements
interface IAidlServiceInterface {
String getMessages();
void sendMessageToService(String message);
}
在服务端的IAidlInterfaceImpl类里重写sendMessageToService方法,接收客户端消息。
public class IAidlInterfaceImpl extends IAidlServiceInterface.Stub {
@Override
public String getMessages() throws RemoteException {
return "This is the AIDL ServiceClient message!";
}
@Override
public void sendMessageToService(String message) throws RemoteException {
Log.i("===========>", "service receive :" + message);
}
}
在客户端的AIDL文件里添加和服务端相同的void sendMessageToService(String message)方法,记得Sync Project
// IAidlServiceInterface.aidl
package com.fanxb.aidlserviceclient;
// Declare any non-default types here with import statements
interface IAidlServiceInterface {
String getMessages();
void sendMessageToService(String message);
}
将ClientApplication 的绑定方法取消,在客户端的MainActivity类里添加四个按钮,分别为 bindServie、unbinService、getMessage、sendMessageToService四个点击事件。
绑定服务:
private void bindService() {
Intent intent = new Intent();
intent.setAction("com.fanxb.aidlserviceclient.service");
intent.setPackage("com.fanxb.aidlserviceclient");
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
}
/**
* Service Connection callback
*/
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
sIAidlServiceInterface = IAidlServiceInterface.Stub.asInterface(iBinder);
Log.i("===========>", "Server connected successfully!!!");
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.i("==============>", "onServiceDisconnected!!!");
sIAidlServiceInterface = null;
}
};
获取消息:
if (sIAidlServiceInterface != null) {
try {
String message = sIAidlServiceInterface.getMessages();
Log.i("============>", "client getMessage:" + message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
发送消息至服务端:
if (sIAidlServiceInterface != null) {
try {
sIAidlServiceInterface.sendMessageToService("this is client send message!!!");
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Log.i("============>", "sIAidlServiceInterface is null");
}
解绑:
if (sIAidlServiceInterface != null) {
unbindService(mServiceConnection);
sIAidlServiceInterface = null;
}
打印信息:
以上介绍的是正常情况下的操作,如果出现连接通信过程中,出现连接异常,断开了通信,如何操作呢?
四、Binder 死亡代理
Binder类中比较重要的两个方法linkToDeath和unlinkToDeath。Binder是运行在服务进程,若服务端进程因为某种原因“死亡”,那么Binder对象也将随之而去,因为Binder对象是寄宿在服务端进程中的,这个时候我们的远程调用将会失败,客户端进程的功能也将受到影响。Binder类提供linkToDeath方法在客户端可以设置死亡代理,当服务端的Binder对象“死亡”,客户端可以受到死亡通知,这个时候我们可以重新恢复链接。
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
sIAidlServiceInterface = IAidlServiceInterface.Stub.asInterface(iBinder);
Log.i("===========>", "Server connected successfully!!!");
try {
//设置Binder死亡代理
sIAidlServiceInterface.asBinder().linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.i("==============>", "onServiceDisconnected!!!");
}
};
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (null == sIAidlServiceInterface) {
return;
}
sIAidlServiceInterface.asBinder().unlinkToDeath(mDeathRecipient, 0);
sIAidlServiceInterface = null;
Log.i("========>", "开始重连!");
bindService();
}
};
五、callBack回调机制
当客户端向服务端发送消息后,希望得到服务端的结果返回,这里就需要建立callBack机制,实现双向通信。
在服务端AIDL文件夹下新建一个AIDL文件,用于定义回调接口,并声明onSuccess和onFailed方法,这两个方法是用于业务层的,比如服务端接收消息失败时调用onFailed,接收成功调用onSuccess。记得Sync Project
// IICallBackInterface.aidl
package com.fanxb.aidlserviceclient;
// Declare any non-default types here with import statements
interface ICallBackInterface {
void onSuccess(String result);
void onFailed(String errorMessage);
}
修改服务端IAidlServiceInterface文件,新增registerCallBack、unregisterCallBack两个方法,用于客户端注册回调和解除回调,记得Sync Project,同时需要import ICallBackInterface接口的包名。
// IAidlServiceInterface.aidl
package com.fanxb.aidlserviceclient;
// Declare any non-default types here with import statements
import com.fanxb.aidlserviceclient.ICallBackInterface;
interface IAidlServiceInterface {
String getMessages();
void sendMessageToService(String message);
void registerCallBack(ICallBackInterface callBackInterface);
void unregisterCallBack(ICallBackInterface callBackInterface);
}
在服务端的IAidlInterfaceImpl类里重写registerCallBack、unregisterCallBack两个方法,接收客户端注册回调和解除回调。
public class IAidlInterfaceImpl extends IAidlServiceInterface.Stub {
private RemoteCallbackList<ICallBackInterface> mCallbackList = new RemoteCallbackList<>();
@Override
public String getMessages() throws RemoteException {
return "This is the AIDL ServiceClient message!";
}
@Override
public void sendMessageToService(String message) throws RemoteException {
Log.i("===========>", "service receive :" + message);
if (TextUtils.isEmpty(message)) {
dispatchResult(false, "receive message failed, message isEmpty ");
} else {
String msg = message;
dispatchResult(true, "receive message successfully");
}
}
@Override
public void registerCallBack(ICallBackInterface callBackInterface) throws RemoteException {
if (callBackInterface != null) {
mCallbackList.register(callBackInterface);
}
}
@Override
public void unregisterCallBack(ICallBackInterface callBackInterface) throws RemoteException {
if (callBackInterface != null) {
mCallbackList.unregister(callBackInterface);
}
}
/**
* 结果分发
*
* @param result this is result
* @param msg this is msg
*/
private void dispatchResult(boolean result, String msg) {
int length = mCallbackList.beginBroadcast();
for (int i = 0; i < length; i++) {
ICallBackInterface callBackInterface = mCallbackList.getBroadcastItem(i);
try {
if (result) {
callBackInterface.onSuccess(msg);
} else {
callBackInterface.onFailed(msg);
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
mCallbackList.finishBroadcast();
}
}
在服务端的AIDL文件复制到客户端,记得Sync Project,在客户端里编辑callBack方法。
ICallBackInterface mICallBackInterface = new ICallBackInterface.Stub() {
@Override
public void onSuccess(String result) throws RemoteException {
}
@Override
public void onFailed(String errorMessage) throws RemoteException {
}
};
在绑定服务成功后注册callBack事件。
sIAidlServiceInterface.registerCallBack(mICallBackInterface);
取消注册callBack
@Override
protected void onDestroy() {
super.onDestroy();
if (null != sIAidlServiceInterface && sIAidlServiceInterface.asBinder().isBinderAlive()) {
try {
sIAidlServiceInterface.unregisterCallBack(mICallBackInterface);
unbindService(mServiceConnection);
sIAidlServiceInterface = null;
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
结尾:
好了小伙伴们,AIDL的完整使用就是这些了,完整代码地址如下,仅供大家下载参阅。
https://github.com/fanxingbin/MyAIDLDemo
注意事项:
Binder死亡代理只有在非正常断开的情况下才会生效;
每次修改AIDL文件必须Sync Project;
客户端和服务端AIDL文件必须使用同一个;
客户端和服务端AIDL包名路径必须一致;