Android Binder原理解析,android应用开发实训总结

public void onServiceDisconnected(ComponentName name) {

iBookManager=null;

}

};

我们要调用 IBookManager.Stub.asInterface(service),这时候又会来到

//将一个IBinder对象转换成一个com.love.candy.aidl,这里就是我们平常用到的那个方法了

public static com.love.candy.aidl.IBookManager asInterface(android.os.IBinder obj) {

if ((obj == null)) {

return null;

}

//这里通过queryLocalInterface去查询有没有IInterface,

//这个在我们调用Stub构造方法的时候就已经穿进去了。就是那个this

android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);

//当获取到的不为空,并且是IBookManager,直接强转为IBookManager并返回

if (((iin != null) && (iin instanceof com.love.candy.aidl.IBookManager))) {

return ((com.love.candy.aidl.IBookManager) iin);

}

//否则就新创建一个Proxy

return new com.love.candy.aidl.IBookManager.Stub.Proxy(obj);

}

当我们去调用访问远程服务的方法iBookManager.addBook(book);就会调用到Proxy中的addBook方法。

@Override

public void addBook(com.love.candy.aidl.Book book) throws android.os.RemoteException {

//去获取序列化对象

android.os.Parcel _data = android.os.Parcel.obtain();

android.os.Parcel _reply = android.os.Parcel.obtain();

try {

//把本aidl通过ndk写入到一个地方

_data.writeInterfaceToken(DESCRIPTOR);

//如果传入的值不是空

if ((book != null)) {

//把传入的值序列化

_data.writeInt(1);

book.writeToParcel(_data, 0);

} else {

_data.writeInt(0);

}

//调用了Binder的transact方法

mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);

_reply.readException();

} finally {

_reply.recycle();

_da

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整资料开源分享

ta.recycle();

}

}

把对象进行一些封装,他最终会调用mRemote.transact方法。

public final boolean transact(int code, Parcel data, Parcel reply,

int flags) throws RemoteException {

if (false) Log.v(“Binder”, "Transact: " + code + " to " + this);

if (data != null) {

data.setDataPosition(0);

}

//这里会通过Binder的onTransact方法回调到我们Stub中

boolean r = onTransact(code, data, reply, flags);

if (reply != null) {

reply.setDataPosition(0);

}

return r;

}

这里会又回调到我们Stub中的onTransact。

@Override

public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply,

int flags) {

switch (code) {

case TRANSACTION_addBook: {

data.enforceInterface(DESCRIPTOR);

com.love.candy.aidl.Book _arg0;

//这里的值和Proxy中的值对应

if ((0 != data.readInt())) {

//通过data创建了个Book对象

_arg0 = com.love.candy.aidl.Book.CREATOR.createFromParcel(data);

} else {

_arg0 = null;

}

//回调抽象方法

this.addBook(_arg0);

reply.writeNoException();

return true;

}

}

return super.onTransact(code, data, reply, flags);

}

这里把我们传过来的对象进行解析,并回调了Stub的抽象方法addBook,这个抽象方法就是我们再Service中重写的那个方法

private class BookBind extends IBookManager.Stub {

@Override

public List getBookList() throws RemoteException {

return books;

}

@Override

public void addBook(Book book) throws RemoteException {

books.add(book);

Log.d(“lichao”," service addBook " + book.bookName);

}

}

最终调用了服务端中的addBook方法,把客户端加入的book加入到了服务端列表中。获取远程服务数据和加入数据流程差不多,只不过获取数据会有返回值。

流程图如下所示

引用了百度大神的图。

Android Binder原理解析,android应用开发实训总结

小结

当我们的客户端调用远程服务方法,被调用的方法运行在服务端的Binder线程池中,同时客户端线程会被挂起,这个时候如果服务端方法执行比较耗时时,就会导致客户端线程长时间阻塞在哪里,而如果这个客户端是UI线程的话,就会造成ANR,因此我们要避免在客户端的UI线程中去访问远程方法。由于客户端的onServiceConnected和onServiceDisconnected方法都运行在UI线程中,因此这里面也不要做耗时操作。

另外,由于服务端的方法本身就运行在服务端的binder线程池中,所以服务端方法本身就可以执行大量的耗时操作,这个时候切记不要在服务端方法中创建新的线程去执行异步任务了。

Github demo 地址
binderService启动流程分析
上一篇:Android启动那些事儿,从头到尾拎一遍~


下一篇:Spring Cloud Stream RocketMQ Binder 源码分析