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界面

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.完整代碼