AIDL (Android Interface Definition Language)是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。AIDL IPC机制是面向接口的,轻量级。它是使用代理类在客户端和实现端传递数据。
为了体现IPC进程见通信的效果,创建两个项目,一个作为服务器,一个作为客户端。工程如下是:AidlTypeClient和AidlTypeService。
基本数据类型调用:
客户端调用服务器端代码,然后在服务器端显示请求的数据信息!运行效果如下:
创建AIDL接口定义文件ITypeService.aidl:
package com.anhuioss.aidl; interface ITypeService { void basicTypes(int anInt, long aLong, char aChar, boolean aBoolean, float aFloat, double aDouble, String aString); }
实现接口:
public class TypeService extends Service {
private Handler mHandler = new Handler();
private ITypeService.Stub typeService = new ITypeService.Stub() {
@Override
public void basicTypes(final int anInt, final long aLong, final char aChar, final boolean aBoolean,
final float aFloat, final double aDouble, final String aString)
throws RemoteException {
mHandler.post(new Runnable() {
@Override
public void run() {
String text = "Int:" + anInt
+ "\nLong:" + aLong
+ "\nChar:" + aChar
+ "\nBoolean:" + aBoolean
+ "\nFloat:" + aFloat
+ "\nDouble:" + aDouble
+ "\nString:" + aString;
Toast.makeText(TypeService.this, text, Toast.LENGTH_SHORT).show();
}
});
}
};
@Override
public IBinder onBind(Intent intent) {
return typeService;
}
}
说明:
- mHandler用于开启新的线程做相关操作;
- onBind暴露接口给客户端;
服务器端需要把这个服务注册到系统中,所以在Manifest文件中给出如下形式的设置:
<service android:name=".TypeService" > <intent-filter > <action android:name="com.anhuioss.aidl.TYPE_SERVICE" > </action> </intent-filter> </service>
说明:
- TypeService是一个处理ITypeService相关逻辑的Service;
- action用于找到匹配的服务并做相关处理;
客户端需要做的是获得接口并调用相应方法。为了让客户端知道服务器端定义的接口,本示例中简单的把相关类复制到客户端中,然后引用,即把服务器端的ITypeService.java复制到客户端的相同包路径下。
客户端使用时,需要绑定服务,示例中是在onStart和onStop中分别做绑定和取消绑定的操作,如下:
@Override
protected void onStart() {
super.onStart();
bindService(new Intent("com.anhuioss.aidl.TYPE_SERVICE"), this, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
unbindService(this);
}
绑定后,需要在ServiceConnection中的onServiceConnected和onServiceDisconnected做相关操作,例如在onServiceConnected中获得远程服务的对象引用等。获得引用的代码如下:
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
typeService = ITypeService.Stub.asInterface(service);
}
而客户端的调用比较简单,示例中在一个方法中完成,如下:
private void callBaseType() {
try {
typeService.basicTypes(123, 123456, 'A', true, 123.456f, 123456.789d, "string");
} catch (RemoteException e) {
e.printStackTrace();
}
}
在aidl文件中,基本类型,如int, long, char, boolean, String, List, Map等,可以直接使用。其它类型需要实现了Parcelable protocol 以及按值传递的自定义类,必须要import 语句声明。
下面以传递一个Dog类为例,说明具体操作。Dog类的具体实现如下:
import android.os.Parcel;
import android.os.Parcelable;
public class Dog implements Parcelable {
private String name;
private int age;
private String color;
public static final Parcelable.Creator<Dog> CREATOR = new Creator<Dog>() {
@Override
public Dog[] newArray(int size) {
return new Dog[size];
}
@Override
public Dog createFromParcel(Parcel source) {
return new Dog(source);
}
};
public Dog(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
public Dog(Parcel pl) {
age = pl.readInt();
name = pl.readString();
color = pl.readString();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(age);
dest.writeString(name);
dest.writeString(color);
}
@Override
public String toString() {
return "{Name:" + name + " Age:" + age + " Color:" + color + "}";
}
}
为了在aidl中使用Dog类,需要使用aidl描述该类,如下:
parcelable Dog;
同时需要在ITypeService.aidl文件中添加和Dog相关的内容,如下:
package com.anhuioss.aidl;
import com.anhuioss.aidl.Dog;
interface ITypeService {
void basicTypes(int anInt, long aLong, char aChar, boolean aBoolean, float aFloat, double aDouble, String aString);
void objectType(in Dog aDog);
}
根据服务端代码提示,修改TypeService的代码,添加如下内容:
@Override
public void objectType(final Dog aDog) throws RemoteException {
mHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(TypeService.this, aDog.toString(), Toast.LENGTH_SHORT).show();
}
});
}
服务端完成,下面只要在客户端添加UI时间和相应的调用即可,如下:
private void callObjectType() {
try {
typeService.objectType(new Dog("Tom", 3, "WHITE"));
} catch (RemoteException e) {
e.printStackTrace();
}
}
上面的代码提示出错吧,原因是测试客户端的ITypeService.java不是最新的而且没有Dog类。跟新ITypeService.java文件,同时复制Dog类到客户端即可!运行效果如下:
上面的调用的返回类型是void,而返回类型是其它数据类型的调用方式基本一样,再次不再赘述!
看下效果,如下:
上述都是单方面调用,下面对操作中的回调做简要说明。之所以可以回调,是因为调用和被调用双方都可以直接或间接获得对方的引用,从而调用相应的方法。
为了完成回调,先在服务端添加一个新的接口定义ITypeServiceListener.aidl:
package com.anhuioss.aidl; interface ITypeServiceListener { void requestCompleted(String message); }
对于服务器而言,这个Listener仅仅是一个接口定义,而具体实现是不同客户端的职责,所以到此即可。为了让服务端可以获得Listener的引用,可以在服务进行连接时获得,故需要在ITypeService中添加一个方法用于实现这个关联,如下:
void request(ITypeServiceListener lintener);
服务端的修改到此已经结束,下面是对客户端的修改。同样,需要更新ITypeService.java文件,同时把服务端的ITypeServiceListener.java文件复制到客户端,下面就是实现客户端的Listener并暴露给服务端即可。
客户端的Listener实现如下:
private ITypeServiceListener.Stub typeServiceListener = new ITypeServiceListener.Stub() {
@Override
public void requestCompleted(String message) throws RemoteException {
Message msg = new Message();
Bundle data = new Bundle();
data.putString("data", message);
msg.setData(data);
mHandler.sendMessage(msg);
}
};
客户端暴露Listener的方法如下:
private void callBack() {
try {
typeService.request(typeServiceListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
好了,我们看看效果吧,如下:
--界面效果--
--服务端进行操作,客户端做其它操作--
--客户端完成操作,回调客户端代码--
多说一句:当然,使用AIDL在同一个APK中也是可以的,如果你原因!代码在附件,如果需要的话!:)
参考开发者网站:http://developer.android.com/guide/components/aidl.html