HarmonyOS Sample 之 EventHandler 線程間通信
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
1.介紹
在開發(fā)過程中,開發(fā)者經(jīng)常需要在當(dāng)前線程中處理下載任務(wù)等較為耗時的操作,但是又不希望當(dāng)前的線程受到阻塞。
此時,就可以使用EventHandler機制。EventHandler是HarmonyOS用于處理線程間通信的一種機制,
可以通過EventRunner創(chuàng)建新線程,將耗時的操作放到新線程上執(zhí)行。
這樣既不阻塞原來的線程,任務(wù)又可以得到合理的處理。比如:
主線程使用EventHandler創(chuàng)建子線程,子線程做耗時的下載圖片操作,下載完成后,子線程通過EventHandler通知主線程,主線程再更新UI。
2.搭建環(huán)境
安裝DevEco Studio,詳情請參考DevEco Studio下載。
設(shè)置DevEco Studio開發(fā)環(huán)境,DevEco Studio開發(fā)環(huán)境需要依賴于網(wǎng)絡(luò)環(huán)境,需要連接上網(wǎng)絡(luò)才能確保工具的正常使用,可以根據(jù)如下兩種情況來配置開發(fā)環(huán)境:
如果可以直接訪問Internet,只需進(jìn)行下載HarmonyOS SDK操作。
如果網(wǎng)絡(luò)不能直接訪問Internet,需要通過代理服務(wù)器才可以訪問,請參考配置開發(fā)環(huán)境。
下載源碼后,使用DevEco Studio 打開項目。
3.理論支持
EventRunner是一種事件循環(huán)器,循環(huán)處理隊列中的 InnerEvent事件 或者 Runnable任務(wù)。
EventHandler是一種在 當(dāng)前線程 上 投遞 InnerEvent事件 或者 Runnable任務(wù) 到 異步線程上處理的機制。
InnerEvent是EventHandler投遞的事件結(jié)構(gòu)對象。
EventHandler和指定的EventRunner所創(chuàng)建的新線程綁定,并且該新線程內(nèi)部有一個事件隊列。
EventRunner的工作模式可以分為托管模式和手動模式。
投遞時,EventHandler的優(yōu)先級可在IMMEDIATE、HIGH、LOW、IDLE中選擇。
詳細(xì)請參考 線程間通信開發(fā)概述
使用EventHandler實現(xiàn)線程間通信的主要流程:
EventHandler投遞具體的InnerEvent事件或者Runnable任務(wù)到EventRunner所創(chuàng)建的線程的事件隊列。
EventRunner循環(huán)從事件隊列中獲取InnerEvent事件或者Runnable任務(wù)。
處理事件或任務(wù):
如果EventRunner取出的事件為InnerEvent事件,
則觸發(fā)EventHandler的回調(diào)方法并觸發(fā)EventHandler的處理方法,在新線程上處理該事件。
如果EventRunner取出的事件為Runnable任務(wù),則EventRunner直接 在新線程上處理Runnable任務(wù)。
4.實例講解
4.1.UI界面

