最近温习了AIDL的相关知识,写在这里,记录下来.
首先,先说下跨进程通信的方式有哪些。进程间的通信我们可以使用Messenger,可以在Intent中附加extras来传递信息,或者通过共享文件的方式来共享数据,还可以使用Binder方式来跨进程通信,也可以使用ContentProvider来进行跨进程的数据传递,通过网络的话使用socket也可以实现跨进程通信。
本章博客主要使用AIDL这种方式来进行进程间的通信,AIDL可以处理大量的并发请求,这是通过Messenger不能实现的。Messenger主要是为了传递信息的,如果调用服务端的方法的话,它也是不能做到的。但是可以使用AIDL来调用服务端的方法。
步骤:
1.服务端:
建立一个Service来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现这个AIDL接口即可。
2.客户端:
通过bindService()绑定客户端,将服务端返回的Binder对象转化成AIDL接口所属的类型,就可以在客户端调用AIDL中的方法了。
3.创建AIDL文件:
AIDL文件支持的数据类型:
基本数据类型、
String和CharSequence、
List:只支持ArrayList、
Map:只支持HashMap
parcelable:所有实现了parcelable接口的对象、
AIDL:所有AIDL接口本身也可以在AIDL文件中使用
注:如果AIDL文件中用到了自定义的parcelable对象,那么,必须新建一个和它同名的AIDL文件,并在其中声明它为parcelable类型
具体实现:
创建bean类
package org.superzhao.aidltest;
import android.os.Parcel;
import android.os.Parcelable;
public class User implements Parcelable {
private int userid;
private String username;
public User(int userid, String username) {
this.userid = userid;
this.username = username;
}
protected User(Parcel in) {
userid = in.readInt();
username = in.readString();
}
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(userid);
dest.writeString(username);
}
@Override
public String toString() {
return "userid:" + userid + ", username:" + username;
}
}
创建AIDL文件:
IUserManager.aidl
// IUserManager.aidl
package org.superzhao.aidltest;
// Declare any non-default types here with import statements
import org.superzhao.aidltest.User;
interface IUserManager {
List<User> getUserList();
void addUser(in User user);
}
user.aidl
// User.aidl
package org.superzhao.aidltest;
parcelable User;
注:在创建完成aidl文件后,记得点击同步按钮或者clean project,否则在service端不能调用aidl中的方法,因为找不到。
Service端的实现:
package org.superzhao.aidltest;
public class UserManagerService extends Service {
private static final String TAG = "UMS";
//在这个boolean值变化期间,不允许任何的插入操作,保持操作的原子性
private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false);
//CopyOnWriteArrayList是支持并发读写的List,自动进行线程同步
private CopyOnWriteArrayList<User> mUserList = new CopyOnWriteArrayList();
private CopyOnWriteArrayList<IOnNewUserArrivedListener> mListenerList = new CopyOnWriteArrayList();
@Override
public void onCreate() {
super.onCreate();
mUserList.add(new User(1,"jobs"));
mUserList.add(new User(2,"Mike"));
}
//实现Stub中的抽象方法
private Binder mBinder = new IUserManager.Stub(){
//返回所有的用户
@Override
public List<User> getUserList() throws RemoteException {
return mUserList;
}
//添加用户
@Override
public void addUser(User user) throws RemoteException {
mUserList.add(user);
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
注:AIDL方法实在服务端的Binder线程池中执行的,因此当多个客户端同时连接的时候,会存在多个线程同时访问的情形,所以要在AIDL方法中处理线程同步,CopyOnWriteArrayList可以进行自动的线程同步。
客户端的实现:
package org.superzhao.aidltest;
public class UserManagerActivity extends Activity {
private static final String TAG = "UMA";
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IUserManager userManager = IUserManager.Stub.asInterface(service);
try {
mRemoteUserManager = userManager;
List<User> list = userManager.getUserList();
Log.i(TAG,"query list" + list.getClass().getCanonicalName());
Log.i(TAG,"query User list" + list.toString());
User user = new User(3,"Tom");
userManager.addUser(user);
List<User> newList = userManager.getUserList();
Log.i(TAG,"query User newList" + newList.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name)
{
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,UserManagerService.class);
bindService(intent,mConnection,BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
}
总结一下:
使用AIDL的大致流程:
首先创建一个Service和一个AIDL接口,接着创建一个类继承自AIDL接口中的Stub类并实现Stub中的抽象方法,在Service的onBind方法中返回这个类的对象,然后客户端就可以绑定服务端的Service,建立连接后就可以访问远程服务端的方法了。