ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-01-03 11:02:48  阅读:217  来源: 互联网

标签:aidl os Binder 实训 reply Android data addBook 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加入到了服务端列表中。获取远程服务数据和加入数据流程差不多,只不过获取数据会有返回值。

流程图如下所示

引用了百度大神的图。

在这里插入图片描述

小结

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

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

Github demo 地址
binderService启动流程分析

标签:aidl,os,Binder,实训,reply,Android,data,addBook,android
来源: https://blog.csdn.net/m0_65145685/article/details/122284764

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有