一、概述
① 基本概念
- 在开发过程中,开经常需要在当前线程中处理下载任务等较为耗时的操作,但是又不希望当前的线程受到阻塞。此时,就可以使用 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 投递具体的 InnerEvent 事件或者 Runnable 任务到 EventRunner 所创建的线程的事件队列。
-
- EventRunner 循环从事件队列中获取 InnerEvent 事件或者 Runnable 任务。
-
-
-
- 如果 EventRunner 取出的事件为 InnerEvent 事件,则触发 EventHandler 的回调方法并触发 EventHandler 的处理方法,在新线程上处理该事件。
-
-
- 如果 EventRunner 取出的事件为 Runnable 任务,则 EventRunner 直接在新线程上处理 Runnable 任务。
③ 约束和限制
- 在进行线程间通信的时候,EventHandler 只能和 EventRunner 所创建的线程进行绑定, EventRunner 创建时需要判断是否创建成功,只有确保获取的 EventRunner 实例非空时,才可以使用 EventHandler 绑定 EventRunner。
- 一个 EventHandler 只能同时与一个 EventRunner 绑定,一个 EventRunner 可以同时绑定多个 EventHandler。
二、应用场景
① EventHandler 开发场景
- EventHandler 的主要功能是将 InnerEvent 事件或者 Runnable 任务投递到其他的线程进行处理,其使用的场景包括:
-
- 开发者需要将 InnerEvent 事件投递到新的线程,按照优先级和延时进行处理。投递时,EventHandler 的优先级可在 IMMEDIATE、HIGH、LOW、IDLE 中选择,并设置合适的 delayTime。
-
- 开发者需要将 Runnable 任务投递到新的线程,并按照优先级和延时进行处理。投递时,EventHandler 的优先级可在 IMMEDIATE、HIGH、LOW、IDLE 中选择,并设置合适的 delayTime。
-
② EventRunner 工作模式
- EventRunner 的工作模式可以分为托管模式和手动模式。两种模式是在调用 EventRunner 的 create() 方法时,通过选择不同的参数来实现的,默认为托管模式。
-
- 托管模式:不需要调用 run() 和 stop() 方法去启动和停止 EventRunner。当 EventRunner 实例化时,系统调用 run() 来启动 EventRunner;当 EventRunner 不被引用时,系统调用 stop() 来停止 EventRunner。
-
- 手动模式:需要自行调用 EventRunner 的 run() 方法和 stop() 方法来确保线程的启动和停止。
三、API 说明
① EventHandler
- EventHandler 的属性 Priority(优先级):EventRunner 将根据优先级的高低从事件队列中获取事件或者 Runnable 任务进行处理。
- EventHandler 的属性:
属性 | 描述 |
---|
Priority.IMMEDIATE | 表示事件被立即投递 |
Priority.HIGH | 表示事件先于LOW优先级投递 |
Priority.LOW | 表示事件优于IDLE优先级投递,事件的默认优先级是LOW |
Priority.IDLE | 表示在没有其他事件的情况下,才投递该事件 |
接口名 | 描述 |
---|
EventHandler(EventRunner runner) | 利用已有的EventRunner来创建EventHandler |
current() | 在processEvent回调中,获取当前的EventHandler |
processEvent(InnerEvent event) | 回调处理事件,由开发者实现 |
sendEvent(InnerEvent event) | 发送一个事件到事件队列,延时为0ms, 优先级为LOW |
sendEvent(InnerEvent event, long delayTime) | 发送一个延时事件到事件队列,优先级为LOW |
sendEvent(InnerEvent event, long delayTime, EventHandler.Priority priority) | 发送一个指定优先级的延时事件到事件队列 |
sendEvent(InnerEvent event, EventHandler.Priority priority) | 发送一个指定优先级的事件到事件队列,延时为0ms |
sendSyncEvent(InnerEvent event) | 发送一个同步事件到事件队列,延时为0ms,优先级为LOW |
sendSyncEvent(InnerEvent event, EventHandler.Priority priority) | 发送一个指定优先级的同步事件到事件队列,延时为0ms,优先级不可以是IDLE |
postSyncTask(Runnable task) | 发送一个Runnable同步任务到事件队列,延时为0ms, 优先级为LOW |
postSyncTask(Runnable task, EventHandler.Priority priority) | 发送一个指定优先级的Runnable同步任务到事件队列,延时为0ms |
postTask(Runnable task) | 发送一个Runnable任务到事件队列,延时为0ms,优先级为LOW |
postTask(Runnable task, long delayTime) | 发送一个Runnable延时任务到事件队列,优先级为LOW |
postTask(Runnable task, long delayTime, EventHandler.Priority priority) | 发送一个指定优先级的Runnable延时任务到事件队列 |
postTask(Runnable task, EventHandler.Priority priority) | 发送一个指定优先级的Runnable任务到事件队列,延时为0ms |
sendTimingEvent(InnerEvent event, long taskTime) | 发送一个定时事件到队列,在taskTime时间执行,如果taskTime小于当前时间,立即执行,优先级为LOW |
sendTimingEvent(InnerEvent event, long taskTime, EventHandler.Priority priority) | 发送一个带优先级的事件到队列,在taskTime时间执行,如果taskTime小于当前时间,立即执行 |
postTimingTask(Runnable task, long taskTime) | 发送一个Runnable任务到队列,在taskTime时间执行,如果taskTime小于当前时间,立即执行,优先级为LOW |
postTimingTask(Runnable task, long taskTime, EventHandler.Priority priority) | 发送一个带优先级的Runnable任务到队列,在taskTime时间执行,如果taskTime小于当前时间,立即执行 |
removeEvent(int eventId) | 删除指定id的事件 |
removeEvent(int eventId, long param) | 删除指定id和param的事件 |
removeEvent(int eventId, long param, Object object) | 删除指定id、param和object的事件 |
removeAllEvent() | 删除该EventHandler的所有事件 |
getEventName(InnerEvent event) | 获取事件的名字 |
getEventRunner() | 获取该EventHandler绑定的EventRunner |
isIdle() | 判断队列是否为空 |
hasInnerEvent(Runnable runnable) | 根据指定的runnable参数,检查是否有还未被处理的任务。可以根据不同的入参进行检查,详见EventHandler |
② EventRunner
接口名 | 描述 |
---|
create() | 创建一个拥有新线程的EventRunner |
create(boolean inNewThread) | 创建一个拥有新线程的EventRunner,inNewThread为true时,EventRunner为托管模式,系统将自动管理该EventRunner;inNewThread为false时,EventRunner为手动模式 |
create(String newThreadName) | 创建一个拥有新线程的EventRunner, 新线程的名字是 newThreadName |
current() | 获取当前线程的EventRunner |
run() | EventRunner为手动模式时,调用该方法启动新的线程 |
stop() | EventRunner为手动模式时,调用该方法停止新的线程 |
③ InnerEvent
属性 | 描述 |
---|
eventId | 事件的ID, 由开发者定义用来辨别事件 |
object | 事件携带的Object信息 |
param | 事件携带的long型数据 |
接口名 | 描述 |
---|
drop() | 释放一个事件实例 |
get() | 获得一个事件实例 |
get(int eventId) | 获得一个指定的eventId的事件实例 |
get(int eventId, long param) | 获得一个指定的eventId和param的事件实例 |
get(int eventId, long param, Object object) | 获得一个指定的eventId,param和object的事件实例 |
get(int eventId, Object object) | 获得一个指定的eventId和object的事件实例 |
PacMap getPacMap() | 获取PacMap,如果没有,会新建一个 |
Runnable getTask() | 获取Runnable任务 |
PacMap peekPacMap() | 获取PacMap |
void setPacMap(PacMap pacMap) | 设置PacMap |
四、线程的通信使用
① EventHandler 投递 InnerEvent 事件
- EventHandler 投递 InnerEvent 事件,并按照优先级和延时进行处理。
- 创建 EventHandler 的子类,在子类中重写实现方法 processEvent() 来处理事件:
private static final int EVENT_MESSAGE_NORMAL = 1;
private static final int EVENT_MESSAGE_DELAY = 2;
private class MyEventHandler extends EventHandler {
private MyEventHandler(EventRunner runner) {
super(runner);
}
@Override
public void processEvent(InnerEvent event) {
super.processEvent(event);
if (event == null) {
return;
}
int eventId = event.eventId;
switch (eventId) {
case EVENT_MESSAGE_NORMAL:
break;
case EVENT_MESSAGE_DELAY:
break;
default:
break;
}
}
}
EventRunner runner = EventRunner.create(false);
MyEventHandler myHandler = new MyEventHandler(runner);
long param = 0L;
Object object = null;
InnerEvent normalInnerEvent = InnerEvent.get(EVENT_MESSAGE_NORMAL, param, object);
InnerEvent delayInnerEvent = InnerEvent.get(EVENT_MESSAGE_DELAY, param, object);
- 投递事件,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2m:
myHandler.sendEvent(normalInnerEvent, 0, EventHandler.Priority.IMMEDIATE);
myHandler.sendEvent(delayInnerEvent, 2, EventHandler.Priority.IMMEDIATE);
- 启动和停止 EventRunner,如果为托管模式,则不需要此步骤:
runner.run();
...
runner.stop();
② EventHandler 投递 Runnable 任务
- EventHandler 投递 Runnable 任务,并按照优先级和延时进行处理。
- 创建 EventHandler 的子类,创建 EventRunner,并创建 EventHandler 子类的实例,步骤与 EventHandler 投递 InnerEvent 场景的前三个步骤相同。
- 创建 Runnable 任务。
Runnable normalTask = new Runnable() {
@Override
public void run() {
}
};
Runnable delayTask = new Runnable() {
@Override
public void run() {
}
};
- 投递 Runnable 任务,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。
myHandler.postTask(normalTask, 0, EventHandler.Priority.IMMEDIATE);
myHandler.postTask(delayTask, 2, EventHandler.Priority.IMMEDIATE);
- 启动和停止 EventRunner,如果是托管模式,则不需要此步骤:
runner.run();
...
runner.stop();
③ 在新创建的线程里投递事件到原线程
- EventHandler 从新创建的线程投递事件到原线程并进行处理。
- 创建 EventHandler 的子类,在子类中重写实现方法 processEvent() 来处理事件。
private static final int EVENT_MESSAGE_CROSS_THREAD = 1;
private class MyEventHandler extends EventHandler {
private MyEventHandler(EventRunner runner) {
super(runner);
}
@Override
public void processEvent(InnerEvent event) {
super.processEvent(event);
if (event == null) {
return;
}
int eventId = event.eventId;
switch (eventId) {
case EVENT_MESSAGE_CROSS_THREAD:
Object object = event.object;
if (object instanceof EventRunner) {
EventRunner runner2 = (EventRunner) object;
EventHandler myHandler2 = new EventHandler(runner2) {
@Override
public void processEvent(InnerEvent event) {
}
};
int eventId2 = 1;
long param2 = 0L;
Object object2 = null;
InnerEvent event2 = InnerEvent.get(eventId2, param2, object2);
myHandler2.sendEvent(event2);
}
break;
default:
break;
}
}
}
EventRunner runner = EventRunner.create(false);
MyEventHandler myHandler = new MyEventHandler(runner);
long param = 0L;
InnerEvent event = InnerEvent.get(EVENT_MESSAGE_CROSS_THREAD, param, EventRunner.current());
myHandler.sendEvent(event);
- 启动和停止 EventRunner,如果是托管模式,则不需要此步骤:
runner.run();
...
runner.stop();
五、完整示例
public static final int CODE_DOWNLOAD_FILE1 = 1;
public static final int CODE_DOWNLOAD_FILE2 = 2;
public static final int CODE_DOWNLOAD_FILE3 = 3;
EventRunner runnerA = EventRunner.create(false);
runnerA.run();
public class MyEventHandler extends EventHandler {
private MyEventHandler(EventRunner runner) {
super(runner);
}
@Override
public void processEvent(InnerEvent event) {
super.processEvent(event);
if (event == null) {
return;
}
int eventId = event.eventId;
switch (eventId) {
case CODE_DOWNLOAD_FILE1: {
break;
}
case CODE_DOWNLOAD_FILE2: {
break;
}
case CODE_DOWNLOAD_FILE3: {
break;
}
default:
break;
}
}
}
MyEventHandler handler = new MyEventHandler(runnerA);
handler.sendEvent(CODE_DOWNLOAD_FILE1);
handler.sendEvent(CODE_DOWNLOAD_FILE2);
handler.sendEvent(CODE_DOWNLOAD_FILE3);
runnerA.stop();
public static final int CODE_DOWNLOAD_FILE1 = 1;
public static final int CODE_DOWNLOAD_FILE2 = 2;
public static final int CODE_DOWNLOAD_FILE3 = 3;
EventRunner runnerA = EventRunner.create("downloadRunner");
public class MyEventHandler extends EventHandler {
private MyEventHandler(EventRunner runner) {
super(runner);
}
@Override
public void processEvent(InnerEvent event) {
super.processEvent(event);
if (event == null) {
return;
}
int eventId = event.eventId;
switch (eventId) {
case CODE_DOWNLOAD_FILE1: {
break;
}
case CODE_DOWNLOAD_FILE2: {
break;
}
case CODE_DOWNLOAD_FILE3: {
break;
}
default:
break;
}
}
}
MyEventHandler handler = new MyEventHandler(runnerA);
handler.sendEvent(CODE_DOWNLOAD_FILE1);
handler.sendEvent(CODE_DOWNLOAD_FILE2);
handler.sendEvent(CODE_DOWNLOAD_FILE3);
runnerA = null;