4.2.后臺代碼
4.2.1 初始化EventRunner、EventHandler 對象
- /**
- * 初始化對象
- */
- private void initHandler() {
- //創(chuàng)建事件運行器,默認(rèn)是托管模式,create()的參數(shù)是false時,則為手動模式
- eventRunner = EventRunner.create("TestRunner");
- //初始化事件處理器,需要傳入一個事件運行器
- handler = new TestEventHandler(eventRunner);
- //第二個EventHandler
- myHandler=new MyEventHandler(eventRunner);
- }
4.2.2 發(fā)送普通事件
- /**
- * 發(fā)送一個普通事件
- * @param component
- */
- private void sendInnerEvent(Component component) {
- stringBuffer = new StringBuffer();
- long param = 0L;
- //獲取一個事件結(jié)構(gòu)對象
- //InnerEvent 對象包含一個額外的整數(shù)字段和一個額外的對象字段來攜帶特定數(shù)據(jù)。
- InnerEvent normalInnerEvent = InnerEvent.get(EVENT_MESSAGE_NORMAL, param, null);
- InnerEvent delayInnerEvent = InnerEvent.get(EVENT_MESSAGE_DELAY, param, null);
- //發(fā)送事件,事件結(jié)構(gòu)對象+事件等級
- //IMMEDIATE:即時;IDLE:閑置;HIGH:高;LOW:低
- handler.sendEvent(normalInnerEvent, EventHandler.Priority.IMMEDIATE);
- HiLog.debug(LABEL,"Send a NormalEvent done");
- //發(fā)送一個延遲事件,事件結(jié)構(gòu)對象+延遲時間+事件等級
- handler.sendEvent(delayInnerEvent, DELAY_TIME, EventHandler.Priority.IMMEDIATE);
- HiLog.debug(LABEL,"Send a DelayEvent done");
- }
輸出結(jié)果
- 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 發(fā)布可運行任務(wù)
- /**
- * 發(fā)布可運行任務(wù)
- * @param component
- */
- private void postRunnableTask(Component component) {
- stringBuffer = new StringBuffer();
- //任務(wù)1
- //Runnable任務(wù),將在EventRunner所在線程執(zhí)行Runnable的run回調(diào)。
- Runnable task1 = () -> {
- stringBuffer.append("Post runnableTask1 done").append(System.lineSeparator());
- getUITaskDispatcher().asyncDispatch(() -> resultText.setText(stringBuffer.toString()));
- HiLog.debug(LABEL,"Post runnableTask1 done asyncDispatch");
- };
- //任務(wù)2
- //Runnable任務(wù),將在EventRunner所在線程執(zhí)行Runnable的run回調(diào)。
- 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...");
- //發(fā)布任務(wù)
- myHandler.postTask(task1, EventHandler.Priority.IMMEDIATE);
- HiLog.debug(LABEL,"Main Task run2...");
- //發(fā)布延遲任務(wù),所以在task1后執(zhí)行
- myHandler.postTask(task2, DELAY_TIME, EventHandler.Priority.IMMEDIATE);
- HiLog.debug(LABEL,"Main Task run3...");
- }
輸出結(jié)果
- 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 發(fā)送一個跨線程的事件
- /**
- * 發(fā)送跨線程的事件
- * @param component
- */
- private void sendToOriginalThread(Component component) {
- stringBuffer = new StringBuffer();
- long param = 0;
- //獲取一個標(biāo)志為跨線程的事件結(jié)構(gòu)對象
- InnerEvent innerEvent = InnerEvent.get(EVENT_MESSAGE_CROSS_THREAD, param, eventRunner);
- //發(fā)送一個延遲事件
- handler.sendEvent(innerEvent, DELAY_TIME, EventHandler.Priority.IMMEDIATE);
- HiLog.debug(LABEL,"send a CrossThreadAndDelayEvent done"+System.currentTimeMillis());
- }
輸出結(jié)果
- 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 {
- /**
- * 默認(rèn)構(gòu)造函數(shù)
- * @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實例投遞給新創(chuàng)建的線程
- EventRunner runner = (EventRunner) object;
- // 將原先線程的EventRunner實例與新創(chuàng)建的線程的EventHandler綁定
- EventHandler eventHandler = new EventHandler(runner) {
- @Override
- public void processEvent(InnerEvent innerEvent) {
- //需要在原先線程執(zhí)行的操作
- 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;
- //獲取事件傳遞的參數(shù)
- InnerEvent innerEvent = InnerEvent.get(testEventId, testParam, null);
- ///投遞事件到原先的線程
- eventHandler.sendEvent(innerEvent);
- HiLog.debug(LABEL,"send a ReplyEvent "+System.currentTimeMillis());
- }
- break;
- default:
- break;
- }
- }
- }
5.問題與思考
5.1 發(fā)布一個定時任務(wù)到隊列,沒有得到預(yù)期的效果。
- //TODO 沒有得到預(yù)期的效果
- myHandler.postTimingTask(task1,System.currentTimeMillis()+1000L, EventHandler.Priority.IMMEDIATE);
5.2 思考一下 示例中 哪個地方體現(xiàn)了 “一個EventRunner可以同時綁定多個EventHandler” 這句話?
6.完整代碼
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)