HarmonyOS Sample 之 EventHandler 线程间通信 原创 精华

Buty9147
发布于 2021-9-9 19:09
浏览
4收藏

@toc

HarmonyOS Sample 之 EventHandler 线程间通信

1.介绍

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

2.搭建环境

安装DevEco Studio,详情请参考DevEco Studio下载
设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:

如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。
如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境
下载源码后,使用DevEco Studio 打开项目。

3.理论支持

EventRunner是一种事件循环器,循环处理队列中的 InnerEvent事件 或者 Runnable任务。
EventHandler是一种在 当前线程 上 投递 InnerEvent事件 或者 Runnable任务 到 异步线程上处理的机制。
InnerEvent是EventHandler投递的事件结构对象。
EventHandler和指定的EventRunner所创建的新线程绑定,并且该新线程内部有一个事件队列。

EventRunner的工作模式可以分为托管模式和手动模式。
投递时,EventHandler的优先级可在IMMEDIATE、HIGH、LOW、IDLE中选择。

详细请参考 线程间通信开发概述


使用EventHandler实现线程间通信的主要流程:
EventHandler投递具体的InnerEvent事件或者Runnable任务到EventRunner所创建的线程的事件队列
EventRunner循环从事件队列中获取InnerEvent事件或者Runnable任务
处理事件或任务:
如果EventRunner取出的事件为InnerEvent事件,
则触发EventHandler的回调方法并触发EventHandler的处理方法,在新线程上处理该事件
如果EventRunner取出的事件为Runnable任务,则EventRunner直接 在新线程上处理Runnable任务

4.实例讲解

4.1.UI界面

HarmonyOS Sample 之 EventHandler 线程间通信-鸿蒙开发者社区

4.2.后台代码

4.2.1 初始化EventRunner、EventHandler 对象

/**
 * 初始化对象
 */
private void initHandler() {
    //创建事件运行器,默认是托管模式,create()的参数是false时,则为手动模式
    eventRunner = EventRunner.create("TestRunner");
    
    //初始化事件处理器,需要传入一个事件运行器
    handler = new TestEventHandler(eventRunner);

    //第二个EventHandler
    myHandler=new MyEventHandler(eventRunner);
}

4.2.2 发送普通事件

/**
 * 发送一个普通事件
 * @param component
 */
private void sendInnerEvent(Component component) {
    stringBuffer = new StringBuffer();
    long param = 0L;

    //获取一个事件结构对象
    //InnerEvent 对象包含一个额外的整数字段和一个额外的对象字段来携带特定数据。
    InnerEvent normalInnerEvent = InnerEvent.get(EVENT_MESSAGE_NORMAL, param, null);
    InnerEvent delayInnerEvent = InnerEvent.get(EVENT_MESSAGE_DELAY, param, null);

    //发送事件,事件结构对象+事件等级
    //IMMEDIATE:即时;IDLE:闲置;HIGH:高;LOW:低
    handler.sendEvent(normalInnerEvent, EventHandler.Priority.IMMEDIATE);
    HiLog.debug(LABEL,"Send a NormalEvent done");

    //发送一个延迟事件,事件结构对象+延迟时间+事件等级
    handler.sendEvent(delayInnerEvent, DELAY_TIME, EventHandler.Priority.IMMEDIATE);
    HiLog.debug(LABEL,"Send a DelayEvent done");

}

输出结果

09-09 12:14:36.512 14769-14769/ohos.samples.eventhandler D 00001/=>MainAbilitySlice:  Send a NormalEvent done
09-09 12:14:36.512 14769-14769/ohos.samples.eventhandler D 00001/=>MainAbilitySlice:  Send a DelayEvent done
09-09 12:14:36.512 14769-15211/ohos.samples.eventhandler D 00001/=>MainAbilitySlice:  Received a NormalEvent 1631160876512
09-09 12:14:37.512 14769-15211/ohos.samples.eventhandler D 00001/=>MainAbilitySlice:  Received a DelayEvent 1631160877512

4.2.3 发布可运行任务

/**
 * 发布可运行任务
 * @param component
 */
private void postRunnableTask(Component component) {
    stringBuffer = new StringBuffer();

    //任务1
    //Runnable任务,将在EventRunner所在线程执行Runnable的run回调。
    Runnable task1 = () -> {
        stringBuffer.append("Post runnableTask1 done").append(System.lineSeparator());
        getUITaskDispatcher().asyncDispatch(() -> resultText.setText(stringBuffer.toString()));
        HiLog.debug(LABEL,"Post runnableTask1 done asyncDispatch");
    };
    //任务2
    //Runnable任务,将在EventRunner所在线程执行Runnable的run回调。
    Runnable task2 = () -> {
        stringBuffer.append("Post runnableTask2 done").append(System.lineSeparator());
        getUITaskDispatcher().asyncDispatch(() -> resultText.setText(stringBuffer.toString()));
        HiLog.debug(LABEL,"Post runnableTask2 done asyncDispatch");
    };

    HiLog.debug(LABEL,"Main Task run1...");

    //发布任务
    myHandler.postTask(task1, EventHandler.Priority.IMMEDIATE);
    HiLog.debug(LABEL,"Main Task run2...");
    
    //发布延迟任务,所以在task1后执行
    myHandler.postTask(task2, DELAY_TIME, EventHandler.Priority.IMMEDIATE);
    HiLog.debug(LABEL,"Main Task run3...");

}

输出结果

