写点什么

Android-Binder 机制及 AIDL 使用,字节跳动安卓开发面试题

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

this.bookName = bookName;}


public int getBookId() {return bookId;}


public void setBookId(int bookId) {this.bookId = bookId;}public String getBookName() {return bookName;}public void setBookName(String bookName) {this.bookName = bookName;}


@Overridepublic int describeContents() {return 0;}


@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeInt(this.bookId);dest.writeString(this.bookName);}


protected Book(Parcel in) {this.bookId = in.readInt();this.bookName = in.readString();}public static final Parcelable.Creator<Book> CREATOR = new P arcelable.Creator<Book>() {@Overridepublic Book createFromParcel(Parcel source) {return new Book(source);}


@Overridepublic Book[] newArray(int size) {return new Book[size];}};}


由于 AIDL 只支持数据类型:基本类型(int,long,char,boolean 等),String, CharSequence,List,Map,其他类型必须使用 import 导入,即使它们可能在同一 个包里,比如上面的 Book。 最终IBookManager.aidl 的实现


// Declare any non-default types here with import statements import com.lvr.aidldemo.Book;interface IBookManager {/**


  • Demonstrates some basic types that you can use as paramet ers

  • and return values in AIDL.*/void basicTypes(int anInt, long aLong, boolean aBoolean, flo at aFloat, double aDouble, String aString);void addBook(in Book book); List<Book> getBookList();}


注意: 如果自定义的Parcelable对象,必须创建一个和它同名的 AIDL 文件,并在其 中声明它为parcelable类型。


Book.aidl


// Book.aidlpackage com.lvr.aidldemo;


parcelable Book;


以上就是 AIDL 部分的实现,一共三个文件。 然后 Make Project ,SDK 为自动为我们生成对应的 Binder 类。 在如下路径下:



其中该接口中有个重要的内部类 Stub ,继承了 Binder 类,同时实现了 IBookManager 接口。 这个内部类是接下来的关键内容。


public static abstract class Stub extends android.os.Binder impl ements com.lvr.aidldemo.IBookManager{}


服务端 服务端首先要创建一个 Service 用来监听客户端的连接请求。然后在 Service 中实现 Stub 类,并定义接口中方法的具体实现。


//实现了 AIDL 的抽象函数 private IBookManager.Stub mbinder = new IBookManager.Stub() {@Overridepublic void basicTypes(int anInt, long aLong, boolean aBoole an, float aFloat, double aDouble, String aString) throws RemoteE xception {//什么也不做}


@Overridepublic void addBook(Book book) throws RemoteException {//添加书本 if (!mBookList.contains(book)) {mBookList.add(book); }}


@Overridepublic List<Book> getBookList() throws RemoteException {return mBookList;}};


当客户端连接服务端,服务端就会调用如下方法:


public IBinder onBind(Intent intent) {return mbinder;}


就会把 Stub 实现对象返回给客户端,该对象是个 Binder 对象,可以实现进程间通 信。 本例就不真实模拟两个应用之间的通信,而是让 Service 另外开启一个进程来 模拟进程间通信。


<serviceandroid:name=".MyService"android:process=":remote"><intent-filter><category android:name="android.intent.category.DEFAULT" /><action android:name="com.lvr.aidldemo.MyService" /></intent-filter></service>


android:process=":remote"设置为另一个进程。 <action android:name="com.lvr.aidldemo.MyService"/> 是为了能让其他 apk 隐式 bindService。通过隐式调用的方式来连接 service,需要把 category 设为 default, 这是因为,隐式调用的时候,intent 中的 category 默认会被设置为 default。


客户端


首先将服务端工程中的 aidl 文件夹下的内容整个拷贝到客户端工程的对应位置下, 由于本例的使用在一个应用中,就不需要拷贝了,其他情况一定不要忘记这一步。客户端需要做的事情比较简单,首先需要绑定服务端的 Service。


Intent intentService = new Intent();intentService.setAction("com.lvr.aidldemo.MyService");intentService.setPackage(getPackageName());intentService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);MyClient.this.bindService(intentService, mServiceConnection, BIND_AUTO_CREATE);Toast.makeText(getApplicationContext(), "绑定了服务", Toast.LENGTH _SHORT).show();


