Android轻量级进程间通信Messenger源码分析

2024-02-21 06:52

本文主要是介绍Android轻量级进程间通信Messenger源码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一. 概述

        Android中比较有代表性的两大通信机制:1. 线程间Handler通信   2. 进程间Binder通信,本篇文章中我们在理解AIDL原理的基础上来解读一下Messenger的源代码, 并结合示例Demo加深理解。 在看本篇文章前,建议先查阅一下笔者的 Android 进程间通信机制(六) 手写AIDL文件

        首先说下我对Messenger的个人理解:

1. 从概念上阐述

    Messenger进程间通信的信使,是一个轻量级的IPC通信方案, 和Message消息不是一个概念。

2. 从实现上描述

     实现: AIDL  +  Handler    它的底层实现原理还是使用 AIDL,  对应的文件为(IMessenger.aidl)

相应的接口方法:

oneway interface IMessenger {void send(in Message msg);
}

Messenger使用了Handler进行通信, 调用的这句代码

    private final class MessengerImpl extends IMessenger.Stub {public void send(Message msg) {msg.sendingUid = Binder.getCallingUid();//核心代码Handler.this.sendMessage(msg);}}

3. 使用场景

    两个进程间只进行简单的,轻量级通信, 不需要处理多线程的业务场景。

二. 示例

2.1 先看一下清单文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.messengertest"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.MessengerTest"><activityandroid:name=".MainActivity"android:exported="true"android:process=":client"><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity><serviceandroid:name=".MyService"android:exported="true"android:enabled="true"android:process=":server"></service></application></manifest>

我把MainActivity作为客户端,  MyService作为服务端, 用android:process标记让两个组件运行在不同的进程中。

2.2 客户端

public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";private Messenger mServiceMessenger;//创建客户端 Messenger 对象,并绑定 Handlerprivate Messenger mClientMessenger = new Messenger(new MessengerHandler());private static final class MessengerHandler extends Handler {@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);switch (msg.what) {case MyConstants.MSG_FROM_SERVER: //接受来自 服务端 的消息Log.d(TAG, "receive msg from server: " + msg.getData().get("reply"));break;default:break;}}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//绑定服务端的 Service, 成功后用返回的 IBinder 对象创建 MessengerIntent intent = new Intent(this, MyService.class);bindService(intent, mConnection, Context.BIND_AUTO_CREATE);}private ServiceConnection mConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder binder) {mServiceMessenger = new Messenger(binder); // 获取服务端的 Messenger对象, 通过它向服务端发送消息Message msg = Message.obtain(null, MyConstants.MSG_FROM_CLIENT);Bundle data = new Bundle();data.putString("msg", "hello, this is client");msg.setData(data);msg.replyTo = mClientMessenger ; //将客户端的 Messenger 传给 服务端try {mServiceMessenger.send(msg);} catch (RemoteException e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {}};
}

2.3 服务端

public class MyService extends Service {private static final String TAG = "MyService";//服务端创建 Messenger对象,并绑定对应 Handler, 用于处理 Client 发过来的消息private final Messenger mServiceMessenger = new Messenger(new MessengerHandler());@Nullable@Overridepublic IBinder onBind(Intent intent) {//返回 Binder 对象给 Clientreturn mServiceMessenger.getBinder();}public MyService() {}private static class MessengerHandler extends Handler {@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);switch (msg.what) {case MyConstants.MSG_FROM_CLIENT:Log.d(TAG, "receive msg from client:" + msg.getData().getString("msg"));Messenger clientMessenger = msg.replyTo; //获取传递过来的客户端Messenger对象Message replyMsg = Message.obtain(null, MyConstants.MSG_FROM_SERVER);Bundle bundle = new Bundle();bundle.putString("reply", " server have receive your msg");replyMsg.setData(bundle);try {clientMessenger.send(replyMsg);} catch (RemoteException e) {e.printStackTrace();}break;default:break;}}}
}

2.4 消息常量

public class MyConstants {public static final int MSG_FROM_SERVER = 2;public static final int MSG_FROM_CLIENT = 1;
}

2.5 运行结果

16:12:57.139 31928 31928 D MyService: receive msg from client:hello, this is client
16:12:57.181 31894 31894 D MainActivity: receive msg from server:  server have receive your msg

客户端和服务端关键代码处有注释说明,方便理解。

三. 模型

上面Demo,可以用如下图来说明

四. 源码解析

大多数应用,跨进程只是一对一通信,  并且无需执行多线程处理的业务, 此时使用Messenger更适合一点。

我们重点看如下5个方法:

public final class Messenger implements Parcelable {......//1. mTarget 为 IMessenger接口实例化对象private final IMessenger mTarget;//2. 创建一个指向target Handler的Messenger,//   然后调运Messenger的send 实质是调用Handler的sendMessage方法public Messenger(Handler target) {mTarget = target.getIMessenger();}//3. 跨进程发送消息方法public void send(Message message) throws RemoteException {mTarget.send(message);}//4. 获得Messenger的Binder,一般用在service端获取返回public IBinder getBinder() {return mTarget.asBinder();}//5. 获取getBinder相同的Messenger对象,一般用在client端获取public Messenger(IBinder target) {mTarget = IMessenger.Stub.asInterface(target);}......}

第1个方法  mTarget 为 IMessenger 接口实例化对象, 在java语法规则中,接口类不能直接创建对象, 只能实例化实现该接口的类对象,我们来看看IMessenger.java 它是IMessenger.aidl 文件通过aapt编译自动生成的,具体输出路径为:

out/soong/.intermediates/frameworks/base/framework/android_common/gen/aidl/frameworks/base/core/java/android/os/IMessenger.java

public interface IMessenger extends android.os.IInterface {......
}

它是一个public 接口类,不能直接通过new IMessenge() 来创建对象,但是可以new 实现了该接口的类对象。

第2和5个方法 是Messenger类的两个构造方法

  private final IMessenger mTarget;public Messenger(Handler target) {mTarget = target.getIMessenger();}public Messenger(IBinder target) {mTarget = IMessenger.Stub.asInterface(target);}

可以这样子理解两个方法的用途: 

1. 参数为Handler的是远程端进程的实例方法

2. 参数为IBinder的是客户端进程的实例方法

第1个构造方法的内容:

//frameworks/base/core/java/android/os/Handler.java 文件中IMessenger mMessenger;//对于一个Handler对象来说getIMessenger得到的Messenger是一个单例模式对象
final IMessenger getIMessenger() {synchronized (mQueue) {if (mMessenger != null) {return mMessenger;}//这里就是new了一个实现该接口类的对象mMessenger = new MessengerImpl();return mMessenger;}}//这里其实是IMessenger.aidl的接口send的具体实现类private final class MessengerImpl extends IMessenger.Stub {public void send(Message msg) {msg.sendingUid = Binder.getCallingUid();//核心还是与该(进程绑定的Handler)去发送消息Handler.this.sendMessage(msg);}}

结论:Messenger类中的mTarget其实就是一个Handler中 实现了(IMessenger远程IPC send接口)的MessengerImpl 单例对象。

第2个方法的使用,就是在客户端拿到服务端的Messenger对象

在MyService.java中 我们看下Service中的onBind实现,其调运了Messenger的getBinder方法,这个方法源码如下:

    //服务端创建 Messenger对象,并绑定对应 Handler, 用于处理 Client 发过来的消息private final Messenger mServiceMessenger = new Messenger(new MessengerHandler());@Nullable@Overridepublic IBinder onBind(Intent intent) {//返回 Binder 对象给 Clientreturn mServiceMessenger .getBinder();}
    public IBinder getBinder() {return mTarget.asBinder();}//调用mTarget.asBinder()方法,也即是this对象自己//在 Stub类中public static abstract class Stub extends android.os.Binder implements android.os.IMessenger{....@Override public android.os.IBinder asBinder(){return this;}....}//还记得上面的Handler类中的 MessengerImpl 实现了 IMessenger.StubIMessenger mMessenger = new MessengerImpl()private final class MessengerImpl extends IMessenger.Stub {}

可以看见,其实asBinder返回的就是this, 也就是把Service中的Messenger通过onBind方法返回给客户端。

然后再回到客户端 MainActivity.java 中的 onServiceConnected 方法

    private Messenger mServiceMessenger;private final IMessenger mTarget;// 1. 获取服务端的 Messenger对象, 通过它向服务端发送消息public void onServiceConnected(ComponentName name, IBinder binder) {mServiceMessenger = new Messenger(binder); // 2. 上面的 new Messenger(binder)调用方法/*** Create a Messenger from a raw IBinder, which had previously been* retrieved with {@link #getBinder}.* * @param target The IBinder this Messenger should communicate with.*/public Messenger(IBinder target) {mTarget = IMessenger.Stub.asInterface(target);}

通过asInterface方法转化一下,由于不在同一个进程,会把Stub转换成Proxy代理对象

    public static android.os.IMessenger asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof android.os.IMessenger))) {return ((android.os.IMessenger)iin);}return new android.os.IMessenger.Stub.Proxy(obj);}

