征服面试官系列: Binder 核心机制和进程间通信,你都理解了吗
return true;
}
return super.onTransact(code, data, reply, flags);
}
}
上述代码将查询成绩的相关逻辑从 Service 搬到了 GradeBinder 中。因此,此时 Service 中只需要在 onBind 的时候返回 GradeBinder 的实例即可。代码如下:
public class GradeService extends Service {
public static final int REQUEST_CODE=1000;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new GradeBinder();
}
}
2.客户端代码优化
客户端优化的思路是在连接到远程服务时候实例化一个代理类,代理类持有 Binder,让代理类行使 Binder 的权利。首先来看代理类的代码实现:
public class BinderProxy implements IGradeInterface {
// 被代理的 Binder
private final IBinder mBinder;
// 私有化构造方法
private BinderProxy(IBinder binder) {
mBinder = binder;
}
// 通过 Binde 读取成绩
@Override
public int getStudentGrade(String name) {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
int grade = 0;
data.writeString(name);
try {
if (mBinder == null) {
throw new IllegalStateException("Need Bind Remote Server...");
}
mBinder.transact(REQUEST_CODE, data, reply, 0);
grade = reply.readInt();
} catch (RemoteException e) {
e.printStackTrace();
}
return grade;
}
// 实例化 Binder 代理类的对象
public static IGradeInterface asInterface(IBinder iBinder) {
if (iBinder == null) {
return null;
}
if (iBinder instanceof IGradeInterface) {
LogUtils.e("当前进程");
// 如果是同一个进程的请求,则直接返回 Binder
return (IGradeInterface) iBinder;
} else {
LogUtils.e("远程进程");
// 如果是跨进程查询则返回 Binder 的代理对象
return new BinderProxy(iBinder);
}
}
}
BinderProxy 类的构造方法被设置成了 private。同时提供了一个 asInterface 方法中,这个方法通过判断 Binder 是不是 IGradeInterface 类型从而确定是不是跨进程的通信。如果不是跨进程通信,则返回当前这个 Binder,否则就返回 Binder 的这个代理类。
接下来客户端连接上远程服务的时候使用 BinderProxy 获取 Binder 或者 BinderProxy 实例。代码如下:
public class BinderProxyActivity extends BaseViewBindingActivity<ActivityBinderBinding> {
// 此处可能是 BinderProxy 也可能是 GradeBinder
private IGradeInterface mBinderProxy;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
// 连接服务成功,根据是否跨进程获取 BinderProxy 或者 GradeBinder 实例
mBinderProxy = BinderProxy.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mBinderProxy = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding.btnBindService.setOnClickListener(view -> bindGradeService());
// 查询学生成绩点击事件,通过 mBinderProxy 查询成绩
binding.btnFindGrade.setOnClickListener(view -> ToastUtils.showShort("Anna grade is " + mBinderProxy.getStudentGrade("Anna")));
}
// 绑定服务
private void bindGradeService() {
String action = "android.intent.action.server.gradeservice";
Intent intent = new Intent(action);
intent.setPackage(getPackageName());
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
}
}
可以看到,此时的代码相比第一章的代码整洁了不少。但是,代码写起来似乎还没有第一章中的方便。主要是因为要我们增加一个 IGradeInterface 接口,还要自定义一个 GradeBinder,同时,还需要写代理类的相关代码,感觉非常繁琐。那么有没有办法让代码简洁,写起来还不繁琐呢?答案是肯定的,使用 AIDL 就可以实现。
四、AIDL
AIDL 是 Android Interface Description Languaged 简写。用于描写客户端/服务端通信接口的一种描述语言。提起 AIDL 相信很多人都会觉得头大,定义一个 AIDL 接口,生成了那么多不知所云的代码,看起来简直就是灾难。先别担心,如果你看懂了第三章的内容,那么其实你已经完全掌握了 AIDL。没错,说白了 AIDL 生成的那一坨代码其实就是我们第三章中写的代码。即 AIDL 的原理其实就是使用了代理模式对 Binder 的使用进行了优化,使用 AIDL 保证了代码的整洁,同时也省去了自己编写繁琐的代理类相关代码。
关于 AIDL 的使用就非常简单了。
1.创建 AIDL 接口
首先,在要创建 AIDL 的目录上右键->New->AIDL->AIDl File 来创建一个 AIDL 文件,如下图所示:
![](https://img-blog.csdnimg
.cn/img_convert/af028f7c18000b3c9e28f1fcc195ff52.png)
创建一个名为 IGradeService 的 AIDL 文件,并添加一个 getStudentGrade 的方法。代码如下:
// IGradeService.aidl
package com.zhpan.sample.binder.aidl;
// Declare any non-default types here with import statements
interface IGradeService {
/**
Demonstrates some basic types that you can use as parameters
and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
int getStudentGrade(String name);
}
接着 Rebuild 一下项目后 IDE 就会自动生成 AIDL 的代码了。
2.AIDL 生成的代码
在项目的 build 目录下 com.zhpan.sample.binder.aidl 包中会看到自动生成的一个名为 IGradeService 的接口,代码如下:
// 这个接口相当于上一章中的 IGradeInterface 接口
public interface IGradeService extends android.os.IInterface {
...
// Stub 是一个 Binder,相当于上一章中的 GradeBinder
public static abstract class Stub extends android.os.Binder
implements com.zhpan.sample.binder.aidl.IGradeService {
private static final java.lang.String DESCRIPTOR = "com.zhpan.sample.binder.aidl.IGradeService";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static IGradeService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.zhpan.sample.binder.aidl.IGradeService))) {
// 如果是当前进程则直接返回当前 Binder 对象
return ((com.zhpan.sample.binder.aidl.IGradeService) iin);
}
// 跨进程则返回 Binder 的代理对象
return new com.zhpan.sample.binder.aidl.IGradeService.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
throws android.os.RemoteException {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_basicTypes: {
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0 != data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
case TRANSACTION_getStudentGrade: {
data.enforceInterface(descriptor);
java.lang.String _arg0;
_arg0 = data.readString();
int _result = this.getStudentGrade(_arg0);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
// Binder 的代理类,相当于上一章中的 BinderProxy
private static class Proxy implements com.zhpan.sample.binder.aidl.IGradeService {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, java.lang.String aString) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean) ? (1) : (0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
boolean _status = mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().basicTypes(anInt, aLong, aBoolean, aFloat, aDouble, aString);
return;
}
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override public int getStudentGrade(java.lang.String name)
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(name);
boolean _status = mRemote.transact(Stub.TRANSACTION_getStudentGrade, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getStudentGrade(name);
}
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public static com.zhpan.sample.binder.aidl.IGradeService sDefaultImpl;
}
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getStudentGrade = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
public static boolean setDefaultImpl(com.zhpan.sample.binder.aidl.IGradeService impl) {
if (Stub.Proxy.sDefaultImpl == null && impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static com.zhpan.sample.binder.aidl.IGradeService getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
/**
Demonstrates some basic types that you can use as parameters
and return values in AIDL.
*/
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble,
java.lang.String aString) throws android.os.RemoteException;
public int getStudentGrade(java.lang.String name) throws android.os.RemoteException;
}
瞥一眼代码会发现 IGradeService 接口中有一个名为 Stub 的内部类,它继承了 Binder,并实现了 IGradeService 接口,并且它的内部有一个 asInterface 的方法,这个方法与我们上一章 BinderProxy 中的 asInterface 一致,只是写的位置不同而已。另外在 Stub 的 onTranscation 方法的 TRANSACTION_getStudentGrade 条件中的代码与 GradeBinder 的 onTranscation 方法代码是一样的。
接着,Stub 类中还有一个名为 Proxy 的内部类。Proxy 类与上一章的 BinderProxy 相对应。可以看到 Proxy 类的构造方法并没有修饰符,而 BinderProxy 的构造方法被声明成了 private,都可以防止外部通过构造方法区实例化代理类的对象。Proxy 的 getStudentGrade 方法与 BinderProxy 中的 getStudentGrade 一样,通过 Binder 去读取服务端的写入数据。
3.AIDL 客户端
使用 AIDL 的客户端实现几乎与第三章中的代码一致。只不过是在连接到服务端后通过 IGradeService.Stub 下的 asInterface 方法来获取 Binder 或者 Binder 的代理对象。代码如下:
public class AidlActivity extends BaseViewBindingActivity<ActivityBinderBinding> {
private IGradeService mBinderProxy;
评论