鸿蒙OS 线程间通信

server/2024/9/21 10:20:41/

鸿蒙OS 线程间通信概述

在开发过程中,开发者经常需要在当前线程中处理下载任务等较为耗时的操作,但是又不希望当前的线程受到阻塞。此时,就可以使用 EventHandler 机制。EventHandler 是 HarmonyOS 用于处理线程间通信的一种机制,可以通过 [EventRunner] 创建新线程,将耗时的操作放到新线程上执行。这样既不阻塞原来的线程,任务又可以得到合理的处理。比如:主线程使用 EventHandler 创建子线程,子线程做耗时的下载图片操作,下载完成后,子线程通过 EventHandler 通知主线程,主线程再更新 UI。

基本概念
EventRunner 是一种事件循环器,循环处理从该 EventRunner 创建的新线程的事件队列中获取 InnerEvent 事件或者 Runnable 任务。InnerEvent 是 EventHandler 投递的事件。

EventHandler 是一种用户在当前线程上投递 InnerEvent 事件或者 Runnable 任务到异步线程上处理的机制。每一个 EventHandler 和指定的 EventRunner 所创建的新线程绑定,并且该新线程内部有一个事件队列。EventHandler 可以投递指定的 InnerEvent 事件或 Runnable 任务到这个事件队列。EventRunner 从事件队列里循环地取出事件,如果取出的事件是 InnerEvent 事件,将在 EventRunner 所在线程执行 processEvent 回调;如果取出的事件是 Runnable 任务,将在 EventRunner 所在线程执行 Runnable 的 run 回调。一般,EventHandler 有两个主要作用:

在不同线程间分发和处理 InnerEvent 事件或 Runnable 任务。
延迟处理 InnerEvent 事件或 Runnable 任务。

运作机制
EventHandler 的运作机制如下图所示:

在这里插入图片描述

使用 EventHandler 实现线程间通信的主要流程:

EventHandler 投递具体的 InnerEvent 事件或者 Runnable 任务到 EventRunner 所创建的线程的事件队列。
EventRunner 循环从事件队列中获取 InnerEvent 事件或者 Runnable 任务。
处理事件或任务:

如果 EventRunner 取出的事件为 InnerEvent 事件,则触发 EventHandler 的回调方法并触发 EventHandler 的处理方法,在新线程上处理该事件。
如果 EventRunner 取出的事件为 Runnable 任务,则 EventRunner 直接在新线程上处理 Runnable 任务。

约束限制
在进行线程间通信的时候,EventHandler 只能和 EventRunner 所创建的线程进行绑定,EventRunner 创建时需要判断是否创建成功,只有确保获取的 EventRunner 实例非空时,才可以使用 EventHandler 绑定 EventRunner。
一个 EventHandler 只能同时与一个 EventRunner 绑定,一个 EventRunner 上可以创建多个 EventHandler。

鸿蒙OS 线程间通信开发指导

EventHandler开发场景

EventHandler 的主要功能是将 InnerEvent 事件或者 Runnable 任务投递到其他的线程进行处理,其使用的场景包括:

开发者需要将 InnerEvent 事件投递到新的线程,按照优先级和延时进行处理。投递时,EventHandler 的优先级可在 IMMEDIATE、HIGH、LOW、IDLE 中选择,并设置合适的 delayTime。
开发者需要将 Runnable 任务投递到新的线程,并按照优先级和延时进行处理。投递时, EventHandler 的优先级可在 IMMEDIATE、HIGH、LOW、IDLE 中选择,并设置合适的 delayTime。
开发者需要在新创建的线程里投递事件到原线程进行处理。

EventRunner工作模式

EventRunner 的工作模式可以分为托管模式和手动模式。两种模式是在调用 EventRunner 的 create() 方法时,通过选择不同的参数来实现的,详见 API 参考。默认为托管模式。