将服务端返回的 Binder 对象转换成 AIDL 接口所属的类型,接着就可以调用 AIDL 中的 方法了。


if (mIBookManager != null) {try {mIBookManager.addBook(new Book(18, "新添加的书"));Toast.makeText(getApplicationContext(), mIBookManager.getBookList().size() + "", Toast.LENGTH_SHORT).show();} catch (RemoteEx


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


ception e) {e.printStackTrace();}}

3.AIDL 的工作原理

Binder 机制的运行主要包括三个部分:注册服务、获取服务和使用服务。 其中注册 服务和获取服务的流程涉及 C 的内容,由于个人能力有限,就不予介绍了。本篇文章主要介绍使用服务时,AIDL 的工作原理。


①.Binder 对象的获取 Binder 是实现跨进程通信的基础,那么 Binder 对象在服务端和客户端是共享的,是 同一个 Binder 对象。在客户端通过 Binder 对象获取实现了 IInterface 接口的对象来调 用远程服务,然后通过 Binder 来实现参数传递。


那么如何维护实现了IInterface接口的对象和获取 Binder 对象呢?服务端获取 Binder 对象并保存IInterface接口对象 Binder中两个关键方法:


public class Binder implement IBinder {void attachInterface(IInterface plus, String descriptor)IInterface queryLocalInterface(Stringdescriptor) //从 IBinder 中继承而来......}


Binder 具有被跨进程传输的能力是因为它实现了 IBinder 接口。系统会为每个实现了 该接口的对象提供跨进程传输,这是系统给我们的一个很大的福利。


Binder 具有的完成特定任务的能力是通过它的IInterface的对象获得的,我们可以 简单理解attachInterface方法会将(descriptor,plus)作为(key,value)对存入 Binder 对象中的一个 Map 对象中,Binder 对象可通过attachInterface方法持有一个 IInterface对象(即 plus)的引用,并依靠它获得完成特定任务的能力。 queryLocalInterface方法可以认为是根据 key 值(即参数 descriptor)查找相应的 IInterface对象。 在服务端进程,通过实现 private IBookManager.Stub mbinder = new IBookManager.Stub() {}抽象类,获得 Binder 对象。 并保存了IInterface对象。


public Stub() {this.attachInterface(this, DESCRIPTOR);}


客户端获取 Binder 对象并获取IInterface接口对象 通过bindService获得 Binder 对象


MyClient.this.bindService(intentService, mServiceConnection, BIN D_AUTO_CREATE);


然后通过 Binder 对象获得IInterface对象。


private ServiceConnection mServiceConnection = new ServiceConnec tion() {@Overridepublic void onServiceConnected(ComponentName name, IBinder b inder) {//通过服务端 onBind 方法返回的 binder 对象得到 IBookManager 的实例, 得到实例就可以调用它的方法了 mIBookManager = IBookManager.Stub.asInterface(binder);}@Overridepublic void onServiceDisconnected(ComponentName name) {mIBookManager = null;}};


其中 asInterface(binder)方法如下:


public static com.lvr.aidldemo.IBookManager asInterface(android. os.IBinder obj) {if ((obj == null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPT OR);if (((iin != null) && (iin instanceof com.lvr.aidldemo.IBook Manager))) {return ((com.lvr.aidldemo.IBookManager) iin);}return new com.lvr.aidldemo.IBookManager.Stub.Proxy(obj);}


先通过 queryLocalInterface(DESCRIPTOR);查找到对应的IInterface对象,然后 判断对象的类型,如果是同一个进程调用则返回IBookManager对象,由于是跨进 程调用则返回 Proxy 对象,即 Binder 类的代理对象。②.调用服务端方法获得了 Binder 类的代理对象,并且通过代理对象获得了IInterface对象,那么就可以 调用接口的具体实现方法了,来实现调用服务端方法的目的。 以addBook方法为例,调用该方法后,客户端线程挂起,等待唤醒:


@Override public void addBook(com.lvr.aidldemo.Book book) th rows android.os.RemoteException{..........

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android-Binder机制及AIDL使用,字节跳动安卓开发面试题