就这样客户端就拿到了服务端的Messenger对象,接下来就可以在客户端中用Messenger给服务端发送消息了。

五. 小结

1.  客户端和服务端都有自己的Handler对象,用于在各自的进程中接收处理消息,发送消息则是和Handler绑定的Messenger对象。

2.  通过IMessenger.aidl 中的 send(Message msg)方法进行跨进程通信, 注意 msg.replyTo变量实则是一个Messenger对象, 用于两个进程传递各自的Messenger对象。

这篇关于Android轻量级进程间通信Messenger源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/730907

相关文章

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

linux进程D状态的解决思路分享

《linux进程D状态的解决思路分享》在Linux系统中,进程在内核模式下等待I/O完成时会进入不间断睡眠状态(D状态),这种状态下,进程无法通过普通方式被杀死,本文通过实验模拟了这种状态,并分析了如... 目录1. 问题描述2. 问题分析3. 实验模拟3.1 使用losetup创建一个卷作为pv的磁盘3.

C#使用DeepSeek API实现自然语言处理,文本分类和情感分析

《C#使用DeepSeekAPI实现自然语言处理,文本分类和情感分析》在C#中使用DeepSeekAPI可以实现多种功能,例如自然语言处理、文本分类、情感分析等,本文主要为大家介绍了具体实现步骤,... 目录准备工作文本生成文本分类问答系统代码生成翻译功能文本摘要文本校对图像描述生成总结在C#中使用Deep

Linux环境变量&&进程地址空间详解

《Linux环境变量&&进程地址空间详解》本文介绍了Linux环境变量、命令行参数、进程地址空间以及Linux内核进程调度队列的相关知识,环境变量是系统运行环境的参数,命令行参数用于传递给程序的参数,... 目录一、初步认识环境变量1.1常见的环境变量1.2环境变量的基本概念二、命令行参数2.1通过命令编程

Linux之进程状态&&进程优先级详解

《Linux之进程状态&&进程优先级详解》文章介绍了操作系统中进程的状态,包括运行状态、阻塞状态和挂起状态,并详细解释了Linux下进程的具体状态及其管理,此外,文章还讨论了进程的优先级、查看和修改进... 目录一、操作系统的进程状态1.1运行状态1.2阻塞状态1.3挂起二、linux下具体的状态三、进程的

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操