托管模式:不需要开发者调用 run() 和 stop() 方法去启动和停止 EventRunner。当 EventRunner 实例化时,系统调用 run() 来启动 EventRunner;当 EventRunner 不被引用时,系统调用 stop() 来停止 EventRunner。
手动模式:需要开发者自行调用 EventRunner 的 run() 方法和 stop() 方法来确保线程的启动和停止。

接口说明

EventHandler

EventHandler 的属性 Priority (优先级)介绍:
EventRunner 将根据优先级的高低从事件队列中获取事件或者 Runnable 任务进行处理。

在这里插入图片描述

EventHandler 的主要接口介绍:
在这里插入图片描述

EventRunner

EventRunner的主要接口介绍:
在这里插入图片描述

InnerEvent

InnerEvent的属性介绍:
在这里插入图片描述

InnerEvent的主要接口介绍:
在这里插入图片描述

开发步骤
EventHandler 投递 InnerEvent 事件

EventHandler 投递 InnerEvent 事件,并按照优先级和延时进行处理,开发步骤如下:

创建 EventHandler 的子类,在子类中重写实现方法

processEvent() 来处理事件。private class MyEventHandler extends EventHandler {private MyEventHandler(EventRunner runner) {super(runner);}// 重写实现processEvent方法public void processEvent(InnerEvent event) {super.processEvent(event);if (event == null) {return;}int eventId = event.eventId;long param = event.param;switch (eventId | param) {case CASE1:// 待执行的操作,由开发者定义break;default:break;}}}

创建 EventRunner,以手动模式为例。

  EventRunner runner = EventRunner.create(false);// create()的参数是 true时,则为托管模式// 需要对 EventRunner 的实例进行校验,因为创建 EventRunner 可能失败,如创建线程失败时,创建 EventRunner 失败。if (runner == null) {return;}

创建 EventHandler 子类的实例。

MyEventHandler myHandler = new MyEventHandler(runner);

获取 InnerEvent 事件。

 // 获取事件实例,其属性 eventId, param, object 由开发者确定,代码中只是示例。int eventId1 = 0;int eventId2 = 1; long param = 0; Object object = null; InnerEvent event1 = InnerEvent.get(eventId1, param, object);InnerEvent event2 = InnerEvent.get(eventId2, param, object);

投递事件,投递的优先级以 IMMEDIATE 为例,延时选择 0ms和 2ms。

 // 优先级 immediate,投递之后立即处理,延时为 0ms,该语句等价于同步投递sendSyncEvent(event1,EventHandler.Priority.immediate);myHandler.sendEvent(event1, 0, EventHandler.Priority.IMMEDIATE);myHandler.sendEvent(event2, 2, EventHandler.Priority.IMMEDIATE); // 延时 2ms 后立即处理

启动和停止 EventRunner,如果为托管模式,则不需要此步骤。

 runner.run();//待执行操作runner.stop();// 开发者根据业务需要在适当时机停止 EventRunner

EventHandler 投递 Runnable 任务

EventHandler 投递Runnable 任务,并按照优先级和延时进行处理,开发步骤如下:

创建 EventHandler 的子类,创建 EventRunner,并创建 EventHandler 子类的实例,步骤与[ EventHandler 投递 InnerEvent] 场景的步骤1-3相同。
创建 Runnable 任务。

  Runnable task1 = new Runnable() {public void run() {// 待执行的操作,由开发者定义}};Runnable task2 = new Runnable() {public void run() {// 待执行的操作,由开发者定义}};

投递 Runnable 任务,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。

   //优先级为 immediate,延时 0ms,该语句等价于同步投递myHandler.postSyncTask(task1,EventHandler.Priority.immediate);myHandler.postTask(task1,0EventHandler.Priority.IMMEDIATE);myHandler.postTask(task2,2EventHandler.Priority.IMMEDIATE);// 延时2ms后立即执行

启动和停止 EventRunner,如果是托管模式,则不需要此步骤。

 runner.run();//待执行操作runner.stop();// 停止 EventRunner

在新创建的线程里投递事件到原线程

EventHandler 从新创建的线程投递事件到原线程并进行处理,开发步骤如下:

创建 EventHandler 的子类,在子类中重写实现方法 processEvent() 来处理事件。

 private class MyEventHandler extends EventHandler {private MyEventHandler(EventRunner runner) {super(runner);}// 重写实现processEvent方法public void processEvent(InnerEvent event) {super.processEvent(event);if (event == null) {return;}int eventId = event.eventId;long param = event.param;Object object = event.object;switch (eventId | param) {case CASE1:// 待执行的操作,由开发者定义break;case CASE2:// 将原先线程的EventRunner实例投递给新创建的线程if (object instanceof EventRunner) {EventRunner runner2 = (EventRunner)object;}// 将原先线程的EventRunner实例与新创建的线程的EventHandler绑定EventHandler myHandler2 = new EventHandler(runner2) {public void processEvent(InnerEvent event) {//需要在原先线程执行的操作}};int eventId = 1; long param = 0; Object object = null; InnerEvent event2 = InnerEvent.get(eventId, param, object);myHandler2.sendEvent(event2); // 投递事件到原先的线程break;default:break;}}}

创建 EventRunner,以手动模式为例。

  EventRunner runner1 = EventRunner.create(false);// create()的参数是true时,则为托管模式。// 需要对 EventRunner 的实例进行校验,不是任何线程都可以通过 create 创建,例如:当线程池已满时,不能再创建线程。if (runner1 == null) {return;}

创建 EventHandler 子类的实例。

   MyEventHandler myHandler1 = new MyEventHandler(runner1);

获取 InnerEvent 事件。

 // 获取事件实例,其属性 eventId, param, object 由开发者确定,代码中只是示例。int eventId1 = 0;long param = 0; Object object = (Object) EventRunner.current();InnerEvent event1 = InnerEvent.get(eventId1, param, object);

投递事件,在新线程上直接处理。

 // 将与当前线程绑定的 EventRunner 投递到与 runner1 创建的新线程中  myHandler.sendEvent(event1);

启动和停止 EventRunner,如果是托管模式,则不需要此步骤。

 runner.run();//待执行操作runner.stop();// 停止 EventRunner

**完整代码示例

非托管情况:**

 //全局:EventRunner runnerA//线程A:runnerA = EventRunner.create(false);runnerA.run(); // run之后一直循环卡在这里,所以需要新建一个线程run//线程B://1.创建类继承EventHandlerpublic class MyEventHandler extends EventHandler {public static int CODE_DOWNLOAD_FILE1;public static int CODE_DOWNLOAD_FILE2;public static int CODE_DOWNLOAD_FILE3;private MyEventHandler(EventRunner runner) {super(runner);}public void processEvent(InnerEvent event) {super.processEvent(event);if (event == null) {return;}int eventId = event.eventId;if (STOP_EVENT_ID != eventId) {resultEventIdList.add(eventId);}switch (eventId) {case CODE_DOWNLOAD_FILE1: {... // your processbreak;}case CODE_DOWNLOAD_FILE1: {... // your processbreak;}case CODE_DOWNLOAD_FILE1: {... // your processbreak;}default:break;}}}//2.创建 MyEventHandler 实例MyEventHandler handler = new MyEventHandler(runnerA);// 3.向线程 A 发送事件handler.sendEvent(CODE_DOWNLOAD_FILE1);handler.sendEvent(CODE_DOWNLOAD_FILE2);handler.sendEvent(CODE_DOWNLOAD_FILE3);......// 4.runnerA 不再使用后,退出runnerA.stop();

托管情况:

 //1.创建 EventRunner A:EventRunner runnerA = EventRunner.create("downloadRunner"); // 内部会新建一个线程//2.创建类继承 EventHandlerpublic class MyEventHandler extends EventHandler {public static int CODE_DOWNLOAD_FILE1;public static int CODE_DOWNLOAD_FILE2;public static int CODE_DOWNLOAD_FILE3;private MyEventHandler(EventRunner runner) {super(runner);}public void processEvent(InnerEvent event) {super.processEvent(event);if (event == null) {return;}int eventId = event.eventId;if (STOP_EVENT_ID != eventId) {resultEventIdList.add(eventId);}switch (eventId) {case CODE_DOWNLOAD_FILE1: {... // your processbreak;}case CODE_DOWNLOAD_FILE1: {... // your processbreak;}case CODE_DOWNLOAD_FILE1: {... // your processbreak;}default:break;}}}//3.创建MyEventHandler实例MyEventHandler handler = new MyEventHandler(runnerA);//4.向线程A发送事件handler.sendEvent(CODE_DOWNLOAD_FILE1);handler.sendEvent(CODE_DOWNLOAD_FILE2);handler.sendEvent(CODE_DOWNLOAD_FILE3);......//5.runnerA没有任何对象引入时,线程会自动回收runnerA = null;

http://www.ppmy.cn/server/119771.html

相关文章

Oracle(129) 如何使用闪回归档(Flashback Archive)?

闪回归档(Flashback Archive)是Oracle数据库提供的一个功能,用于长期存储表的历史数据。通过启用和配置闪回归档,你可以查询表的历史数据,而不需要依赖撤销段或归档日志。这对于审计、合规性和历史数据分析非常有用。 …

OpenAI API key not working in my React App

题意:OpenAI API 密钥在我的 React 应用中不起作用 问题背景: I am trying to create a chatbot in my react app, and Im not able to generate an LLM powered response. Ive been studying documentation and checking out tutorials but am unable …

JavaWeb JavaScript 11.XML —— 配置文件

生活想埋没我,没想到我是颗种子 —— 24.9.19 一、XML 1.什么是XML XML是EXtensible Markup Languge的缩写,翻译过来就是可扩展标记语言。所以很明显,XML和HTML一样都是标记语言,也就是说它们的基本语法都是标签 可扩展 三个字…

RetrievalAttention——提高 LLM 处理长上下文的效率

概述 论文地址:https://arxiv.org/abs/2409.10516 本文的研究背景主要是为了解决 "具有长语境的大型语言模型(LLM)"问题。基于变换器的 LLM 被广泛应用于各个领域,但在处理长上下文时,其计算成本非常高。特…

(undone) 学习语音学中关于 i-vector 和 x-vector

来源:https://ieeexplore.ieee.org/stamp/stamp.jsp?tp&arnumber8461375 (这是一篇跟 X-vector 有关的论文) 这里有更适合初学者的两个资料: 1.https://www.youtube.com/watch?vR3rzN6JYm38 (MIT教授的youtube视频) 2.https://people.c…

无人机之4G模块的主要功能和优势

一、增强图传 在无人机飞行过程中,传统的图传方式可能会受到信号遮挡或干扰的影响,导致图像传输不稳定甚至中断。而4G模块通过结合4G网络技术,能够在原有图传技术的基础上提供增强的图传功能。当传统图传信号不佳时,无人机可以自动…

《MmAP : Multi-Modal Alignment Prompt for Cross-Domain Multi-Task Learning》中文校对版

系列论文研读目录 文章目录 系列论文研读目录摘要1 引言2 相关工作3 方法3.1对比图像预训练3.2 多模式对齐提示3.3 多任务提示学习框架 4 实验4.1基准设置4.2实验结果4.3消融研究 5、结论 摘要 多任务学习(Multi-Task Learning,MTL)是为了同…

离散型制造业MES系统主要功能介绍

一、离散型制造业的特点 离散型制造业是指生产过程中涉及多个独立工序或步骤,且这些工序之间相对独立、缺乏连续性的企业。其特点主要包括: 产品种类多,开发频繁: 离散型制造业通常需要进行多品种产品开发,产品种类繁…