客户端demo:https://github.com/hewind/AidlClientTest
服务端demo:https://github.com/hewind/AidlServerTest
实现功能:增加人员、删除人员、获取人员信息;
一、客户端
1、创建PersonBean实体类
public class PersonBean implements Parcelable {
private String name;
public PersonBean(String name) {
this.name = name;
}
public String getName() {
return name == null ? "" : name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "PersonBean{" + "name='" + name + '\'' + '}';
}
protected PersonBean(Parcel in) {
name = in.readString();
}
public static final Creator<PersonBean> CREATOR = new Creator<PersonBean>() {
@Override
public PersonBean createFromParcel(Parcel in) {
return new PersonBean(in);
}
@Override
public PersonBean[] newArray(int size) {
return new PersonBean[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(name);
}
//删除使用
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj){//自反性
return true;
}
if (!(obj instanceof PersonBean)){//instanceof比较判断是否是同一类或者子父类关系
return false;
}
if (this.name.equals(((PersonBean) obj).getName())){//判断是同一类或者子父类关系,再将Object类型强转为Students
return true;
}
return false;
}
@Override
public int hashCode() {
return name.hashCode();
}
}
PersonBean实现Parcelable接口,目的为了跨进程传输,重写equals和hashCode方法目的为了使用删除;
2、创建PersonManagerInterface接口
public interface PersonManagerInterface extends IInterface {
//添加人数
void addPerson(PersonBean personBean) throws RemoteException;
//删除人数
void deletePerson(PersonBean personBean) throws RemoteException;
//获取人数
List<PersonBean> getPerson() throws RemoteException;
}
创建PersonManagerInterface接口,并实现IInterface接口,只有实现IInterface接口,才具备跨进程传输的基础能力,另外如果我们使用Android Studio自带的创建AIDL生成的aidl文件,也是继承了该IInterface接口,这里自己手动创建并继承效果是一样的。
3、创建Proxy代理类
public class Proxy implements PersonManagerInterface {
//远程binder对象
private IBinder iBinder;
//Binder ID
private static final String DESCRIPTOR = "com.example.aidlservertest.Proxy.PersonManagerInterface";
public Proxy(IBinder iBinder) {
this.iBinder = iBinder;
}
//增加人数实现
@Override
public void addPerson(PersonBean personBean) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel replay = Parcel.obtain();
try {
data.writeInterfaceToken(DESCRIPTOR);
if (personBean != null){
data.writeInt(1);
personBean.writeToParcel(data,0);
}else {
data.writeInt(0);
}
iBinder.transact(Stub.TRANSAVTION_addperson,data,replay,0);
replay.readException();
}finally {
replay.recycle();
data.recycle();
}
}
//删除人数实现
@Override
public void deletePerson(PersonBean personBean) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel replay = Parcel.obtain();
try {
data.writeInterfaceToken(DESCRIPTOR);
if (personBean != null){
data.writeInt(1);
personBean.writeToParcel(data,0);
}else {
data.writeInt(0);
}
iBinder.transact(Stub.TRANSAVTION_deleteperson,data,replay,0);
replay.readException();
}finally {
replay.recycle();
data.recycle();
}
}
//查询人数实现
@Override
public List<PersonBean> getPerson() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel replay = Parcel.obtain();
List<PersonBean> result;
try {
//写入一个校验
data.writeInterfaceToken(DESCRIPTOR);
//客户端调用到这个方法,走到iBinder.transact,此时会进入系统层处理,处理结果通过调用Stub的transact方法返回,系统层处理过程会阻塞在这行代码,直到处理完成,
iBinder.transact(Stub.TRANSAVTION_getpersons,data,replay,0);
//上面一行代码在系统处理成功后,返回结果,由于Stub的transact方法写入了一个【reply.writeNoException()】,这里reply进行读取异常
replay.readException();
//这里是Stub的transact方法处理返回的结果
result = replay.createTypedArrayList(PersonBean.CREATOR);
}finally {
replay.recycle();
data.recycle();
}
return result;
}
/**
* 方法说明:返回当前获取到的服务端的IBander
* 日期:2020-09-09 10:31
*/
@Override
public IBinder asBinder() {
return iBinder;
}
}
- Proxy在AIDL通信中承担着发送信息的角色;
- Proxy实现了PersonManagerInterface接口,同时实现asBinder方法,该方法返回一个iBinder对象,该iBinder对象由Stub类实例化Proxy并传入iBinder对象;
- DESCRIPTOR为BinderID,一般由包名+PersonManagerInterface组成;
- 获取人数信息getPerson方法中data为要传送的数据,reply为接收返回的数据;data.writeInterfaceToken(DESCRIPTOR)方法为写入binderID作为校验,服务端的Stub方法收到后也会进行一个校验;接下来开始调用iBinder的transact方法,该方法会直接进入系统层处理,最终会调用到Binder驱动,然后通过Binder调用服务端的Stub的ontTransact方法建立起一个完整的沟通机制;另外在调用该方法时系统会阻塞线程进入等待,直到返回处理结果;
4、创建Stub类
public abstract class Stub extends Binder implements PersonManagerInterface {
//Binder ID
private static final String DESCRIPTOR = "com.example.aidlservertest.Proxy.PersonManagerInterface";
public Stub() {
//attachInterface方法:向BinderService注册Binder服务。只有注册了binder,客户端才能查询到有这个binder对象,并使用它
this.attachInterface(this,DESCRIPTOR);
}
@Override
public IBinder asBinder() {
return this;
}
//将服务端的Binder对象准换成客户端所需要的AIDL接口对象,
public static PersonManagerInterface asInterface(IBinder iBinder){
if ((iBinder==null)) {
return null;
}
//查询当前进程,如果客户端和服务端位于同一进程,那么此方法返回的就是当前进程的Stub对象本身,否则返回服务端进程的Stub.proxy对象(服务端也有该Stub类)
IInterface iin = iBinder.queryLocalInterface(DESCRIPTOR);
if ((iin != null) && (iin instanceof PersonManagerInterface)) {
return (PersonManagerInterface)iin;
}
//返回服务端的Stub.proxy对象
return new Proxy(iBinder);
}
//这个方法运行在服务端中的Binder线程池当中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理。
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
switch (code){
case INTERFACE_TRANSACTION:
reply.writeString(DESCRIPTOR);
return true;
case TRANSAVTION_addperson://增加人数
//返回一个校验
data.enforceInterface(DESCRIPTOR);
PersonBean personBean = null;
if (data.readInt() != 0){
//读取PersonBean
personBean = PersonBean.CREATOR.createFromParcel(data);
}
//接口方法回调出去,这里最终会走到服务端的Service类的IBinder回调中
this.addPerson(personBean);
//返回一个无异常
reply.writeNoException();
return true;
case TRANSAVTION_deleteperson://删除人数
data.enforceInterface(DESCRIPTOR);
PersonBean personBean2 = null;
if (data.readInt() != 0){
personBean2 = PersonBean.CREATOR.createFromParcel(data);
}
this.deletePerson(personBean2);
reply.writeNoException();
return true;
case TRANSAVTION_getpersons://获取人数
data.enforceInterface(DESCRIPTOR);
List<PersonBean> result = this.getPerson();
reply.writeNoException();
reply.writeTypedList(result);
return true;
}
return super.onTransact(code, data, reply, flags);
}
//使用int型代替字符串传递来标识调用的是哪一个方法,属于性能优化
public static final int TRANSAVTION_getpersons = IBinder.FIRST_CALL_TRANSACTION;
public static final int TRANSAVTION_addperson = IBinder.FIRST_CALL_TRANSACTION + 1;
public static final int TRANSAVTION_deleteperson = IBinder.FIRST_CALL_TRANSACTION + 2;
}
- Stub在AIDL通信中承担着接收信息的角色;
- Stub类继承了Binder,同时实现了PersonManagerInterface接口;
- 无参构造器中,Stub类调用了一个attachInterface方法,传入了当前对象以及BinderID,该方法是向BinderService注册Binder服务,只有注册了Binder,客户端才能查询到这个Binder对象并使用它;
- asBinder方法返回的是当前对象,实际上跟Proxy中asBinder方法返回的是同一个Binder对象;
- asInterface方法是将服务端的BInder对象转换成客户端所需要的AIDL接口对象,iBinder.queryLocalInterface(DESCRIPTOR)方法会先查询一下本地进程的DESCRIPTOR是否为null,不为null的话就直接返回PersonManagerInterface接口对象;否则就实例化Proxy,并传入iBinder对象;
- onTransact方法即为BInder驱动处理后返回给服务端的出口,这个方法运行在服务端中的Binder线程池中,当客户端发起跨进程请求时,请求经过BInder处理,再交给该方法;
- 其中code参数为方法代理名称,使用数字来代替客户端想要调用的某个方法名,如果有多个方法名,会在IBinder.FIRST_CALL_TRANSACTION默认上进行加1,以此类推;
5、客户端绑定服务
public class MainActivity extends AppCompatActivity {
private Button button,button2,button3;
private TextView textView;
private PersonManagerInterface personManagerInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
prePareAidl();
textView = findViewById(R.id.textview);
button = findViewById(R.id.button);
button2 = findViewById(R.id.button2);
button3 = findViewById(R.id.button3);
//添加人员
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
PersonBean personBean = new PersonBean();
personBean.setName("张三");
try {
personManagerInterface.addPerson(personBean);
} catch (RemoteException e) {
e.printStackTrace();
}
getPerson();
}
});
//删除人员
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
PersonBean personBean = new PersonBean();
personBean.setName("张三");
try {
personManagerInterface.deletePerson(personBean);
} catch (RemoteException e) {
e.printStackTrace();
}
getPerson();
}
});
//获取人员
button3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getPerson();
}
});
}
/**
* 方法说明:获取Person人数
* 日期:2020-09-11 16:36
*/
private void getPerson() {
try {
List<PersonBean> list = personManagerInterface.getPerson();
String str = "";
for (PersonBean p:list){
str += p.getName()+", ";
}
textView.setText(str);
} catch (RemoteException e) {
e.printStackTrace();
}
}
/**
* 方法说明:通过绑定远程service,初始化远程iBinder实例
* 日期:2020-09-09 17:14
*/
private void prePareAidl() {
Intent intent = new Intent();
intent.setClassName("com.example.aidlservertest","com.example.aidlservertest.Service.PersonService");
bindService(intent,MyServerConnection, Context.BIND_AUTO_CREATE);
}
/**
* 方法说明:创建ServiceConnection
* 日期:2020-09-09 17:15
*/
private ServiceConnection MyServerConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
System.out.println("---客户端 建立服务链接; Thread: "+Thread.currentThread().getName());
//初始化远程iBinder实例,将iBinder转成远程服务代理对象,也就是PersonManagerProxy类对象,并调用它的方法
personManagerInterface = Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
System.out.println("---客户端 断开服务链接; Thread: "+Thread.currentThread().getName());
}
};
}
- 绑定服务中,Intent中传入的两个参数,一个是服务端的包名,一个是服务端Service的类路径;
- ServiceConnection类中onServiceConnected方法返回了一个iBinder对象,此时通过调用Stub.asInterface(iBinder)将iBInder转为服务端代理对象,也就是PersonManagerProxy接口实现类对象,并调用它的方法;
二、服务端
1、拷贝通信文件
将客户端的PersonManagerProxy、Proxy、Stub、PersonBean三个类,原封不动拷贝到服务端工程下,三个类所在目录也要同客户端一致;
2、创建Service
public class PersonService extends Service {
private List<PersonBean> list = new ArrayList<>();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("---服务端 onStartCommand; Thread: "+Thread.currentThread().getName());
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
System.out.println("---服务端 onBind; Thread: "+Thread.currentThread().getName());
return mIBinder;
}
/**
* 方法说明:
* 日期:2020-09-09 11:26
*/
private IBinder mIBinder = new Stub(){
@Override
public void addPerson(PersonBean personBean) throws RemoteException {
if (personBean != null){
list.add(personBean);
}
System.out.println("---服务端 addPerson; Thread: "+Thread.currentThread().getName()+", list: "+list);
}
@Override
public void deletePerson(PersonBean personBean) throws RemoteException {
list.remove(personBean);
System.out.println("---服务端 deletePerson; Thread: "+Thread.currentThread().getName()+", list: "+list);
}
@Override
public List<PersonBean> getPerson() throws RemoteException {
System.out.println("---服务端 getPerson; Thread: "+Thread.currentThread().getName()+", list: "+list);
return list;
}
};
}
- Service类中的onBind方法返回了一个IBinder对象,这里在Service类中实例化一个Stub对象,因为Stub继承了Binder,同时实现增加、删除、查询方法,在这三个方法中进行实现相应的功能,客户端通过Proxy——>Binder.transact——>Binder驱动——>服务端Stub.onTransact——服务端new Stub;形成一个完整的通信机制
3、服务端开启服务
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this, PersonService.class));
}
}
使用startService开启服务;
4、注册服务
<service android:name="com.example.aidlservertest.Service.PersonService"
android:enabled="true"
android:exported="true"/>
到此整个手动创建AIDL工程已经结束,测试的时候,需要先运行服务端,再运行客户端;