首先创建一个User.java文件,实现Parcelable接口以用来进程间的对象传递
package com.example.aidl;
import android.os.Parcel;
import android.os.Parcelable;
public class User implements Parcelable{
private String username;
private String password;
public User(){
}
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(username);
dest.writeString(password);
}
public static final Parcelable.Creator<User> CREATOR = new Creator<User>() {
@Override
public User[] newArray(int size) {
return new User[size];
}
@Override
public User createFromParcel(Parcel source) {
return new User(source);
}
};
private User(Parcel source){
username = source.readString();
password = source.readString();
}
@Override
public String toString() {
return username + "-" +password;
}
}
然后创建User.aidl文件,声明User对象。如果AIDL中用到了自定义的Parcelable对象,一定要创建与之同名的aidl文件,并对它进行声明。
package com.example.aidl;
import com.example.aidl.User;
parcelable User;
parcelable User是对User对象的声明,它的类型是parcelable,不管User.java和User.aidl在没在一个包中,都要导包import com.example.aidl.User。
最后暴露客户端需要的方法接口IUserManager.aidl
package com.example.aidl;
import com.example.aidl.User;
interface IUserManager{
List<User> findUser();
void addUser(in User user);
}
这里具体说明一下AIDL中支持的数据类型
1、基本数据类型
2、String
3、List中的ArrayList,当然ArrayList中的元素也要是AIDL中支持数据类型
4、Map中的HashMap,当然key和value也要是AIDL中支持数据类型
5、Parcelable
6、AIDL接口本身
在IUserManager.aidl中我们暴露了两个方法给客户端,方法的定义与普通的接口基本一致,但是如果该方法有参数,参数除了基本数据类型,其他类型都要加in、out、inout,in表示输入型参数,out表示输出型参数,inout表示输入输出型参数。
当客户端是其它应用时,只需将aidl包完整拷入客户端程序即可,所以我们为了方便、不出错,将aidl相关的放入一个包下,这是符合开发规范的。
当IUserManager.aidl文件写完时,gen目录下会出现IUserManager.java文件。本文暂不对IUserManager.java进行深究,先讨论用法,下文对此进行深究。
此时创建远程Service,
private CopyOnWriteArrayList<User> users = new CopyOnWriteArrayList<User>();
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private Binder mBinder = new IUserManager.Stub() {
@Override
public List<User> findUser() throws RemoteException {
return users;
}
@Override
public void addUser(User user) throws RemoteException {
if(!users.contains(user)){
users.add(user);
}
}
}
创建IUserManager的静态内部类Stub对象作为Binder对象返回给绑定Service的Binder,并且实现接口中的两个方法给客户端调用。
客户端需要做的就是绑定此Service,即可调用服务端暴露给客户端的方法。
Intent intent = new Intent();
intent.setClass(MainActivity.this, AIDLService.class);
bindService(intent, connAIDL, Context.BIND_AUTO_CREATE);
connAIDL
private ServiceConnection connAIDL = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
userManager = IUserManager.Stub.asInterface(service);
try {
List<com.example.aidl.User> users = userManager.findUser();
System.out.println(users);
userManager.addUser(new com.example.aidl.User("wangwu", "789"));
users = userManager.findUser();
System.out.println(users);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
userManager = IUserManager.Stub.asInterface(service)是以绑定的Service返回的Binder对象创建IUserManager对象,该对象便可调用服务端暴露给客户端的方法。
userManager.findUser();
userManager.addUser(new com.example.aidl.User(“wangwu”, “789”));
注意:客户端调用服务端暴露的方法时,客户端线程会挂起,等待服务端方法运行,服务端的方法是运行在Binder线程池中的,因此不需要对这些方法开新的子线程异步执行,服务端方法运行结束时,返回给客户端,客户端线程才能继续运行。所以一旦服务端的方法需要长时间时,客户端必须在子线程中调用,防止ANR。