Android面试:AIDL是什么?有使用过它吗,它支持哪些数据类型?

}
};
}

然后在MainActivity通过bindService绑定这个服务,即可以获得AIDL的接口调用的引用。运行前,我们设置一下AndroidManifest.xml文件记这个Service运行在一个单独的进程中:

现在来bindService:

public class MainActivity extends AppCompatActivity {
private final static String TAG = “MainActivity”;
private IRemoteService remoteService;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Intent intent = new Intent();
intent.setClass(this, RemoteService.class);
bindService(intent, connection, Service.BIND_AUTO_CREATE); // 绑定服务
}

private ServiceConnection connection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
remoteService = IRemoteService.Stub.asInterface(service); //获取AIDL的接口实现引用
try {
Log.i(TAG, "Client pid= " + Process.myPid());
Log.i(TAG, "RemoteService pid= " + remoteService.getPid());
} catch (RemoteException e) {
e.printStackTrace();
}
}

public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, “Service has unexpectedly disconnected”);
remoteService = null;
}
};
}

从输出的日志看到Service和Activity运行在两个不同的进程中:

02-05 09:51:40.154 18992-18992/net.goeasyway.aidltest I/MainActivity: Client pid= 18992
02-05 09:51:40.154 18992-18992/net.goeasyway.aidltest I/MainActivity: RemoteService pid= 19022

到这里,我们完成了一个AIDL的范例,有几个地方可能会对我们造成困扰:

  • Stub类:Binder的实现类,服务端需要实现这个类来提供服务。
  • asInterface函数: 一个静态函数,用来将IBinder转换成对应的Binder的引用。先通过queryLocalInterface查询,如果服务端和客户端都是在同一个进程,那么就不需要跨进程了,直接将IRemoteService当做普通的对象来使用,否则会返回远程对象的代理对象(Proxy)。

public static net.goeasyway.aidltest.IRemoteService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof net.goeasyway.aidltest.IRemoteService))) {
return ((net.goeasyway.aidltest.IRemoteService)iin);
}
return new net.goeasyway.aidltest.IRemoteService.Stub.Proxy(obj);
}

通过IPC传递对象

现在,我们加大一下难度,AIDL的接口使用一个我们自己定义的类为参数(或者返回值)。实现步骤如下:

  • 添加一个自定义对象类,并且要实现Parcelable接口,如MyProcess.java;
  • 在AIDL目录下的相同Pacage下添加一个同名的AIDL文件,如MyProcess.aidl;

注意:通过“Android Studio->File->New->AIDL->AIDL file”不让你创建和MyProcess.java同名的AIDL文件,你可以直接用通过“Android Studio->File->New->File”创建一个MyProcess.aidl。

  • 在AIDL接口类中添加一个接口函数,使用MyProcess做为参数或者返回值;

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其他的细节大家可以直接查看Github上的代码:https://github.com/goeasyway/AIDL_Test (或者查看提交的说明找到具体每次的代码区别:https://github.com/goeasyway/AIDL_Test/commits/master

in、out & inout
这节我们看到“MyProcess getProcess(in MyProcess clientProcess);”这个接口的参数有一个“in”修饰符,这也是一个常见的面试题,可以考察一下对方是否真的写过AIDL的代码。

问题:AIDL中的接口函数有时会使用in、out或者inout的参数修饰符,它们各表示什么意思?在什么情况下要使用呢?

in、out和inout表示数据的流向。大家可以把AIDL的客户端和服务端理解成两个进程(其实大多数情况也是这样才会使用AIDL),从客户端流向服务端用in表示,表示这个对象是从客户端中传递到服务端,在服务端修改这个对象不会对客户端输入的对象产生影响。

而out则表示,数据只能从服务端影响客户端,即客户端输入这个参数时,服务端并不能获取到客户端的具体实例中的数据,而是生成一个默认数据,但是服务端对这个默认数据的修改会影响到客户端的这个类对象实例发生相应的改变。

