上一篇说了kotlin如何使用AIDL进行跨进程通信,这篇文章是对上一篇文章的补充和深入,主要研究依赖AIDL生成的Java文件写了什么。
先附上之前的实体类文件
package com.example.com.testapplication.bean.kotlin
import android.annotation.SuppressLint
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize
@SuppressLint("ParcelCreator")
class Person(var name: String) : Parcelable {
override fun toString(): String {
return " [Person name = " + name + " ]"
}
}
package com.example.com.testapplication.aidl;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.example.com.testapplication.bean.kotlin.Person;
import java.util.List;
public interface IMyAidl extends IInterface {
void addPerson(com.example.com.testapplication.bean.kotlin.Person person) throws android.os.RemoteException;
java.util.List getPersonList() throws android.os.RemoteException;
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends Binder implements IMyAidl {
private static final String DESCRIPTOR = "com.example.com.testapplication.IMyAidl";
static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.com.testapplication.IMyAidl interface,
* generating a proxy if needed.
*/
public static com.example.com.testapplication.aidl.IMyAidl asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.com.testapplication.aidl.IMyAidl))) {
return ((com.example.com.testapplication.aidl.IMyAidl) iin);
}
return new com.example.com.testapplication.aidl.IMyAidl.Stub.Proxy(obj);
}
@Override
public IBinder asBinder() {
return this;
}
/**
* 返回true则代表访问成功,返回失败则代表访问失败
*
* @param code
* @param data
* @param reply
* @param flags
* @return
* @throws RemoteException
*/
@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 TRANSACTION_addPerson:
data.enforceInterface(DESCRIPTOR);
Person arg0;
if (0 != data.readInt()) {
arg0 = (Person) Person.CREATOR.createFromParcel(data);
} else {
arg0 = null;
}
this.addPerson(arg0);
reply.writeNoException();
return true;
case TRANSACTION_getPersonList:
data.enforceInterface(DESCRIPTOR);
List result = getPersonList();
reply.writeNoException();
reply.writeTypedList(result);
return true;
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements IMyAidl {
private IBinder mRemote;
public Proxy(IBinder mRemote) {
this.mRemote = mRemote;
}
@Override
public IBinder asBinder() {
return mRemote;
}
public String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public void addPerson(Person person) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(DESCRIPTOR);
if (null != person) {
data.writeInt(1);
person.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
mRemote.transact(TRANSACTION_addPerson, data, reply, 0);
reply.readException();
} finally {
data.recycle();
reply.recycle();
}
}
@Override
public List getPersonList() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
List result;
try {
data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(TRANSACTION_getPersonList, data, reply, 0);
reply.readException();
result = reply.createTypedArrayList(Person.CREATOR);
} finally {
data.recycle();
reply.recycle();
}
return result;
}
}
}
}
上面是经过整理的生成的Java文件,看上面的代码其实还不够简洁,咱们来拆分一下,上面的文件中有三个类,IMyAidl、Stub、Proxy,我们将这三个类分别写入一个单独的文件。
package com.example.com.testapplication.aidl;
import android.os.IInterface;
public interface IMyAidl extends IInterface {
void addPerson(com.example.com.testapplication.bean.kotlin.Person person) throws android.os.RemoteException;
java.util.List getPersonList() throws android.os.RemoteException;
}
package com.example.com.testapplication.aidl;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.example.com.testapplication.bean.kotlin.Person;
import java.util.List;
/**
* Local-side IPC implementation stub class.
*/
public abstract class Stub extends Binder implements IMyAidl {
static final String DESCRIPTOR = "com.example.com.testapplication.IMyAidl";
static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.com.testapplication.IMyAidl interface,
* generating a proxy if needed.
*/
public static com.example.com.testapplication.aidl.IMyAidl asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.com.testapplication.aidl.IMyAidl))) {
return ((com.example.com.testapplication.aidl.IMyAidl) iin);
}
return new Proxy(obj);
}
@Override
public IBinder asBinder() {
return this;
}
/**
* 返回true则代表访问成功,返回失败则代表访问失败
*
* @param code
* @param data
* @param reply
* @param flags
* @return
* @throws RemoteException
*/
@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 TRANSACTION_addPerson:
data.enforceInterface(DESCRIPTOR);
Person arg0;
if (0 != data.readInt()) {
arg0 = (Person) Person.CREATOR.createFromParcel(data);
} else {
arg0 = null;
}
this.addPerson(arg0);
reply.writeNoException();
return true;
case TRANSACTION_getPersonList:
data.enforceInterface(DESCRIPTOR);
List result = getPersonList();
reply.writeNoException();
reply.writeTypedList(result);
return true;
}
return super.onTransact(code, data, reply, flags);
}
}
package com.example.com.testapplication.aidl;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import com.example.com.testapplication.bean.kotlin.Person;
import java.util.List;
import static com.example.com.testapplication.aidl.Stub.DESCRIPTOR;
import static com.example.com.testapplication.aidl.Stub.TRANSACTION_addPerson;
import static com.example.com.testapplication.aidl.Stub.TRANSACTION_getPersonList;
public class Proxy implements IMyAidl {
private IBinder mRemote;
public Proxy(IBinder mRemote) {
this.mRemote = mRemote;
}
@Override
public IBinder asBinder() {
return mRemote;
}
public String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public void addPerson(Person person) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(DESCRIPTOR);
if (null != person) {
data.writeInt(1);
person.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
mRemote.transact(TRANSACTION_addPerson, data, reply, 0);
reply.readException();
} finally {
data.recycle();
reply.recycle();
}
}
@Override
public List getPersonList() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
List result;
try {
data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(TRANSACTION_getPersonList, data, reply, 0);
reply.readException();
result = reply.createTypedArrayList(Person.CREATOR);
} finally {
data.recycle();
reply.recycle();
}
return result;
}
}
通过上面拆分出来的三个类我们能看明白,定义了一个拥有Person类中方法名一样的接口类IMyAidl,一个继承Binder实现了IMyAidl接口的抽象类Stub,一个实现了IMyAidl接口的具体实现类Proxy。
IMyAidl继承IInterface接口,规范接口方法。
Stub这个类是重点,我们看到它继承Binder类就知道使用的是Binder机制。其中有下面几个方法
构造方法,内部调用Binder的attachInterface(IInterface owner, String descriptor)方法将Stub当前类和描述写入Binder父类
我们先来看一下这个方法的注释
/**
* Cast an IBinder object into an com.example.com.testapplication.IMyAidl interface,
* generating a proxy if needed.
*/
可以看到这个方法是将参数传进来的IBinder转成我们定义的接口类,如果需要的话创建代理类。那么什么是需要的时候通常来说非本应用访问就属于需要的时候。
这个类主要也是实现了注释所说的功能,第一步为空判断,判断传进来的参数是否为空不为空的话继续否则退出,第二步查询接口,通过构造方法中attachInterface传入的说明使用Binder的queryLocalInterface方法查询接口,第三步接口转换,查询接口不为空并且是定义的IMyAidl接口类的话就将查询到的接口强转成IMyAidl接口并返回,第四步启动代理,如果第三步判断没有通过则创建Proxy类启动代理模式。
其实呢,这个方法是AIDL为我们生成的,如果我们有其他操作,改变这个方法甚至不要这个方法也是没有问题的,具体的就看你的需求了。
这个方法是属于IInterface接口类的,IInterface接口类是使用Binder时必须要继承的类
我们同样先看一下注释
/**
* Retrieve the Binder object associated with this interface.
* You must use this instead of a plain cast, so that proxy objects
* can return the correct result.
*/
检索与此接口关联的绑定器对象。必须实现这个对象而不能强制转换,否则代理对象会出现返回对象不正确的情况。
注释写的云里雾里的,并没有说这个方法怎么用,只是说了必须用它。那么我们看一下这个方法的返回值,IBinder,对照上面的asInterface方法,我们可以知道asBinder方法是将实现了IInterface接口的类转成IBinder接口。
同样我们来看下注释
/**
* Default implementation is a stub that returns false. You will want
* to override this to do the appropriate unmarshalling of transactions.
*
* If you want to call this, call transact().
*/
此方法默认返回false,如果你想实现自定义的逻辑需要重写这个方法进行事务处理,这个方法的触发需要调用transact()方法。也就是说这个方法是用来处理我们自定义的事务的,我们自定义的事务是什么,在此篇文章中就是IMyAidl接口的方法。
这个方法在同一进程内通信时不会执行,只有当不同进程间通信时才会执行。
跟Stub实现的功能差不多,但是它是功能代理类,内部持有一个IBinder代理对象,asBinder方法返回的是持有的代理对象。
它拥有方法
构造方法,参数为传入的IBinder对象。
返回持有的IBinder对象
返回接口的说明
IMyAidl接口需要实现的方法,具体逻辑看编写,编写方法将在下篇文章进行讲解
IMyAidl接口需要实现的方法,具体逻辑看编写,编写方法将在下篇文章进行讲解
至此,AIDL自动生成的Java文件中的三个类就已经分析完了,之后的文章将讲解Binder机制和Parcel