AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言。 AIDL 在Android中有着广泛的应用,是IPC中最常用的通信方式。它分为了 客户端(client) 和 服务端(sever), 可以完成数据的双向通信,数据包括了常规数据类型和自定义类(其中自定义类需要进行序列化)。下面主要介绍了 AIDL的应用, 客户端如何和远程服务端进行双向通信,和传输数据。
AIDL主要步骤:
服务端:
- 创建AIDL接口,如果需要传输自定义类,还需要对该类进行序列化,一般可以使用 parcelable对象进行序列化;如果服务端到客户端也需要回调通信,则此回调也需要一个aidl接口;
- 在服务端中创建一个类(binder)继承自ADIL接口中的Stub类并实现Stub中的抽象方法;
- 在onbind() 方法中返回这个类的对象;
客户端:
- 把编写的aidl目录和目录下的所有文件拷贝到客户端的main文件夹下,在实际应用规划总通常会将aidl接口(包括自定义类,生成的stub类)打成jar包,供服务端和所有客户端使用;
- 创建ServiceConnection,绑定服务端时获取服务端的对象。如果有回调接口,则还需实现回调接口类;
- 隐式启动服务端Service,开始获取服务端数据;
直接上个栗子:
服务端:
- 在 服务端工程中创建了 aidl接口,和自定义类,如下:
ITestInterface.aidl
package com.example.aidlserver.aidl;
import android.os.Parcel;
import android.os.Parcelable;
import com.example.aidlserver.aidl.ITestCallback;
import com.example.aidlserver.bean.TestInfo;
interface ITestInterface {
void registerCallback(ITestCallback callback);
void unRegisterCallback(ITestCallback callback);
TestInfo getTestInfo();
void setTestType(int type);
}
ITestCallback.aidl
package com.example.aidlserver.aidl;
interface ITestCallback {
void onStatuChanged(int type, String arg0, String arg1);
}
2. 自定义类序列化:
如果你有一个类需要跨进程进行传输,你必须保证这个类实现了Parcelable接口并且在IPC的另外一端也有这个类。
为了创建一个支持Parcelable协议的类,必须做下面工作:
- 保证你的类实现Parcelable接口
- 实现writeToParce() 和 describeContents() 方法,writeToParce()方法将得到当前对象的状态,然后写入Parcel;
- 给类增加一个叫做CREATOR的静态常量,这个静态常量实现了Parcelable.Creator接口,AIDL使用以上这些方法和域实现对象的序列化和反序列化
- 最后,如果在AIDL中用到了这个自定义的类,那么必须创建一个和它同名的.aidl文件,并在其中这个类为Parcelable类型,如下所示,创建了一个TestInfo.aidl文件,在这个文件中声明了TestInfo为Parcelable类型。
TestInfo.java 自定义类
package com.example.aidlserver.bean;
import android.os.Parcel;
import android.os.Parcelable;
public class TestInfo implements Parcelable {
private int mType;
private String mMessage;
public TestInfo() {
}
public void setType(int type) {
this.mType = type;
}
public int getType() {
return this.mType;
}
public void setMessage(String message) {
this.mMessage = message;
}
public String getMessage() {
return this.mMessage;
}
private TestInfo(Parcel source) {
readParcelInfo(source);
}
public static final Parcelable.Creator<TestInfo> CREATOR = new Parcelable.Creator<TestInfo>() {
@Override
public TestInfo createFromParcel(Parcel arg0) {
// TODO Auto-generated method stub
return new TestInfo(arg0);
}
@Override
public TestInfo[] newArray(int arg0) {
// TODO Auto-generated method stub
return new TestInfo[arg0];
}
};
@Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
//写入到parcel
@Override
public void writeToParcel(Parcel arg0, int arg1) {
// TODO Auto-generated method stub
arg0.writeInt(mType);
arg0.writeString(mMessage);
}
private void readParcelInfo(Parcel source) {
mType = source.readInt();
mMessage = source.readString();
}
}
TestInfo.aidl 同目录下:
package com.example.aidlserver.bean;
// 声明为 parcelable 类
parcelable TestInfo;
3.在服务端实现 aidl接口
AidlTestService.java 在onBind 中返回实现接口的对象(此处注意和本地client进行区分);
package com.example.aidlserver;
import com.example.aidlserver.aidl.ITestCallback;
import com.example.aidlserver.aidl.ITestInterface;
import com.example.aidlserver.bean.TestInfo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
public class AidlTestService extends Service {
private static final String TAG = "AidlTestService";
final RemoteCallbackList<ITestCallback> mOtherAppCallback = new RemoteCallbackList <ITestCallback>();
@Override
public IBinder onBind(Intent arg0) {
if (arg0.getAction() != null && arg0.getAction().equals("android.intent.action.aidl")) {
return testInterface; // 通过Action 辨别是否是哪一个服务端
} else {
return new Binder(); // 返回给同进程的服务端
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
return super.onStartCommand(intent, flags, startId);
}
public class Binder extends android.os.Binder {
public AidlTestService getService() {
return AidlTestService.this;
}
}
public void refreshInfo() {
Log.i(TAG, "refreshInfo");
}
// 回调,google推荐写法,可以一个 service 对多个 client端
private void onCallbackMsg(int type, String arg0, String arg1) {
final int N = mOtherAppCallback.beginBroadcast();
for (int i=0; i<N; i++) {
try {
mOtherAppCallback.getBroadcastItem(i).onStatuChanged(type, arg0, arg1);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
mOtherAppCallback.finishBroadcast();
}
ITestInterface.Stub testInterface = new ITestInterface.Stub() {
@Override
public void unRegisterCallback(ITestCallback callback)
throws RemoteException {
// TODO Auto-generated method stub
if (callback != null) {
mOtherAppCallback.register(callback);
}
}
@Override
public void setTestType(int type) throws RemoteException {
// TODO Auto-generated method stub
Log.d(TAG, "setTestType " + type);
}
@Override
public void registerCallback(ITestCallback callback) throws RemoteException {
// TODO Auto-generated method stub
if (callback != null) {
mOtherAppCallback.unregister(callback);
}
}
@Override
public TestInfo getTestInfo() throws RemoteException {
// TODO Auto-generated method stub
Log.d(TAG, "getTestInfo");
TestInfo info = new TestInfo();
info.setMessage("testInfo");
info.setType(100);
return info;
}
};
}
4.将aidl接口打成jar包,给服务端使用。 也可以将整个aidl包复制到服务端(目录和文件名都不能更改)。如下是通过eclipse工具进行打包的。
5.服务端:
实现ServiceConnection 和 回调接口,binder成功后,即可拿到远程服务端对象。
MainActivity.java
public class MainActivity extends Activity {
private static final String TAG = "Client Activity";
private Button mBtnBinder;
private Button mBtnStop;
private Button mBtnTest1;
private Button mBtnTest2;
private ITestInterface mInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mBtnBinder = (Button) findViewById(R.id.btn_binder);
mBtnStop = (Button) findViewById(R.id.btn_stop);
mBtnTest1 = (Button) findViewById(R.id.btn_test1);
mBtnTest2 = (Button) findViewById(R.id.btn_test2);
mBtnBinder.setOnClickListener(listener);
mBtnStop.setOnClickListener(listener);
mBtnTest1.setOnClickListener(listener);
mBtnTest2.setOnClickListener(listener);
}
private View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
switch (arg0.getId()) {
case R.id.btn_binder:
binderService();
break;
case R.id.btn_stop:
unbinderService();
break;
case R.id.btn_test1:
test1();
break;
case R.id.btn_test2:
test2();
break;
default:
break;
}
}
};
private void binderService() {
Log.i(TAG, "binderService");
Intent intent = new Intent();
intent.setAction("android.intent.action.aidl"); //通过aciton, binder AidlService
this.bindService(intent, connection, BIND_AUTO_CREATE);
}
private void unbinderService() {
this.unbindService(connection);
}
private void test1() {
if (mInterface != null) {
Log.d(TAG, "test1");
try {
mInterface.setTestType(1);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void test2() {
if (mInterface != null) {
Log.d(TAG, "test2");
TestInfo info = new TestInfo();
try {
info = mInterface.getTestInfo();
Log.i(TAG, "testinfo " + info.getMessage() + " type: " + info.getType());
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName arg0) {
// TODO Auto-generated method stub
Log.d(TAG, "onServiceDisconnected");
}
@Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
// TODO Auto-generated method stub
Log.d(TAG, "onServiceConnected");
mInterface = ITestInterface.Stub.asInterface(arg1);
}
};
// service的回调实现
private ITestCallback.Stub callback = new ITestCallback.Stub() {
@Override
public void onStatuChanged(int arg0, String arg1, String arg2)
throws RemoteException {
// TODO Auto-generated method stub
}
};
}
6.测试: client -> service 端调用成功;
service -> client 端回调成功;