Android 进阶10:进程通信之 Messenger 使用与解析

2024-06-02 07:18

本文主要是介绍Android 进阶10:进程通信之 Messenger 使用与解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

读完本文你将了解:

    • Messenger 简介
    • Messenger 的使用
      • 服务端
      • 客户端
      • 运行效果
      • 使用小结
    • 总结
    • 代码地址
    • Thanks

前面我们介绍了 AIDL 的使用与原理,这篇文章来介绍下 Android 中另一种 IPC 方式:Messenger。

Messenger 简介

Messenger “信使”,顾名思义,它的作用就是传递信息。

Messenger 有两个构造函数:

  1. 以 Handler 为参数
  2. 以 Binder 为参数
private final IMessenger mTarget;
public Messenger(Handler target) {mTarget = target.getIMessenger();
}
public Messenger(IBinder target) {mTarget = IMessenger.Stub.asInterface(target);    //和前面的 AIDL 很相似吧
}

看下 Handler.getIMessenger() 源码:

final IMessenger getIMessenger() {synchronized (mQueue) {if (mMessenger != null) {return mMessenger;}mMessenger = new MessengerImpl();return mMessenger;}
}

这个 IMessanger 应该也是个 AIDL 生成的类吧,看下源码,果然是:

public interface IMessenger extends android.os.IInterface {/** Local-side IPC implementation stub class. */public static abstract class Stub extends android.os.Binder implementsandroid.os.IMessenger {private static final java.lang.String DESCRIPTOR = "android.os.IMessenger";public Stub() {this.attachInterface(this, DESCRIPTOR);}public static android.os.IMessenger asInterface(...}public android.os.IBinder asBinder() {return this;}@Overridepublic boolean onTransact(int code, android.os.Parcel data,android.os.Parcel reply, int flags)throws android.os.RemoteException {...}private static class Proxy implements android.os.IMessenger {...}public void send(android.os.Message msg)throws android.os.RemoteException;
}

IMessenger 是 AIDL 生成的跨进程接口,里面定义了一个发送消息的方法:

    public void send(android.os.Message msg)throws android.os.RemoteException;

HandlerMessengerImpl 实现了这个方法,就是使用 Handler 将消息发出去:

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

这就解释了为什么我们的消息来得时候会出现在 Handler.handlerMessage()

接着再看下 Messenger 另一个重要的方法,send()

public void send(Message message) throws RemoteException {mTarget.send(message);
}

Messenger 中持有一个 IMessenger 的引用,在构造函数中可以通过 Handler 或者 Binder 的形式获得最终的 IMessenger 实现,然后调用它的 send() 方法。

Messenger 其实就是 AIDL 的简化版,它把接口都封装好,我们只需在一个进程创建一个 Handler 传递给 Messenger,Messenger 帮我们把消息跨进程传递到另一个进程,我们在另一个进程的 Handler 在处理消息就可以了。

Messenger 的使用

Messenger 的使用需要结合 Handler, Message, Bundle

下面我们将写一个客户端跨进程发送消息到服务端的例子,服务端在收到消息后会回复,由于在 Messenger 中一个对象对应一个 Handler,所以我们需要在客户端、服务端分别创建一个 Messenger:

这里写图片描述

服务端在收到消息后会使用 Message.replyTo 对应的信使回复消息。

服务端

服务端只需要创建一个 Messenger 对象,然后给它传递一个 Handler,在 Handler 中处理消息:

public class MessengerService extends BaseService {private final String TAG = this.getClass().getSimpleName();Messenger mMessenger = new Messenger(new Handler() {@Overridepublic void handleMessage(final Message msg) {if (msg != null && msg.arg1 == ConfigHelper.MSG_ID_CLIENT) {if (msg.getData() == null) {return;}String content = (String) msg.getData().get(ConfigHelper.MSG_CONTENT);  //接收客户端的消息LogUtils.d(TAG, "Message from client: " + content);//回复消息给客户端Message replyMsg = Message.obtain();replyMsg.arg1 = ConfigHelper.MSG_ID_SERVER;Bundle bundle = new Bundle();bundle.putString(ConfigHelper.MSG_CONTENT, "听到你的消息了,请说点正经的");replyMsg.setData(bundle);try {msg.replyTo.send(replyMsg);     //回信} catch (RemoteException e) {e.printStackTrace();}}}});@Nullable@Overridepublic IBinder onBind(final Intent intent) {return mMessenger.getBinder();}
}

客户端

public class IPCTestActivity extends BaseActivity {private final String TAG = this.getClass().getSimpleName();@BindView(R.id.tv_result)TextView mTvResult;@BindView(R.id.btn_add_person)Button mBtnAddPerson;@BindView(R.id.et_msg_content)EditText mEtMsgContent;@BindView(R.id.btn_send_msg)Button mBtnSendMsg;/*** 客户端的 Messenger*/Messenger mClientMessenger = new Messenger(new Handler() {@Overridepublic void handleMessage(final Message msg) {if (msg != null && msg.arg1 == ConfigHelper.MSG_ID_SERVER){if (msg.getData() == null){return;}String content = (String) msg.getData().get(ConfigHelper.MSG_CONTENT);LogUtils.d(TAG, "Message from server: " + content);}}});//服务端的 Messengerprivate Messenger mServerMessenger;private ServiceConnection mMessengerConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(final ComponentName name, final IBinder service) {mServerMessenger = new Messenger(service);}@Overridepublic void onServiceDisconnected(final ComponentName name) {mServerMessenger = null;}};@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_aidl);ButterKnife.bind(this);bindAIDLService();bindMessengerService();}private void bindMessengerService() {Intent intent = new Intent(this, MessengerService.class);bindService(intent, mMessengerConnection, BIND_AUTO_CREATE);}@OnClick(R.id.btn_send_msg)public void sendMsg() {String msgContent = mEtMsgContent.getText().toString();msgContent = TextUtils.isEmpty(msgContent) ? "默认消息" : msgContent;Message message = Message.obtain();message.arg1 = ConfigHelper.MSG_ID_CLIENT;Bundle bundle = new Bundle();bundle.putString(ConfigHelper.MSG_CONTENT, msgContent);message.setData(bundle);message.replyTo = mClientMessenger;     //指定回信人是客户端定义的try {mServerMessenger.send(message);} catch (RemoteException e) {e.printStackTrace();}}@Overrideprotected void onDestroy() {super.onDestroy();unbindService(mMessengerConnection);}}

运行效果

这里写图片描述

发送后,服务端进程收到消息:
这里写图片描述

然后进行了答复:
这里写图片描述

使用小结

可以看到客户端的操作主要有 3 步:

  1. 创建客户端的 Messenger,传递一个 Handler 处理消息
  2. bindService,在 ServiceConnection 回调中拿到服务端的 Messenger
  3. 发送消息
    • Message.obtain() 消息池里获取一个空闲消息对象
    • 使用 message.setData(bundle) 设置数据
    • 指定回信的信使 message.replyTo = mClientMessenger
    • 调用服务端信使,发射!mServerMessenger.send(message)

总结

Messenger 对 AIDL 进行了封装,也就是对 Binder 的封装,我们可以使用它的实现来完成基于消息的跨进程通信,就和使用 Handler 一样简单。

使用步骤:

  1. 客户端创建一个 Messenger,传递一个 Handler 处理消息
  2. 服务端也一样

如果需要回信,给 Message 设置一个用于回信的 Messenger 即可:

message.replyTo = mClientMessenger;

客户端在调用send()方法之后,就会走 Binder 跨进程通信机制 ,最后到服务端的 Handler 中得到处理。

借用鸿洋的图表达一下:

使用时和 Binder 一样,建议在四大组件中使用,那样可以提高优先级,让系统不随便关闭当前进程。

代码地址

Thanks

https://developer.android.com/reference/android/os/Messenger.html
http://book2s.com/java/src/package/android/os/imessenger.html
http://www.jianshu.com/p/af8991c83fcb
http://blog.csdn.net/lmj623565791/article/details/47017485

这篇关于Android 进阶10:进程通信之 Messenger 使用与解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Spring LDAP目录服务的使用示例

《SpringLDAP目录服务的使用示例》本文主要介绍了SpringLDAP目录服务的使用示例... 目录引言一、Spring LDAP基础二、LdapTemplate详解三、LDAP对象映射四、基本LDAP操作4.1 查询操作4.2 添加操作4.3 修改操作4.4 删除操作五、认证与授权六、高级特性与最佳

Android Studio 配置国内镜像源的实现步骤

《AndroidStudio配置国内镜像源的实现步骤》本文主要介绍了AndroidStudio配置国内镜像源的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、修改 hosts,解决 SDK 下载失败的问题二、修改 gradle 地址,解决 gradle

Qt spdlog日志模块的使用详解

《Qtspdlog日志模块的使用详解》在Qt应用程序开发中,良好的日志系统至关重要,本文将介绍如何使用spdlog1.5.0创建满足以下要求的日志系统,感兴趣的朋友一起看看吧... 目录版本摘要例子logmanager.cpp文件main.cpp文件版本spdlog版本:1.5.0采用1.5.0版本主要

Java中使用Hutool进行AES加密解密的方法举例

《Java中使用Hutool进行AES加密解密的方法举例》AES是一种对称加密,所谓对称加密就是加密与解密使用的秘钥是一个,下面:本文主要介绍Java中使用Hutool进行AES加密解密的相关资料... 目录前言一、Hutool简介与引入1.1 Hutool简介1.2 引入Hutool二、AES加密解密基础

MySQL中FIND_IN_SET函数与INSTR函数用法解析

《MySQL中FIND_IN_SET函数与INSTR函数用法解析》:本文主要介绍MySQL中FIND_IN_SET函数与INSTR函数用法解析,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一... 目录一、功能定义与语法1、FIND_IN_SET函数2、INSTR函数二、本质区别对比三、实际场景案例分

使用Python将JSON,XML和YAML数据写入Excel文件

《使用Python将JSON,XML和YAML数据写入Excel文件》JSON、XML和YAML作为主流结构化数据格式,因其层次化表达能力和跨平台兼容性,已成为系统间数据交换的通用载体,本文将介绍如何... 目录如何使用python写入数据到Excel工作表用Python导入jsON数据到Excel工作表用

鸿蒙中@State的原理使用详解(HarmonyOS 5)

《鸿蒙中@State的原理使用详解(HarmonyOS5)》@State是HarmonyOSArkTS框架中用于管理组件状态的核心装饰器,其核心作用是实现数据驱动UI的响应式编程模式,本文给大家介绍... 目录一、@State在鸿蒙中是做什么的?二、@Spythontate的基本原理1. 依赖关系的收集2.

Python基础语法中defaultdict的使用小结

《Python基础语法中defaultdict的使用小结》Python的defaultdict是collections模块中提供的一种特殊的字典类型,它与普通的字典(dict)有着相似的功能,本文主要... 目录示例1示例2python的defaultdict是collections模块中提供的一种特殊的字

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

在Android平台上实现消息推送功能

《在Android平台上实现消息推送功能》随着移动互联网应用的飞速发展,消息推送已成为移动应用中不可或缺的功能,在Android平台上,实现消息推送涉及到服务端的消息发送、客户端的消息接收、通知渠道(... 目录一、项目概述二、相关知识介绍2.1 消息推送的基本原理2.2 Firebase Cloud Me