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