鸿蒙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 任务进行处理。
属性 | 描述 |
---|---|
Priority.IMMEDIATE | 表示事件被立即投递 |
Priority.HIGH | 表示事件先于 LOW 优先级投递 |
Priority.LOW | 表示事件优于 IDLE 优先级投递,事件的默认优先级是 LOW |
Priority.IDLE | 表示在没有其他事件的情况下,才投递该事件 |
- EventHandler 的主要接口介绍:
接口名 | 描述 |
---|---|
EventHandler(EventRunner runner) | 利用已有的 EventRunner 来创建 EventHandler |
current() | 在processEvent 回调中,获取当前的 EventHandler |
processEvent(InnerEvent event) | 回调处理事件,由开发者实现 |
sendEvent(InnerEvent event) | 发送一个事件到事件队列,延时为 0 ms, 优先级为 LOW |
sendEvent(InnerEvent event, long delayTime) | 发送一个延时事件到事件队列,优先级为 LOW |
sendEvent(InnerEvent event, long delayTime, EventHandler.Priority priority) | 发送一个指定优先级的延时事件到事件队列 |
sendEvent(InnerEvent event, EventHandler.Priority priority) | 发送一个指定优先级的事件到事件队列,延时为 0 ms |
sendSyncEvent(InnerEvent event) | 发送一个同步事件到事件队列,延时为 0 ms,优先级为 LOW |
sendSyncEvent(InnerEvent event, EventHandler.Priority priority) | 发送一个指定优先级的同步事件到事件队列,延时为 0 ms,优先级不可以是 IDLE |
postSyncTask(Runnable task) | 发送一个 Runnable 同步任务到事件队列,延时为 0 ms, 优先级为 LOW |
postSyncTask(Runnable task, EventHandler.Priority priority) | 发送一个指定优先级的 Runnable 同步任务到事件队列,延时为 0 ms |
postTask(Runnable task) | 发送一个 Runnable 任务到事件队列,延时为 0 ms,优先级为 LOW |
postTask(Runnable task, long delayTime) | 发送一个 Runnable 延时任务到事件队列,优先级为 LOW |
postTask(Runnable task, long delayTime, EventHandler.Priority priority) | 发送一个指定优先级的 Runnable 延时任务到事件队列 |
postTask(Runnable task, EventHandler.Priority priority) | 发送一个指定优先级的 Runnable 任务到事件队列,延时为 0 ms |
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) | 是否有还未被处理的这个任务 |
EventRunner
- EventRunner的主要接口介绍:
接口名 | 描述 |
---|---|
create() | 创建一个拥有新线程的 EventRunner |
create(boolean inNewThread) | 创建一个拥有新线程的 EventRunner,isDeposited 为 true 时,EventRunner 为托管模式,系统将自动管理该 EventRunner;isDeposited 为 false 时,EventRunner 为手动模式。 |
create(String newThreadName) | 创建一个拥有新线程的 EventRunner, 新线程的名字是 newThreadName |
current() | 获取当前线程的 EventRunner |
run() | EventRunner 为手动模式时,调用该方法启动新的线程 |
stop() | EventRunner 为手动模式时,调用该方法停止新的线程 |
InnerEvent
- InnerEvent的属性介绍:
属性 | 描述 |
---|---|
eventId | 事件的 ID, 由开发者定义用来辨别事件 |
object | 事件携带的 Object 信息 |
param | 事件携带的 long 型数据 |
- InnerEvent的主要接口介绍:
接口名 | 描述 |
---|---|
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 class MyEventHandler extends EventHandler {
private MyEventHandler(EventRunner runner) {
super(runner);
}
// 重写实现processEvent方法
@Override
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() {
@Override
public void run() {
// 待执行的操作,由开发者定义
}
};
Runnable task2 = new Runnable() {
@Override
public void run() {
// 待执行的操作,由开发者定义
}
};
- 投递 Runnable 任务,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。
//优先级为 immediate,延时 0ms,该语句等价于同步投递myHandler.postSyncTask(task1,EventHandler.Priority.immediate);
myHandler.postTask(task1,0, EventHandler.Priority.IMMEDIATE);
myHandler.postTask(task2,2, EventHandler.Priority.IMMEDIATE);// 延时2ms后立即执行
- 启动和停止 EventRunner,如果是托管模式,则不需要此步骤。
runner.run();
//待执行操作
runner.stop();// 停止 EventRunner
在新创建的线程里投递事件到原线程
EventHandler 从新创建的线程投递事件到原线程并进行处理,开发步骤如下:
- 创建 EventHandler 的子类,在子类中重写实现方法 processEvent() 来处理事件。
private class MyEventHandler extends EventHandler {
private MyEventHandler(EventRunner runner) {
super(runner);
}
// 重写实现processEvent方法
@Override
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) {
@Override
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.创建类继承EventHandler
public 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);
}
@Override
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 process
break;
}
case CODE_DOWNLOAD_FILE1: {
... // your process
break;
}
case CODE_DOWNLOAD_FILE1: {
... // your process
break;
}
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.创建类继承 EventHandler
public 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);
}
@Override
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 process
break;
}
case CODE_DOWNLOAD_FILE1: {
... // your process
break;
}
case CODE_DOWNLOAD_FILE1: {
... // your process
break;
}
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;