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

@Override

public int getStudentGrade(String name) {

return StudentMap.getStudentGrade(name);

}

@Override

protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {

if (code == REQUEST_CODE) {

String name = data.readString();

int studentGrade = getStudentGrade(name);

if (reply != null)

reply.writeInt(studentGrade);

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 {

// 此处可能是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文件,如下图所示:

创建一个名为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 {

private IGradeService mBinderProxy;

private final ServiceConnection mServiceConnection = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

// 连接服务后,根据是否跨进程获取Binder或者Binder的代理对象

mBinderProxy = IGradeService.Stub.asInterface(iBinder);

}

@Override

public void onServiceDisconnected(ComponentName componentName) {

mBinderProxy = null;

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

binding.btnBindService.setOnClickListener(view -> bindGradeService());

// 查询学生成绩

binding.btnFindGrade.setOnClickListener(view -> getStudentGrade(“Anna”));

}

// 绑定服务

private void bindGradeService() {

String action = “android.intent.action.server.aidl.gradeservice”;

Intent intent = new Intent(action);

intent.setPackage(getPackageName());

bindService(intent, mServiceConnection, BIND_AUTO_CREATE);

}

// 查询成绩

private void getStudentGrade(String name) {

int grade = 0;

try {

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
, BIND_AUTO_CREATE);

}

// 查询成绩

private void getStudentGrade(String name) {

int grade = 0;

try {

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-niiictY4-1715906622745)]

[外链图片转存中…(img-koA7C1nV-1715906622746)]

[外链图片转存中…(img-g8c9QJy4-1715906622746)]

[外链图片转存中…(img-LrfNyALg-1715906622747)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 15
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值