Android进阶笔记:Messenger源码详解
Messenger可以理解为一个是用于发送消息的一个类用法也很多,这里主要分析一下再跨进程的情况下Messenger的实现流程与源码分析。相信结合前面两篇关于aidl解析文章能够更好的对aidl有一个认识。(Android进阶笔记:AIDL内部实现详解 (一)、Android进阶笔记:AIDL内部实现详解 (二))
用法说明
先来看一下Messenger在跨进程通讯时的使用方法,代码如下:
Service的代码
//用来传递Messenger中IMessenger
public class ServerService extends Service { public static final String TAG = "ServerService"; private Messenger messenger; @Override public void onCreate() { super.onCreate(); //创建一个Messenger对象 messenger = new Messenger(new MessengerHandler()); } @Nullable @Override public IBinder onBind(Intent intent) { //返回IMessenger return messenger.getBinder(); } } //用于创建Messenger的Handler class MessengerHandler extends Handler { public static final String TAG = "ServerService"; @Override public void handleMessage(Message msg) { if (msg.what == 10001) { String data = msg.getData().getString("data"); data = data == null ? "null" : data; Log.e(TAG, "handleMessage: get msg from client = (" + data + ")"); } } }
上面就是Service的代码,分析一下其实总共做了3步:
- 定义了一个MessengerHandler的内部类并且实现了handleMessage的内部回调;
- 创建了一个Messenger的对象,在Messenger的构造函数中传入刚刚创建的handler实例;
- 在Service的onBind方法中回调messenger的getBinder()方法;
Activity的代码:
public class MainActivity extends AppCompatActivity { private ServiceConnection serviceConnection; private Messenger messenger; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e("MainActivity", "onServiceConnected: connection success !!!"); //用返回的Ibinder对象来构造一个Messenger实例 messenger = new Messenger(service); //创建一个msg Message msg = new Message(); msg.what = 10001; Bundle bundle = new Bundle(); bundle.putString("data", "hello Server"); msg.setData(bundle); try { //调用messenger的send方法 messenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { messenger = null; } }; bindService(new Intent("com.coder_f.messengerdemo.ServerService"), serviceConnection, BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); unbindService(serviceConnection); } }
Activity中做的工作其实也不复杂也是3步:
- 通过绑定Service来获得IBinder对象;
- 通过IBinder对象重新构造一个Messenger;
- 通过Messenger的send方法来发送消息;
以上就是Messenger的使用方法。好了现在就可以根据上面的使用方法来看看Messenger内部到底是怎么来运作的。
源码解析
首先先来看看参数为Handler的Messenger的构造函数
public Messenger(Handler target) {mTarget = target.getIMessenger();}
很简单,就是保存传入Handler的getIMessenger()方法返回的东西。那接下来就去看看getIMessenger()方法返回的是什么东西。
final IMessenger getIMessenger() {synchronized (mQueue) {if (mMessenger != null) {return mMessenger; } mMessenger = new MessengerImpl(); return mMessenger; } }
也不复杂,无非就是判断一下mMessenger是不是空然后返回一下。那mMessenger到底是什么呢。看看它的构造函数new MessengerImpl()代码如下:
private final class MessengerImpl extends IMessenger.Stub { public void send(Message msg) { msg.sendingUid = Binder.getCallingUid(); Handler.this.sendMessage(msg); } }
看到这里相信已经摸的差不多了,这个结构就是aidl的结构。这里猜一下应该就明白了,源码里面肯定有定义了一个IMessage.aidl,而且里面还声明了一个send的方法。而这个seng的方法在Handler里面被实现了,具体就是通过Handler来发送一条消息。那么可以得到结论,最后mTarget获得的其实就是一个IMessenger.Stub的实例,里面已经实现了接口中的方法(send(Message msg))
事实证明确实如此,源码的位置:platform\frameworks\base\core\java\android\os\IMessenger.aidl
package android.os;import android.os.Message;/** @hide */
oneway interface IMessenger {void send(in Message msg); }
上面只是对构造函数的源码进行了分析,但是其实已经把Messenger的结构摸的八九不离十了;
好了既然构造函数分析的差不多了,根据流程下一步应该是通过messenger.getBinder()方法取出一个Ibinder对象通过Service来返回给Activity。那么接下来再来看看messenger.getBinder()方法:
public IBinder getBinder() {return mTarget.asBinder();}
很清楚,调用了IInterface(mTarget就是IMessenger.Stub的实例继承了IMessenger,而IMessenger继承了IInterface)的asBInder方法返回了一个Binder(这里简单的理解其实就是返回了它自己,因为stub内部类也继承了Binder)。
service这边的代码只有这些,那根据上面的使用方法,继续来看Activity这边的代码吧。
Activity这边也有一个构造函数,参数是一个IBinder对象,这个构造函数的源码如下:
public Messenger(IBinder target) {mTarget = IMessenger.Stub.asInterface(target);}
很清楚返回的其实就是一个proxy类也就是一个binder驱动(不明白的可以看之前的博客)。
然后接下来就是调用了Messenger的send方法;那继续再来看看这个send方法的源码是怎么样的。
public void send(Message message) throws RemoteException {mTarget.send(message);
}
其实就是调用了刚刚proxy的send方法吧message当参数传进去。这里面的逻辑其实就是通过这个proxy类中的IBinder对象来远程调用service中已经实现的send方法。
一目了然Messenger就是一个典型的aidl的例子。
总结
Server端就是Handler里面实现的MessengerImpl内部类,然后在Service里面被实例化了。而这个aidl也是只有一个方法(send(Message)),就是通过当前Handler来发送一个消息。
Client端就是通过Service返回过来的IBinder类来获取一个proxy对象,通过proxy对象远程调用send方法来完成通讯。
补充:如果要实现Service那边处理完消息返回给activity的话只要在activity里面也创建一个Messenger,然后把这个Messenger通过Message赋值给参数message.replyTo传过去就好了,同样Service就可以通过这个参数里面的Messenger来发送消息给activity通过activity里面handler来处理消息来完成双向通讯。
注意:这里有一点就是如果不是跨进的的话Service和Activity都运行在主线程,那么Service中用于处理消息的Handler里面不能执行耗时的工作,不然会导致ActivityUI界面卡住,因为Handler是创建在Service线程(主线程)用的是主线程的Looper。如果是跨进程的话Activity这边的主线程就不会卡住(Service所在的线程会卡住)。因为在普通的aidl在proxy调用的时候(其实就是调用IBinder.transact方法时)会挂起当前线程因此在Service端执行耗时操作时activity的UI线程会卡住。而messenger和普通的aidl不同之处在于它又添加了一个Handler,而这个Handler是运行在Service所在线程(默认为Service所在进程的主线程)而真正的Messenger.send方法只执行了一个Handler的sengmessage方法(这个方法是运行在底层binder的工作线程中,只要在这个线程中不执行耗时操作调用方所在的线程就不会被挂起太久)。因此不会卡住(Service线程可能会卡住)。这一点我感觉IntentService的实现非常的相似。
本文转自 一点点征服 博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/8418914.html,如需转载请自行联系原作者
相关文章:

程序员春运抢票的正确姿势!
作者 | 屠敏出品 | CSDN资讯「有钱没钱,回家过年。」转瞬间,2018 年余额已严重不足,而 2019 年还正在赶来的路上:根据国家法定假日规定,距离 2019 年春节( 2019 年 2 月 5 日)的到来还有 45 天&…

centos 6.8 编译安装git 2.11.0
系统环境:CentOS release 6.8 (Final) 默认Git :1.7.1 需求git :2.11 卸载centos自带的git:yum remove git -y 下载git-2.11.0.tar.gz 上传至服务器,下载链接:http://distfiles.macports.org/git/ 解压安装…

小黑盒不显示服务器,steam上买的游戏小黑盒不显示 | 手游网游页游攻略大全
发布时间:2018-04-18贪吃蛇遇上打方块是一款最近非常热门的休闲小游戏,游戏将贪吃蛇和打方块合而为一吸引了很多玩家!但是好多小伙们都不知道该怎么玩,下面小编来教你一个快速入门的小技巧吧!~ 小技巧: 1.通过吃游戏带数字的黄色圆点,增加自己的长 ...标签ÿ…

基于架构的上网行为管理产品界面对比
当前上网行为管理产品风靡市场,对用户的网络管理的能力有很大的提高,给用户带来便利的同时也给用户带来很多困惑。目前市场上的上网行为管理产品在功能点上基本相同,于是一些设备的厂商开始关注设备的其它附加功能,比如网络管理人…

AI in 美团:吃喝玩乐背后的黑科技
作者 | 杨丽出品 | AI科技大本营(rgznai100)很多人都会发现日常生活已经越来越离不开美团了,这个互联网平台涵盖了吃、住、行、游、购、娱……能帮我们做很多事情,非常接地气。黄色的美团外卖骑手,橙色的摩拜单车&…

手机贷服务器维护升级,手机贷服务器升级
手机贷服务器升级 内容精选换一换本章节介绍如何创建告警规则。用户可自定义监控目标与通知策略,及时了解云手机服务器、云手机、磁盘以及GPU卡的状况,从而起到预警作用。登录管理控制台。在管理控制台左上角,选择待创建告警规则的区域。在服…

Windows Server 2008 R2 Beta VHD镜像文件发布
微软刚刚发布了一个VHD格式的Windows Server 2008 R2 Beta镜像文件,它可以用于Hyper-V环境下作评估. 您需要事先安装Windows Server 2008 (64bit edition) 或 Windows Server 2008 R2 Beta,需要更多信息请参阅Hyper-V主页.下载:Windows Server 2008 R2 Beta .uation Virtual Ha…
linux下的usb抓包方法【转】
转自:http://blog.chinaunix.net/uid-11848011-id-4508834.html 1、配置内核使能usb monitor: make menuconfig Device Drivers --> USB Support --> USB M…

中小学AI教育靠谱吗?50%教师教学经验不足1年
作者 | 琥珀出品 | AI科技大本营(rgznai100)近日,一份《中小学阶段人工智能普及教育现状调研报告》的发布让我们不禁汗颜当下中国中小学人工智能教育普及程度、教师教育水平所存在的问题。链接:http://www.cacsi.org.cn/Uploads/a…
你,保持童心;我,帮你保持童颜
在周星驰的《美人鱼》里有这样一句: 童话是存在的,只不过不是幻想的,而是自己去搭建的儿童节到了 感觉自己又小了一岁 越来越年轻了呢! 望遍朋友圈, 都是一群该当妈的在过六一 大龄儿童这么凑热闹是不是不太好呢&#…

java程序通过命令行运行之Path和ClassPath的注意点
习惯用IDE的朋友可能早就不用cmd,想当初我们刚学java的时候还记得对着黑屏幕敲的,哈哈。让我们再来重温旧梦。 我们在现在有这样一个文件HelloWorld.java,它的路径是这样的E:\javaTest\HelloWorld.java public class HelloWorld { public…

美通信与动力公司向WIN-T军事通信计划提供支持
美通信与动力公司向WIN-T军事通信计划提供支持[据美国军事与航宇电子网2009年2月17日报道]日前,通信与动力工业公司(CPI)从通用动力卫星通信技术公司获得一项价值大约为1300万美元的后续合同,向美国陆军士兵信息网络战术ÿ…

看动画轻松理解“递归”与“动态规划”
作者 | 程序员小吴来源 | 五分钟学算法在学习「数据结构和算法」的过程中,因为人习惯了平铺直叙的思维方式,所以「递归」与「动态规划」这种带循环概念(绕来绕去)的往往是相对比较难以理解的两个抽象知识点。程序员小吴打算使用动…
毕业季:理想很丰满,现实也可以很丰满!
六月,原本不是一个适合离开的季节,不是烈日,就是暴雨,让人不得不走走停停,频频回望。然而,哪个季节又适合离开呢?六月,确实得离开了。大学几年的时光终将逝去,而之后各位…

php扩展模块安装-lamp
php扩展模块安装 PECL 的全称是 The PHP Extension Community Library ,是一个开放的并通过 PEAR(PHP Extension and Application Repository,PHP 扩展和应用仓库)打包格式来打包安装的 PHP扩展库仓库。通过 PEAR 的 Package Manager 的安装管理方式&…

一文搞懂K近邻算法(KNN),附带多个实现案例
简介:本文作者为 CSDN 博客作者董安勇,江苏泰州人,现就读于昆明理工大学电子与通信工程专业硕士,目前主要学习机器学习,深度学习以及大数据,主要使用python、Java编程语言。平时喜欢看书,打篮球…
致那些还在创业之路上孤独前行的青年大学生们!
彩虹,在大雨后出现 腊梅,在风雪中吐蕊 雄鹰,在险峰上空盘旋 人,在困境中弥坚 在这个创业的浪潮中 你是否也是其中之一 当所有事情都将有你一个人来完成 你是否有信心和能力把它做好 成功不是回首,不是寄望,…

MS DTC 无法正确处理 DC 升级/降级事件的解决
当Windows 2003安装AD后,经常出现以下警告信息的解决方法:MS DTC 无法正确处理 DC 升级/降级事件。MS DTC 将继续运行并将使用现有的安全设置。错误说明: %1, 打开管理工具的组件服务管理控制台,打开组件服务,计算机。右击我的电…

UML图的分类
作为一种建模语言,UML的定义包括UML语义和UML表示法两个部分。 (1) UML语义 描述基于UML的精确元模型定义。元模型为UML的所有元素在语法和语义上提供了简单、一致、通用的定义性说明,使开发者能在语义上取得一致,消除了因人而异的最佳表达方法所造成的影响。此外UML还支持对元…
告诫那些有创业梦的大学生,切记千万不要盲目创业!
如果你打算创业,那么最好具备两点: 一是有一定的经济实力或行业经验和人脉, 二是没有太多后顾之忧。 有一部分创业者是前期赚了一些钱,能确保基本生活的质量!所以可以全身心投入到创业中,提高成功的概率。然…

春运渡劫!Python给我抢回家的火车票
简介:本文首发于个人公众号「视学算法」,作者阿广,一个专注于大数据、人工智能和算法的学习平台,也是一个保送中科院软件研究所直博生的自留地。人生苦短,我愿做您最忠实的技术支持伙伴!一起用代码改变世界…

首次成功实施 XSS 攻击,盗取目标网站大量 VIP 帐号
前言 之前做网站时有做代码防御 XSS(Cross Site Script) 攻击,但是却只处于了解的阶段,并不知道其中具体的原理,更别说使用了。最近有朋友要求我帮助他 Hack 一个网站,达到一定的目的。思考来思考去,最后想了一套方案&…

oracle取得表中总记录数最快的方法
查询表中的记录总数的语法就是SELECT COUNT(*) FROM TABLE_NAME。这可能是最经常使用的一类SQL语句。 本文讨论怎样才能最快的得到这个记录数。本文纯粹主要是理论上的讨论,文章中很多内容(如常数索引)对实际的指导意义不大。 在具体描述之前…
你的创业前行之路,亲君愿与你一路相随
每一个创业者都是黑暗中的独行侠, 然后告诉别人光明就在前方, 其实, 他们自己心里也不知道光明还有多远。 无论当初是因为理想还是因为实现个人价值, 只要走上创业这条路, 我们就只能不断的告诉自己和他人:…

年度重磅:《AI聚变:2018年优秀AI应用案例TOP 20》正式发布
2018 年,AI 行业的关键词或许非“落地”二字莫属 ,人们强烈期待着更多 AI 技术应用和深入商业化。 一方面,科技巨头们在横向铺设 AI 技术平台,但也更强调 AI 与每一个垂直行业的深度融合。而另一面,AI 创业公司在频繁刷…

防止熊猫烧香的微软补丁
为了防止熊猫烧香病毒,要及时安装微软的安全更新,不要随意访问来源不明的网站。特别是微软的MS06-014漏洞,应立即打好该漏洞补丁。 不知道这个补丁是不是已经打上的朋友,一是在控制面板里可以看到.(勾上显示更新前面的方框),或者下载360安全卫士,扫描漏洞…

【Azure Services Platform Step by Step-第11篇】Windows Azure兰州拉面馆-日志与队列的使用...
在第9篇里,为了便于大家理解,我把Windows Azure的环境比喻成了"Azure兰州拉面馆"。本篇我们继续沿用这个比喻,讲讲Windows Azure中的队列(Queue Storage)与日志的使用。 Queue Storage在【Azure Services Platform Step by Step-第…
这才是世界排名前十位的奢侈品
真正的奢侈品,不是豪车大宅,不是名包贵表,而是这些…… 1. 一颗童心2. 生生不息的信念3. 背包走天下的健康体魄4. 愉悦和舒心的工作环境5. 安稳平和的睡眠6. 享受属于自己空间与时间的生活7. 牵手一个教会你爱与被爱的人8. 品味美好的心情…

配置springmvc在其他类中(spring容器外)获取注入bean
今天在写JedisUtils的时候要注入JedisPool,而这个属性被设置为static,Resource和Autowired都不可以注入,因为spring不能为静态变量依赖注入。因此需要额外的方法获取spring管理的bean。本文即SpringContextHolder: 1 package com.…

声智科技完成2亿元B轮融资,将持续拓展语音交互产品的规模化落地
整理 | 一一出品 | AI科技大本营寒冬之下,不少创业公司依然得到了资本青睐。AI科技大本营消息,12 月 29 日消息,声智科技(SoundAI)已于近期完成 2 亿人民币 B 轮融资,本轮投资由毅达资本领投,峰…