Messenger源码解析
来源:互联网 发布:dwg是什么软件 编辑:程序博客网 时间:2024/05/01 08:33
之前根据官方文档和网上一些大神的博客,已经可以正常的使用Messenger进行跨进程通讯了,其实流程很简单,大体如下:
在使用层面已经熟悉了,最好还是看一下源码,系统是怎么封装的,原理是什么,虽然网上已经有很多类似的,但是自己写,自己看,学到就是自己的。我们就根据流程图的单向通讯分析(Client向Service发送一条消息)。
- 构造Messenger
private final IMessenger mTarget; public Messenger(Handler target) { mTarget = target.getIMessenger(); }
看到,我们传Handler过来,只是为了获取IMessenger对象。追踪到Handler源码看一下
final IMessenger getIMessenger() { synchronized (mQueue) { if (mMessenger != null) { return mMessenger; } mMessenger = new MessengerImpl(); return mMessenger; } }
这里我们看到mMessenger的实现是MessengerImpl这个类,他是Hanler的内部类。
private final class MessengerImpl extends IMessenger.Stub { public void send(Message msg) { msg.sendingUid = Binder.getCallingUid(); Handler.this.sendMessage(msg); } }
总共就这几行,很简单,做的事情也很简单,只有一个send方法,把发起调用的客户端进程的 Linux Uid存储在我们传入的 Message 对象中,然后handler把Message发送出去。
- 构造好Messenger,建立连接,接下来就是发送消息了吧,
public void send(Message message) throws RemoteException { mTarget.send(message); }
这里就是发送的源码,他的实现就是上面我们说的MessengerImpl中的send();
Messenger发送消息是经由Handler实现的,所以Messenger的消息是以MessageQueue去管理的,也就是一次只能处理一个消息,不能支持并发任务。
- 再来看一下IMessenger
发现底层的实现还是用的AIDL,
//Messenger.aidlpackage android.os;parcelable Messenger;//IMessenger.aidlpackage android.os;import android.os.Message;/** @hide 注意这里的oneway关键字*/oneway interface IMessenger { void send(in Message msg);}
这也就不难理解Messenger中出现的两个方法了
//客户端调用 public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); } //服务端调用 public IBinder getBinder() { return mTarget.asBinder(); }
既然底层是AIDL实现,那么那就应该符合AIDL的调用流程
看过aidl的源码实现,我们知道不能在客户端进程的 UI 线程中发起远程方法调用,不然如果远程方法执行了耗时操作,客户端的UI线程将会被阻塞,从而造成 ANR 的问题存在。这个我亲测过,不信你就自己写一个试试。
但是在Messenger貌似不存在这种情况,无论在服务端执行多么耗时的任务,都不会卡顿UI线程。
这是不是有点奇怪,因为其中的交互只有一个Handler,而且还是绑定UI线程的Handler,按说在handleMessage()中执行耗时任务,肯定会阻塞UI线程。然而并没有,肯定是哪里我们忽略了。还记得前面那个oneway关键字吗。google文档中的介绍:
The oneway keyword modifies the behavior of remote calls. When used, a remote call does not block; it simply sends the transaction data and immediately returns. The implementation of the interface eventually receives this as a regular call from the Binder thread pool as a normal remote call. If oneway is used with a local call, there is no impact and the call is still synchronous.
这就是关键,允许客户端能够非阻塞的调用远程方法,之前定义的IMessenger.aidl是不是就是用了oneway关键字,再看一下生成.java有和不同:
//IMessage.Proxy.sendpublic void send(android.os.Message msg)throws android.os.RemoteException {android.os.Parcel _data = android.os.Parcel.obtain();try {_data.writeInterfaceToken(DESCRIPTOR);if ((msg != null)) {_data.writeInt(1);msg.writeToParcel(_data, 0);// } else {_data.writeInt(0);}// 这里如果不加oneway关键字,proxy中的send方法,mRemote.transact(,,,0)最后这个参数是0,加了之后就变为了android.os.IBinder.FLAG_ONEWAYmRemote.transact(Stub.TRANSACTION_send, _data, null,android.os.IBinder.FLAG_ONEWAY);} finally {_data.recycle();}}
查看 API 文档即可以看到 FLAG_ONEWAY 的作用就是让客户端能够非阻塞的调用远程方法,至此真相大白,如果我们自定义的 aidl 也想实现非阻塞的调用,只需声明 oneway 关键字即可。
4.总结,Messenger的工作原理这下就清楚了,传递消息依赖的是Handler,但是此处是不阻塞UI线程的,这也是Messenger的神奇之处。
- Messenger源码解析
- Android中的信使Messenger的源码解析
- Messenger案例解析及其源码分析
- Jive Messenger 源码研究
- Jive Messenger 源码研究
- Messenger源码分析
- Android Messenger源码分析
- Android信使Messenger解析
- Android信使Messenger范例源码
- Android IPC之Messenger解析
- Messenger
- Messenger
- Messenger
- Messenger
- Messenger
- Android进阶笔记:Messenger源码详解
- Android IPC之Messenger源码分析
- 深入解析AIDL的实现:Messenger
- 提升对linux的认识和理解中
- Redis入门指南
- MVC5怎么设置默认访问页
- 二项队列分析及实现
- 开闭原则OCP
- Messenger源码解析
- [iOS Swift3.0] 定位二维码+绘制定位框+简单使用UIBezierPath和CAShapeLayer
- 金融行业风控概念及分析
- actor中!(tell)与forward的区别
- 构造方法,static,文档
- 动态规划
- codeforces363D——Renting Bikes(二分,贪心)
- 提高安卓APP开发效率、管理代码的架子(一):BaseActivity&BaseApplication
- IDE常用快捷键——微信小程序