Android Interface Definition Language,简称AIDL,是Android接口定义语言,用于进程间通信。当然你也可以通过发送广播达到进程间通信的目的,但广播会碰到延迟等现象,个人建议还是使用AIDL。
AIDL传输数据支持Java基本数据类型、List、Map以及实现Parcelable的类。接下来将通过一个实例来讲解下AIDL,并支持双向传输,使用Android Studio开发。
AIDL有服务端和客户端,在服务端,我们先在aidl.com.android.demo路径下生成一个后缀为.aidl的DemoInfo.aidl文件,内容如下:
package com.android.demo;
parcelable DemoInfo;
里面不做什么,只是定义了一个序列化对象。这是到时候AIDL要传递的数据,我们在java.com.android.demo路径下生成DemoInfo.java去实现。
package com.android.demo;
import android.os.Parcel;
import android.os.Parcelable;
public class DemoInfo implements Parcelable {
private int mValue1 = -1;
private int mValue2 = -1;
public int getValue1() {
return mValue1;
}
public void setValue1(int mValue1) {
this.mValue1 = mValue1;
}
public int getValue2() {
return mValue2;
}
public void setValue2(int mValue2) {
this.mValue2 = mValue2;
}
@Override
public int describeContents() {
return 0;
}
public void readFromParcel(Parcel in) {
mValue1 = in.readInt();
mValue2 = in.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mValue1);
dest.writeInt(mValue2);
}
public static final Creator CREATOR = new Creator() {
@Override
public DemoInfo createFromParcel(Parcel source) {
DemoInfo mInfo = new DemoInfo();
mInfo.mValue1 = source.readInt();
mInfo.mValue2 = source.readInt();
return mInfo;
}
@Override
public DemoInfo[] newArray(int size) {
return new DemoInfo[size];
}
};
}
接下来,为了服务端也能向客户端传输数据,我们写个CallBack,供客户端去注册监听回调。在aidl.com.android.demo路径下生成一个后缀为.aidl的DemoCallBack.aidl文件。
package com.android.demo;
import com.android.demo.DemoInfo;
interface DemoCallback {
void sendCtrlData(in DemoInfo info);
}
因为是传递序列化参数,所以AIDL需要我们写明方向,总共有三种: in , out , inout 。in 表示数据由客户端流向服务端, out 表示数据由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。接下来我们再在aidl.com.android.demo路径下生成一个后缀为.aidl的DemoInterface.aidl文件,内容如下:
package com.android.demo;
import com.android.demo.DemoCallback;
interface DemoInterface {
void getResult(boolean bool);
void registListener(DemoCallback listener);
void unregistListener(DemoCallback listener);
}
里面写了供客户端传递数据、注册监听回调和释放监听回调的接口。接下来服务端要提供 IBinder供客户端连接,实现如下:
package com.android.demo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
public class AidlService extends Service {
private static AidlService mService = null;
private static RemoteCallbackList mListener=new RemoteCallbackList<>();
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
mListener.kill();
}
private DemoInterface.Stub stub = new DemoInterface.Stub() {
@Override
public void getResult(boolean bool) throws RemoteException {
Log.d("AidlService","getResult="+bool);
}
@Override
public void registListener(DemoCallback listener) throws RemoteException {
mListener.register(listener);
}
@Override
public void unregistListener(DemoCallback listener) throws RemoteException {
mListener.unregister(listener);
}
};
public static synchronized AidlService getInstance() {
if (mService == null) {
mService = new AidlService();
}
return mService ;
}
public static void notifyClient(DemoInfo mInfo) throws RemoteException {
int count = mListener.beginBroadcast();
for (int i = 0; i < count; i++) {
DemoCallback broadcastItem = mListener.getBroadcastItem(i);
if (broadcastItem != null) {
try {
//发往客户端
broadcastItem.sendCtrlData(mInfo);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//一定要记得finishBroadcast
mListener.finishBroadcast();
}
@Override
public IBinder onBind(Intent intent) {
return stub;
}
}
在AndroidManifest.xml中定义下:
里面的action是供客户端绑定时的Intent所要设置的action。至此,服务端的AIDL相关方面就写好了,现在我们的客户端要去连接服务端。首先要做的就是把服务端刚才写的那些.AIDL复制到客户端,客户端路径要与服务端一致,如服务端是aidl.com.android.demo,那么客户端也要是aidl.com.android.demo。然后实现序列化得DemoInfo.java也要复制到客户端相同位置。现在我们来做连接操作。
package com.android.clinet;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import com.android.demo.DemoCallback;
import com.android.demo.DemoInterface;
import com.android.demo.DemoInfo;
/**
* 服务绑定管理
*/
public class ServiceBindManage implements Handler.Callback{
private final static String TAG = ServiceBindManage.class.getSimpleName();
public static DemoInterface mManagerService = null;
//全局事件服务
private static ServiceBindManage mServiceBindManage = null;
private DemoCallback mListener=new DemoCallback.Stub(){
@Override
public void sendCtrlData(DemoInfo status) throws RemoteException {
Log.d(TAG,"mValue1="+status.getValue1()+",mValue2="+status.getValue2());
}
};
private ServiceConnection mConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.d(TAG, "onServiceConnected");
mManagerService = DemoInterface.Stub.asInterface(iBinder);
try {
mManagerService .registListener(mListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mManagerService.unregistListener(mListener);
mManagerService = null;
}
};
public static ServiceBindManage getInstance() {
if (mServiceBindManage == null) {
mServiceBindManage = new ServiceBindManage();
}
return mServiceBindManage;
}
public void bindService(Context ctx) {
Log.d(TAG, "bindService");
//绑定AIDL
bindAidlService("com.android.demo.aidl",mConn);
}
private void bindAidlService(String action, ServiceConnection connent) {
Log.d(TAG, "bindAidlService:Coon = " + connent);
Intent intent = new Intent();
intent.setAction(action);
//服务端包名
intent.setPackage("com.android.demo");
MyApplication.getInstance().bindService(intent, connent, Context.BIND_AUTO_CREATE);
}
public void unBindService(Context ctx) {
if(mManagerService != null){
MyApplication.getInstance().unbindService(mConn);
mManagerService = null;
}
}
}
我们要与服务端绑定AIDL的时候,就调用ServiceBindManage.getInstance().bindService(this);
不需要时,就调用ServiceBindManage.getInstance().unBindService(this);