理解了in、out之后,inout自然不需要再解释了。AIDL默认支持的数据类型使用in修饰符,对于我们自定义的Parcelable对象,一般情况下我们也是使用in,如果没有必要,应该尽量避免inout。

Intent也是Parcelable实现
也许你会想到,我们在Activity间可以通过Intent携带参数,其实你去看的源码的话会发现Intent也是一个Parcelable的实现类,而且在系统的工程中也有一个Intent.aidl文件(路径:/frameworks/base/core/java/android/content/Intent.aidl)。所以,它才可以在进程间传递。

注:目前Client端和Server端在同一工程中,如果分开在不同的工程的话,Client端所在的工程要把Server端提供的.aidl复制到同名Pacage的AIDL代码目录下。

手动方式创建AIDL(不依赖AIDL工具,手写远程AIDL的代码完成跨进程通信)

通过AIDL,可以让本地调用远程服务的接口就像调用本地接口那么简单,让用户无需关注内部细节,只需要实现自己的业务逻辑接口,内部复杂的参数序列化发送、接收、客户端调用服务端的逻辑,用户并不需要关心。

AIDL的代码生成器,已经根据.aidl文件自动帮我们生成Proxy、Stub(抽象类)两个类,并且把客户端代理mRemote的transact()过程以及服务器端的onTtransact()过程默认实现好了,我们只需要在服务端继承Stub,实现自己的业务方法即可。

但现在,为了进一步加深对Binder机制的理解,我们来做一个手动实现编写AIDL相关代码的练习。

具体的代码大家可以参考:https://github.com/goeasyway/AIDL_Test/tree/master/app/src/main/java/net/goeasyway/aidltest/diy

这个包里有三个类:IRmote.java为接口,Stub.java为Binder实现类(Service端要实例化它并在onBind返回),Proxy.java为代理类,提供给客户端使用的,通过Binder驱动和服务端通信。

大家可以看到这个练习不需要.aidl文件。

在这几个代码中,大家需要搞清楚这个类(或者接口)的关系:

  • Binder
    Binder本地对象。
  • IBinder
    IBinder是一个接口,它代表了一种跨进程传输的能力。
  • IInterface
    IBinder负责数据传输,那么client与server端的调用契约呢?这里的IInterface代表的就是远程server对象具有什么能力。具体来说,就是aidl里面的接口。
  • Proxy
    代表远程进程的Binder对象的本地代理,继承自IBinder,因而具有跨进程传输的能力。实际上,在跨越进程的时候,Binder驱动会自动完成代理对象和本地对象的转换。
  • Stub
    这个类继承了Binder, 说明它是一个Binder本地对象,它实现了IInterface接口,表明它具有远程Server承诺给Client的能力;Stub是一个抽象类,具体的IInterface的相关实现需要我们手动完成。

如果觉得有点难理解的话,不妨先动手写了再来看。

小结

最后

**一个零基础的新人,我认为坚持是最最重要的。**我的很多朋友都找我来学习过,我也很用心的教他们,可是不到一个月就坚持不下来了。我认为他们坚持不下来有两点主要原因:

他们打算入行不是因为兴趣,而是因为所谓的IT行业工资高,或者说完全对未来没有任何规划。

刚开始学的时候确实很枯燥,这确实对你是个考验,所以说坚持下来也很不容易,但是如果你有兴趣就不会认为这是累,不会认为这很枯燥,总之还是贵在坚持。

技术提升遇到瓶颈了?缺高级Android进阶视频学习提升自己吗?还有大量大厂面试题为你面试做准备!

提升自己去挑战一下BAT面试难关吧

对于很多Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。整理的这些知识图谱希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

不论遇到什么困难,都不应该成为我们放弃的理由!

如果有什么疑问的可以直接私我,我尽自己最大力量帮助你!

最后祝各位新人都能坚持下来,学有所成。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
成为我们放弃的理由!**

如果有什么疑问的可以直接私我,我尽自己最大力量帮助你!

最后祝各位新人都能坚持下来,学有所成。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 27
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值