AIDL(Android Interface Definition Language ),可实现进程间的通信,并且允许多线程访问。(如果需要进程间通信,又不需要处理多线程访问,那么使用Messenger的方式更为合适),实现AIDL,需要以下几个步奏。
1.定义AIDL接口
AIDL接口使用后缀名为.aidl的文件来定义(例如创建一个IRemoteData.aidl),使用java语法来编写,在编译时,Android sdk工具会在/gen目录下生成一个java文件(IRemoteData.java),此文件内有一个静态内部抽象类Stub,继承了Binder类并实现了接口(IRemoteData)。它提供了一个asInterface(android.os.IBinder obj)把IBinder对象转换成我们声明的接口类型(实际上就是在Service端对Stub的实现)。
AIDL支持以下五种数据类型:java基本数据类型(int,char,boolean等),String,CharSequence,List和Map。如果你要在AIDL中使用其他数据类型,那么必须使用import导入,即使该类型和aidl处于同一包中。其次,所有非原始数据类型都必须指定参数方向,传入参数用关键字in表示,传出参数用out,传入传出参数用inout,基本数据类型都是传入值。
1 package com.young.testserver.aidl; 2 3 import com.young.testserver.aidl.Person; 4 5 interface IRemoteData { 6 int getRemoteData(); 7 void setRemoteData(int data); 8 9 Person getPerson(); 10 void setPerson(in Person person); 11 }
由于该aidl文件中使用了非原始数据类型Person,所以需要创建一个aidl文件对Person进行声明
1 package com.young.testserver.aidl; 2 3 parcelable Person;
2.创建服务端Service,将我们对AIDL接口的实现通过onBind()方法返出去。
1 public class AidlRemoteService extends Service { 2 3 // IRemoteData.Stub的具体实现 4 private class RemoteData extends IRemoteData.Stub { 5 int data; 6 Person person; 7 @Override 8 public int getRemoteData() throws RemoteException { 9 return data; 10 } 11 12 @Override 13 public void setRemoteData(int data) throws RemoteException { 14 this.data = data; 15 } 16 17 @Override 18 public Person getPerson() throws RemoteException { 19 return person; 20 } 21 22 @Override 23 public void setPerson(Person person) throws RemoteException { 24 this.person = person; 25 } 26 27 } 28 29 @Override 30 public IBinder onBind(Intent intent) { 31 // 将实现的IRemoteData.Stub类返出去,客户端可以使用Stub提供的asInterface获得 32 return new RemoteData(); 33 } 34 }
3.将服务端对应的aidl文件与java文件拷贝到客户端,在客户端绑定服务时,使用Stub类提供的asInterface获取服务端实现的接口类,然后使用这个已实现的接口类就可以调用AIDL中的函数。
1 public class AidlClientActivity extends Activity { 2 3 private static final String TAG = "--DEBUG--"; 4 5 private static final String BIND_ACTION = "com.young.server.START_AIDL_SERVICE"; 6 private Button mBindBtn; 7 8 @Override 9 protected void onCreate(Bundle savedInstanceState) { 10 super.onCreate(savedInstanceState); 11 setContentView(R.layout.activity_aidl_client); 12 13 mBindBtn = (Button) findViewById(R.id.bind_service); 14 mBindBtn.setOnClickListener(new OnClickListener() { 15 @Override 16 public void onClick(View v) { 17 bindService(new Intent(BIND_ACTION), conn, Context.BIND_AUTO_CREATE); 18 } 19 }); 20 } 21 22 private ServiceConnection conn = new ServiceConnection() { 23 24 @Override 25 public void onServiceDisconnected(ComponentName name) { 26 Log.v(TAG, "AIDL 服务已断开"); 27 } 28 29 @Override 30 public void onServiceConnected(ComponentName name, IBinder service) { 31 Log.v(TAG, "AIDL 服务已链接"); 32 33 // 获得服务端对Stub的实现 34 IRemoteData remoteData = IRemoteData.Stub.asInterface(service); 35 try { 36 remoteData.setRemoteData(123456); 37 int data = remoteData.getRemoteData(); 38 Log.v(TAG, "client get remote data=" + data); 39 40 remoteData.setPerson(new Person("Allen", 25)); 41 Person person = remoteData.getPerson(); 42 Log.v(TAG, "client get remote Person=" + person.toString()); 43 } catch (RemoteException e) { 44 e.printStackTrace(); 45 } 46 } 47 }; 48 }
4.通过AIDL在进程间传递对象,需要符合以下几点要求
(1)实现Parcelable接口。
(2)实现writeToParcel方法,以便将当前对象状态写入Parcel中。
(3)增加一个名为CREATOR的静态变量,实现Parcelable.Creator<T>接口
(4)创建一个AIDL文件来声明这个类(见上文的Person.aidl)
1 public class Person implements Parcelable { 2 3 private String name; 4 private int age; 5 6 public Person(String name, int age) { 7 super(); 8 this.name = name; 9 this.age = age; 10 } 11 12 public String getName() { 13 return name; 14 } 15 16 public void setName(String name) { 17 this.name = name; 18 } 19 20 public int getAge() { 21 return age; 22 } 23 24 public void setAge(int age) { 25 this.age = age; 26 } 27 28 @Override 29 public String toString() { 30 return "Person [name=" + name + ", age=" + age + "]"; 31 } 32 33 // -------------分割线--------------- 34 35 // 注意读入和写出顺序 36 public Person(Parcel parcel) { 37 name = parcel.readString(); 38 age = parcel.readInt(); 39 } 40 41 public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() { 42 43 @Override 44 public Person createFromParcel(Parcel source) { 45 return new Person(source); 46 } 47 48 @Override 49 public Person[] newArray(int size) { 50 return new Person[size]; 51 } 52 53 }; 54 55 @Override 56 public int describeContents() { 57 return 0; 58 } 59 60 @Override 61 public void writeToParcel(Parcel dest, int flags) { 62 dest.writeString(name); 63 dest.writeInt(age); 64 }
最后运行程序,打印日志结果如下,客户端取到了从客户端传给服务端的数据。
11-13 15:56:23.081: V/--DEBUG--(25361): AIDL 服务已链接
11-13 15:56:23.081: V/--DEBUG--(25361): client get remote data=123456
11-13 15:56:23.081: V/--DEBUG--(25361): client get remote Person=Person [name=Allen, age=25]