写点什么

征服面试官系列: Binder 核心机制和进程间通信,你都理解了吗

用户头像
Android架构
关注
发布于: 刚刚

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


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


.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;

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
征服面试官系列: Binder 核心机制和进程间通信,你都理解了吗