欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Android Messenger实现进程间通信及其原理

程序员文章站 2022-06-25 12:25:54
前言之前分析android消息机制的源码时,曾遇到过replyto、imessenger等属性字段,当时只是说这些字段用于进程间通信,并未作深入分析。今天这篇文字就来演示一下使用messenger如何...

前言

之前分析android消息机制的源码时,曾遇到过replyto、imessenger等属性字段,当时只是说这些字段用于进程间通信,并未作深入分析。今天这篇文字就来演示一下使用messenger如何进行进程间通信并分析其源码实现。

messenger进程间通信的流程

messenger顾名思义,即信使,那么它的作用就是满足不同进程两边的通信需要了。通常我们会写aidl来实现进程间通信,其实简单的ipc可以用messenger来实现,需要知道的是messenger也是基于aidl的,只不过messenger帮我们做了封装而已,其进程间通信框架是这样的:

Android Messenger实现进程间通信及其原理

如上图,假设两个进程分别为client process和server process,首先server端需要将自己这边的messenger引用传给client,然后client使用server端传过来的messenger来发消息给server端,这样就实现了一个单向通信。同理,如果想要实现双向通信,则需要client端也发送一个自己的messenger到server端,那么server端也就可以利用该messenger向client发消息了。虽然messenger是基于aidl的,但它们最底层都是基于binder的。

messenger进程间双向通信示例

创建一个service模拟server进程

一般的进程间通信多是在两个app之间,但一个app中也可以有多进程,这个很常见,如应用中的推送服务一般位于单独的进程。当然我们可以把这个service创建到另一个app中,但为了方便测试,这里只是将该service注册为另一个进程,但还是在同一个应用中。

该service的实现很简单,如下:

上述代码虽然简单,但有几点需要注意:

1、为什么service中要开一个工作线程?因为service作为四大组件之一,它是运行在主线程的,所以不能执行耗时操作,一旦进程间交互是耗时操作,那么service所在进程就会阻塞,而client端进程则不会阻塞。
2、该service中创建了一个messenger对象,并在onbind中返回了ibinder对象,这里是进程间通信的关键,在后面会详细分析。
3、该service的子线程中创建了一个handler,并关联给messenger,用于进程间通信的消息处理。handler消息处理跟我们平时用的一样,但有一点提一下,子线程是没有默认looper的,因此需要自己创建并启动,否则子线程的handler无法收到message。
4、server端收到消息后,toast一下“hello server”并显示cient传过来的两个整数值。如果client端也将自己的messenger传过来了,则向client端回复消息,将两个整数之和返回。

另外该service在androidmanifest.xml中的注册如下:

核心一句为android:process=":remote",将该service置于另一个进程之中,从而可以在同一个app中模拟进程间通信。

创建一个activity模拟client进程

该activity默认就是该app所在进程了,具体实现如下:

代码逻辑也很简单,界面有3个按钮,操作如下:

1、先启动server端的service,暂且叫做启动远程service
2、绑定远程service
3、client向servcie端发送消息,并接收返回的消息

需要注意的有如下几点:

1、绑定远程service后,client端才拿到了server端的messenger引用。
2、client端的messenger需要关联自己的handler,用来处理从server端收到的消息。这里也需要注意,理论上如果server端与client端交互也是耗时的话,也需要开子线程,这个例子中由于只是显示下消息,直接放在ui线程了。
3、如果需要双向通信,client端需要通过message的replyto参数将自己的messenger发到server端。
4、android 5.0+要求绑定service时必须使用显式intent,可以通过设置包名的方式来解决,注意我是在同一个app中开的两个进程,因此包名相同,但如果远程service位于另一个app,则应该填写其所在app的包名。
5、client端收到回复消息后,toast“hello client”及两个整数之和。

示例效果演示

以上示例的进程间通信效果演示如下:

Android Messenger实现进程间通信及其原理

messenger进程间通信原理分析

关于service的启动、绑定不必多说,先从client端通过绑定远程service获取server端的messenger入手,代码如下:

接着来看mremotemessenger = new messenger(service);的源码实现:

注意到该构造方法的参数ibinder,就是远程service中onbind返回的,具体代码如下:

再来看这一句代码:

mtarget是imessenger对象,看起来越来越像aidl的写法了,其实不能说像,本来就是aidl。于是猜想源码必定中有一个名为imessenger.aidl的文件,它应该定义了发送消息的相关接口。果然在源码目录 “/frameworks/base/core/java/android/os/”下找到了imessenger.aidl文件,其内容如下:

因此可知messenger只是帮我们省去了写aidl的工作而已,底层还是aidl。

再来看messenger是如何发送消息的,即messenger的send方法:

通过注释可知,messenger会将消息发送到其关联的handler,且handler不存在时会报异常,这就是我们无论是创建客户端还是服务端messenger时都为其创建了一个handler的原因。

另外上述示例中为了简便,只是在进程间传递了基本类型的值,其实类似单进程的消息机制,也可以传递bundle数据,但注意需要序列化,具体说明可参考message源码的基本字段支撑。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。