共计 3784 个字符,预计需要花费 10 分钟才能阅读完成。
作者:韩茹
公司:程序咖(北京)科技有限公司
鸿蒙巴士专栏作家
在开发过程中,咱们常常须要在以后线程中解决下载工作等较为耗时的操作,然而又不心愿以后的线程受到阻塞。此时,就能够应用 EventHandler 机制。EventHandler 是 HarmonyOS 用于解决线程间通信的一种机制,能够通过 EventRunner 创立新线程,将耗时的操作放到新线程上执行。这样既不阻塞原来的线程,工作又能够失去正当的解决。比方:主线程应用 EventHandler 创立子线程,子线程做耗时的下载图片操作,下载实现后,子线程通过 EventHandler 告诉主线程,主线程再更新 UI。
一、主线程更新 UI
所有的 UI 操作都应该在主线程进行设置。
咱们能够尝试一下在子线程中设置 UI,看会有什么后果。首先在 ability_main.xml 中增加两个按钮和一个 Text:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:padding="20vp"
ohos:orientation="vertical">
<Button
ohos:id="$+id:btn1"
ohos:height="match_content"
ohos:width="match_content"
ohos:text="设置文本"
ohos:background_element="#eeeeee"
ohos:padding="20vp"
ohos:text_size="20fp"
ohos:margin="10vp"
/>
<Button
ohos:id="$+id:btn2"
ohos:height="match_content"
ohos:width="match_content"
ohos:text="启动子线程设置文本"
ohos:background_element="#eeeeee"
ohos:padding="20vp"
ohos:text_size="20fp"
ohos:margin="10vp"
/>
<Text
ohos:id="$+id:text1"
ohos:height="200vp"
ohos:width="300vp"
ohos:text="文本"
ohos:background_element="#eeeeee"
ohos:padding="20vp"
ohos:text_size="20fp"
ohos:text_alignment="center"
ohos:margin="10vp"
/>
</DirectionalLayout>
在 MainAbilitySlice 中,解决这两个按钮的点击事件:
package com.example.hanrueventhandler.slice;
import com.example.hanrueventhandler.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class MainAbilitySlice extends AbilitySlice {
// 定义日志标签
private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");
@Override
public void onStart(Intent intent) {super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
// 打印日志
// I 00201/MY_TAG: === 线程 ID 号:1, 线程名称:main
HiLog.info(LABEL, "=== 线程 ID 号:" + Thread.currentThread().getId() + ", 线程名称:" + Thread.currentThread().getName());
//UI 线程中更改 textview 的数据。。Button btn1 = (Button) findComponentById(ResourceTable.Id_btn1);
Button btn2 = (Button) findComponentById(ResourceTable.Id_btn2);
Text text = (Text) findComponentById(ResourceTable.Id_text1);
btn1.setClickedListener(component -> {
// 先睡 5s
try {HiLog.info(LABEL,"UI 线程睡眠 5s");
Thread.sleep(5*1000);
} catch (InterruptedException e) {e.printStackTrace();
}
text.setText("面朝大海哈");
});
btn2.setClickedListener(component -> {
// 换到子线程试试,程序间接挂掉了。所以子线程不能操作 UI
new Thread(){
@Override
public void run() {HiLog.info(LABEL, "======= 线程 ID 号:" + Thread.currentThread().getId() + ", 线程名称:" + Thread.currentThread().getName());
text.setText("春暖花开"); // java.lang.IllegalStateException: Attempt to update UI in non-UI thread.
}
}.start();});
}
}
程序运行起来后,咱们就能看到打印的日志,UI 线程就是 main 线程:
而后咱们点击第一个按钮:
点击按钮 5s 后,文本内容被设置了。
接下来咱们再来点击第二个按钮,能够打印出子线程:
而后程序就崩掉了:
而后咱们能够看到管制台上的错误信息:
由此咱们晓得了,在 HarmonyOS 中,子线程不能操作 UI。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 实现线程间通信的次要流程:
- 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。