09-09 10:21:43.672 19863-19863/ohos.samples.eventhandler D 00001/=>MainAbilitySlice:  Main Task run1...
09-09 10:21:43.672 19863-19863/ohos.samples.eventhandler D 00001/=>MainAbilitySlice:  Main Task run2...
09-09 10:21:43.672 19863-19863/ohos.samples.eventhandler D 00001/=>MainAbilitySlice:  Main Task run3...
09-09 10:21:43.673 19863-31145/ohos.samples.eventhandler D 00001/=>MainAbilitySlice:  Post runnableTask1 done asyncDispatch
09-09 10:21:44.675 19863-31145/ohos.samples.eventhandler D 00001/=>MainAbilitySlice:  Post runnableTask2 done asyncDispatch

4.2.4 发送一个跨线程的事件

/**
 * 发送跨线程的事件
 * @param component
 */
private void sendToOriginalThread(Component component) {
    stringBuffer = new StringBuffer();
    long param = 0;

    //获取一个标志为跨线程的事件结构对象
    InnerEvent innerEvent = InnerEvent.get(EVENT_MESSAGE_CROSS_THREAD, param, eventRunner);

    //发送一个延迟事件
    handler.sendEvent(innerEvent, DELAY_TIME, EventHandler.Priority.IMMEDIATE);
    HiLog.debug(LABEL,"send a CrossThreadAndDelayEvent done"+System.currentTimeMillis());

}

输出结果

09-09 12:15:28.625 14769-14769/ohos.samples.eventhandler D 00001/=>MainAbilitySlice:  send a CrossThreadAndDelayEvent done1631160928625
09-09 12:15:29.626 14769-15211/ohos.samples.eventhandler D 00001/=>MainAbilitySlice:  Received a CrossThreadAndDelayEvent 1631160929626
09-09 12:15:29.626 14769-15211/ohos.samples.eventhandler D 00001/=>MainAbilitySlice:  send a ReplyEvent 1631160929626
09-09 12:15:29.626 14769-15211/ohos.samples.eventhandler D 00001/=>MainAbilitySlice:  receive a ReplyEvent 1631160929626

4.2.5 继承事件处理器类,重写处理事件的方法

/**
 * 继承事件处理器类,重写处理事件的方法
 */
private class TestEventHandler extends EventHandler {

    /**
     * 默认构造函数
     * @param runner
     */
    private TestEventHandler(EventRunner runner) {
        super(runner);
    }

    @Override
    public void processEvent(InnerEvent event) {
        switch (event.eventId) {
            case EVENT_MESSAGE_NORMAL:
                HiLog.debug(LABEL,"Received a NormalEvent "+System.currentTimeMillis());
                stringBuffer.append("Received an innerEvent message").append(System.lineSeparator());
                getUITaskDispatcher().asyncDispatch(() -> resultText.setText(stringBuffer.toString()));
                break;
            case EVENT_MESSAGE_DELAY:
                HiLog.debug(LABEL,"Received a DelayEvent "+System.currentTimeMillis());
                stringBuffer.append("Received an innerEvent delay message").append(System.lineSeparator());
                getUITaskDispatcher().asyncDispatch(() -> resultText.setText(stringBuffer.toString()));
                break;
            case EVENT_MESSAGE_CROSS_THREAD:
                HiLog.debug(LABEL,"Received a CrossThreadAndDelayEvent "+System.currentTimeMillis());
                //接收事件对象
                Object object = event.object;
                //判断对象类型
                if (object instanceof EventRunner) {
                    //将原先线程的EventRunner实例投递给新创建的线程
                    EventRunner runner = (EventRunner) object;
                    // 将原先线程的EventRunner实例与新创建的线程的EventHandler绑定
                    EventHandler eventHandler = new EventHandler(runner) {
                        @Override
                        public void processEvent(InnerEvent innerEvent) {
                            //需要在原先线程执行的操作
                            HiLog.debug(LABEL,"receive a ReplyEvent "+System.currentTimeMillis());
                            stringBuffer.append("OriginalThread receive a message");
                            getUITaskDispatcher().asyncDispatch(() -> resultText.setText(stringBuffer.toString()));
                        }
                    };
                    int testEventId = 1;
                    long testParam = 0;
                    //获取事件传递的参数
                    InnerEvent innerEvent = InnerEvent.get(testEventId, testParam, null);
                    ///投递事件到原先的线程
                    eventHandler.sendEvent(innerEvent);
                    HiLog.debug(LABEL,"send a ReplyEvent "+System.currentTimeMillis());
                }
                break;
            default:
                break;
        }
    }

}

5.问题与思考

5.1 发布一个定时任务到队列,没有得到预期的效果。

//TODO 没有得到预期的效果
myHandler.postTimingTask(task1,System.currentTimeMillis()+1000L, EventHandler.Priority.IMMEDIATE);

5.2 思考一下 示例中 哪个地方体现了 “一个EventRunner可以同时绑定多个EventHandler” 这句话?

6.完整代码

附件直接下载

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
EventHandler.zip 1.8M 61次下载
已于2021-9-9 19:15:17修改
3
收藏 4
回复
举报
2条回复
按时间正序
/
按时间倒序
董昱
董昱

很棒,赞一个

回复
2021-9-15 08:13:06
Buty9147
Buty9147 回复了 董昱
很棒,赞一个

谢谢支持!

回复
2021-9-15 08:56:58
回复
    相关推荐