网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
HiLog.info(label, “” + revoked);
}
在onStart()中调用
//取消异步任务
revocableAsyncTask(MainAbility.this);
运行效果如下:
⑩ 同步设置屏障任务 (syncDispatchBarrier)
在任务组上设立任务执行屏障,同步等待任务组中的所有任务执行完成,再执行指定任务。在全局并发任务分发器(GlobalTaskDispatcher)上同步设置任务屏障,将不会起到屏障作用。就比如说考试提前交卷,A提前20分钟,B提前10分钟,但你只是离开了考室,离不开考场,这个考场的门就是这个屏障,无论你是提前多久,你都要等到所有考生考完,老师收卷之后才能离开考场,就是这么一个理。代码如下:
/**
- 同步设置屏障任务
*/
private void setSyncDispatchBarrier(Context context) {
TaskDispatcher dispatcher = context.createParallelTaskDispatcher(“parallelTask”,TaskPriority.DEFAULT);
//创建任务组
Group group = dispatcher.createDispatchGroup();
//将任务1加入任务组
dispatcher.asyncGroupDispatch(group, new Runnable() {
@Override
public void run() {
HiLog.info(label,“task1 is running”);
}
});
//将任务2加入任务组
dispatcher.asyncGroupDispatch(group, new Runnable() {
@Override
public void run() {
HiLog.info(label,“task2 is running”);
}
});
dispatcher.asyncDispatchBarrier(new Runnable() {
@Override
public void run() {
HiLog.info(label,“Barrier”);
}
});
HiLog.info(label,“after syncDispatchBarrier”);
}
在onStart()中调用,
//同步设置屏障任务
setSyncDispatchBarrier(MainAbility.this);
运行
⑪ 异步设置屏障任务 (asyncDispatchBarrier)
在任务组上设立任务执行屏障后直接返回,指定任务将在任务组中的所有任务执行完成后再执行。在全局并发任务分发器(GlobalTaskDispatcher)上异步设置任务屏障,将不会起到屏障作用。可以使用并发任务分发器(ParallelTaskDispatcher)分离不同的任务组,达到微观并行、宏观串行的行为。
/**
- 异步设置屏障任务
*/
private void setAsyncDispatchBarrier(Context context) {
TaskDispatcher dispatcher = context.createParallelTaskDispatcher(“AsyncParallelTaskDispatcher”, TaskPriority.DEFAULT);
// 创建任务组
Group group = dispatcher.createDispatchGroup();
//将任务1加入任务组
dispatcher.asyncGroupDispatch(group, new Runnable() {
@Override
public void run() {
HiLog.info(label, “task1 is running”); // 1
}
});
//将任务2加入任务组
dispatcher.asyncGroupDispatch(group, new Runnable() {
@Override
public void run() {
HiLog.info(label, “task2 is running”); // 2
}
});
dispatcher.asyncDispatchBarrier(new Runnable() {
@Override
public void run() {
HiLog.info(label, “barrier”); // 3
}
});
HiLog.info(label, “after syncDispatchBarrier”); // 4
}
在onStart()中调用
//异步设置屏障任务
setAsyncDispatchBarrier(MainAbility.this);
运行效果
⑫ 执行多次任务(applyDispatch)
对指定任务执行多次
/**
- 执行多次任务
*/
private void multipleTasks() {
//总执行次数
final int total = 10;
//倒数计时器
final CountDownLatch latch = new CountDownLatch(total);
//长整形列表数组
final ArrayList indexList = new ArrayList<>(total);
TaskDispatcher dispatcher = createParallelTaskDispatcher(“dispatcher”,
TaskPriority.DEFAULT);
//执行多次任务
dispatcher.applyDispatch((index) -> {
indexList.add(index);
latch.countDown();
HiLog.info(label, "long: "+index);
}, total);
//设置任务超时
try {
latch.await();
} catch (InterruptedException e) {
HiLog.info(label, “latch exception”);
}
//返回true则说明执行了10次
HiLog.info(label, “list size matches,” + (total == indexList.size()));
}
运行效果如下:
在开发过程中,开发者经常需要在当前线程中处理下载任务等较为耗时的操作,但是又不希望当前的线程受到阻塞。此时,就可以使用 EventHandler 机制。EventHandler 是HarmonyOS 用于处理线程间通信的一种机制,可以通过 EventRunner 创建新线程,将耗时的操作放到新线程上执行。这样既不阻塞原来的线程,任务又可以得到合理的处理。比如:主线程使用 EventHandler 创建子线程,子线程做耗时的下载图片操作,下载完成后,子线程通过 EventHandler 通知主线程,主线程再更新 UI。
① EventRunner
EventRunner 是一种事件循环器,循环处理从该 EventRunner 创建的新线程的事件队列中获取 InnerEvent 事件或者 Runnable 任务。InnerEvent 是 EventHandler 投递的事件。
EventHandler 是一种用户在当前线程上投递 InnerEvent 事件或者 Runnable 任务到异步线程上处理的机制。每一个 EventHandler 和指定的 EventRunner 所创建的新线程绑定,并且该新线程内部有一个事件队列。EventHandler 可以投递指定的 InnerEvent 事件或 Runnable 任务到这个事件队列。EventRunner 从事件队列里循环地取出事件,如果取出的事件是InnerEvent 事件,将在 EventRunner 所在线程执行 processEvent 回调;如果取出的事件是Runnable 任务,将在 EventRunner 所在线程执行 Runnable 的 run 回调。
② EventHandler
EventHandler 有两个主要作用:
-
在不同线程间分发和处理 InnerEvent 事件或 Runnable 任务。
-
延迟处理 InnerEvent 事件或 Runnable 任务。
EventHandler 的运作机制如下图所示:
使用 EventHandler 实现线程间通信的主要流程:
-
EventHandler 投递具体的 InnerEvent 事件或者 Runnable 任务到 EventRunner 所创建的线程的事件队列。
-
EventRunner 循环从事件队列中获取 InnerEvent 事件或者 Runnable 任务。
-
处理事件或任务:
① 如果 EventRunner 取出的事件为 InnerEvent 事件,则触发 EventHandler 的回调方法并触发 EventHandler 的处理方法,在新线程上处理该事件。
② 如果 EventRunner 取出的事件为 Runnable 任务,则 EventRunner 直接在新线程上处理 Runnable 任务。
1. 约束限制
-
在进行线程间通信的时候,EventHandler 只能和 EventRunner 所创建的线程进行绑定,EventRunner 创建时需要判断是否创建成功,只有确保获取的 EventRunner 实例非空时,才可以使用 EventHandler 绑定 EventRunner。
-
一个 EventHandler 只能同时与一个 EventRunner 绑定,一个 EventRunner 上可以创建多个 EventHandler。
2. 开发场景
EventHandler 的主要功能是将 InnerEvent 事件或者 Runnable 任务投递到其他的线程进行处理,其使用的场景包括
-
开发者需要将 InnerEvent 事件投递到新的线程,按照优先级和延时进行处理。投递时,EventHandler 的优先级可在IMMEDIATE、HIGH、LOW、IDLE 中选择,并设置合适的 delayTime。
-
开发者需要将 Runnable 任务投递到新的线程,并按照优先级和延时进行处理。投递时,EventHandler 的优先级可在IMMEDIATE、HIGH、LOW、IDLE 中选择,并设置合适的 delayTime。
-
开发者需要在新创建的线程里投递事件到原线程进行处理。
3. 工作模式
EventRunner 的工作模式可以分为托管模式和手动模式。两种模式是在调用 EventRunner 的create()方法时,通过选择不同的参数来实现的,默认为托管模式。
- 托管模式:不需要开发者调用 run()和 stop()方法去启动和停止 EventRunner。当 EventRunner 实例化时,系统调用
run()来启动 EventRunner;当 EventRunner 不被引用时,系统调用 stop()来停止 EventRunner。
- 手动模式:需要开发者自行调用 EventRunner 的 run()方法和 stop()方法来确保线程的启动和停止。
③ 接口说明
1. 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) | 发送一个事件到事件队列,延时为 0ms, 优先级为 LOW |
| sendEvent(InnerEvent event, long delayTime) | 发送一个延时事件到事件队列,优先级为 LOW |
| sendEvent(InnerEvent event, long delayTime, EventHandler.Priority priority) | 发送一个指定优先级的延时事件到事件队列 |
| sendEvent(InnerEvent event, EventHandler.Priority priority) | 发送一个指定优先级的事件到事件队列,延时为 0ms |
| sendSyncEvent(InnerEvent event) | 发送一个同步事件到事件队列,延时为 0ms,优先级为 LOW |
| sendSyncEvent(InnerEvent event, EventHandler.Priority priority) | 发送一个指定优先级的同步事件到事件队列,延时为 0ms,优先级不可以是 IDLE |
| postSyncTask(Runnable task) | 发送一个 Runnable 同步任务到事件队列,延时为 0ms, 优先级为 LOW |
| postSyncTask(Runnable task, EventHandler.Priority priority) | 发送一个指定优先级的 Runnable 同步任务到事件队列,延时为0ms |
| postTask(Runnable task) | 发送一个 Runnable 任务到事件队列,延时为 0ms,优先级为LOW |
| postTask(Runnable task, long delayTime) | 发送一个 Runnable 延时任务到事件队列,优先级为 LOW |
| postTask(Runnable task, long delayTime, EventHandler.Priority priority) | 发送一个指定优先级的 Runnable 延时任务到事件队列 |
| postTask(Runnable task, EventHandler.Priority priority) | 发送一个指定优先级的 Runnable 任务到事件队列,延时为 0ms |
| 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) | 是否有还未被处理的这个任务 |
2. EventRunner
- EventRunner 的主要接口介绍:
| 接口名 | 描述 |
| — | — |
| create() | 创建一个拥有新线程的 EventRunner |
| create(boolean isDeposited) | 创建一个拥有新线程的 EventRunner,isDeposited 为 true 时,EventRunner 为托管模式,系统将自动管理该 EventRunner;isDeposited 为 false 时,EventRunner 为手动模式。 |
| create(String newThreadName) | 创建一个拥有新线程的 EventRunner, 新线程的名字是 newThreadName |
| current() | 获取当前线程的 EventRunner |
| run() | EventRunner 为手动模式时,调用该方法启动新的线程 |
| stop() | EventRunner 为手动模式时,调用该方法停止新的线程 |
3. 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 事件,并按照优先级和延时进行处理,创建一个MyEventHandler类型继承EventHandler
package com.llw.thread.event;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class MyEventHandler extends EventHandler {
/**
- 日志
*/
private static final HiLogLabel label = new HiLogLabel(3, 0xD001100, “ThreadDemo”);
public MyEventHandler(EventRunner runner) throws IllegalArgumentException {
super(runner);
}
/**
-
- 创建 EventHandler 的子类,在子类中重写实现方法 processEvent()来处理事件
-
@param event
*/
@Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
if (event == null) {
return;
}
int eventId = event.eventId;
long param = event.param;
switch ((int) (eventId | param)) {
case 1:
HiLog.info(label, “eventId | param —>” + 1);
break;
default:
break;
}
}
/**
- EventHandler 投递 InnerEvent 事件
*/
private void initInnerEvent() {
//2. 创建 EventRunner,以手动模式为例。
// create()的参数是 true 时,则为托管模式
EventRunner runner = EventRunner.create(false);
if (runner == null) {
return;
}
//3. 创建 EventHandler 子类的实例。
MyEventHandler myHandler = new MyEventHandler(runner);
//4. 获取 InnerEvent 事件。
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);
//5. 投递事件,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。
myHandler.sendEvent(event1, 0, EventHandler.Priority.IMMEDIATE);
// 延时 2ms 后立即处理
myHandler.sendEvent(event2, 2, EventHandler.Priority.IMMEDIATE);
//6. 启动和停止 EventRunner,如果为托管模式,则不需要此步骤。
runner.run();
//待执行操作
// … 执行业务逻辑
// 停止 EventRunner
runner.stop();
}
}
二、EventHandler 投递 Runnable 任务
/**
- EventHandler 投递 Runnable 任务
*/
private void initRunnable() {
//2. 创建 EventRunner,以手动模式为例。
// create()的参数是 true 时,则为托管模式
EventRunner runner = EventRunner.create(false);
if (runner == null) {
return;
}
//3. 创建 EventHandler 子类的实例。
MyEventHandler myHandler = new MyEventHandler(runner);
//2. 创建 Runnable 任务。
Runnable task1 = new Runnable() {
@Override
public void run() {
HiLog.info(label, “task1 running”);
}
};
Runnable task2 = new Runnable() {
@Override
public void run() {
HiLog.info(label, “task1 running”);
}
};
//3. 投递 Runnable 任务,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。
myHandler.postTask(task1, 0, EventHandler.Priority.IMMEDIATE);
// 延时 2ms 后立即执行
myHandler.postTask(task2, 2, EventHandler.Priority.IMMEDIATE);
//4. 启动和停止 EventRunner,如果是托管模式,则不需要此步骤。
runner.run();
//待执行操作
// … 执行业务逻辑
// 停止 EventRunner
runner.stop();
}
三、在新创建的线程里投递事件到原线程
修改MyEventHandler之后代码如下:
package com.llw.thread.event;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
public class MyEventHandler extends EventHandler {
/**
- 日志
*/
private static final HiLogLabel label = new HiLogLabel(3, 0xD001100, “ThreadDemo”);
private MyEventHandler myHandler;
private EventRunner runner;
public MyEventHandler(EventRunner runner) throws IllegalArgumentException {
super(runner);
}
/**
-
- 创建 EventHandler 的子类,在子类中重写实现方法 processEvent()来处理事件
-
@param event
*/
@Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
if (event == null) {
return;
}
int eventId = event.eventId;
long param = event.param;
Object object = event.object;
switch ((int) (eventId | param)) {
case 1:
HiLog.info(label, “eventId | param —>” + 1);
break;
case 2:
EventRunner runner2 = null;
// 将原先线程的 EventRunner 实例投递给新创建的线程
if (object instanceof EventRunner) {
//强转
runner2 = (EventRunner) object;
}
// 将原先线程的 EventRunner 实例与新创建的线程的 EventHandler 绑定
EventHandler myHandler2 = new EventHandler(runner2) {
@Override
protected void processEvent(InnerEvent event) {
//需要在原先线程执行的操作
}
};
int eventId2 = 1;
long param2 = 0;
Object object2 = null;
InnerEvent event2 = InnerEvent.get(eventId2, param2, object2);
// 投递事件到原先的线程
myHandler2.sendEvent(event2);
break;
default:
break;
}
}
/**
- EventHandler 投递 InnerEvent 事件
*/
private void initInnerEvent() {
//2. 创建 EventRunner,以手动模式为例。
// create()的参数是 true 时,则为托管模式
runner = EventRunner.create(false);
if (runner == null) {
return;
}
//3. 创建 EventHandler 子类的实例。
myHandler = new MyEventHandler(runner);
//4. 获取 InnerEvent 事件。
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);
//5. 投递事件,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。
myHandler.sendEvent(event1, 0, EventHandler.Priority.IMMEDIATE);
// 延时 2ms 后立即处理
myHandler.sendEvent(event2, 2, EventHandler.Priority.IMMEDIATE);
//6. 启动和停止 EventRunner,如果为托管模式,则不需要此步骤。
runner.run();
//待执行操作
// … 执行业务逻辑
// 停止 EventRunner
runner.stop();
}
/**
- EventHandler 投递 Runnable 任务
*/
private void initRunnable() {
//2. 创建 EventRunner,以手动模式为例。
// create()的参数是 true 时,则为托管模式
runner = EventRunner.create(false);
if (runner == null) {
return;
}
//3. 创建 EventHandler 子类的实例。
myHandler = new MyEventHandler(runner);
//2. 创建 Runnable 任务。
Runnable task1 = new Runnable() {
@Override
public void run() {
HiLog.info(label, “task1 running”);
}
};
Runnable task2 = new Runnable() {
@Override
public void run() {
HiLog.info(label, “task1 running”);
}
};
//3. 投递 Runnable 任务,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。
myHandler.postTask(task1, 0, EventHandler.Priority.IMMEDIATE);
// 延时 2ms 后立即执行
myHandler.postTask(task2, 2, EventHandler.Priority.IMMEDIATE);
//4. 启动和停止 EventRunner,如果是托管模式,则不需要此步骤。
runner.run();
//待执行操作
// … 执行业务逻辑
// 停止 EventRunner
runner.stop();
}
/**
- 在新创建的线程里投递事件到原线程
*/
private void initNewToOld() {
//2. 创建 EventRunner,以手动模式为例。
// create()的参数是 true 时,则为托管模式。
EventRunner runner1 = EventRunner.create(false);
// 需要对 EventRunner 的实例进行校验,不是任何线程都可以通过 create 创建,例如:当线程池已满时,不能再创建线程。
if (runner1 == null) {
return;
}
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
() {
@Override
public void run() {
HiLog.info(label, “task1 running”);
}
};
//3. 投递 Runnable 任务,投递的优先级以 IMMEDIATE 为例,延时选择 0ms 和 2ms。
myHandler.postTask(task1, 0, EventHandler.Priority.IMMEDIATE);
// 延时 2ms 后立即执行
myHandler.postTask(task2, 2, EventHandler.Priority.IMMEDIATE);
//4. 启动和停止 EventRunner,如果是托管模式,则不需要此步骤。
runner.run();
//待执行操作
// … 执行业务逻辑
// 停止 EventRunner
runner.stop();
}
/**
- 在新创建的线程里投递事件到原线程
*/
private void initNewToOld() {
//2. 创建 EventRunner,以手动模式为例。
// create()的参数是 true 时,则为托管模式。
EventRunner runner1 = EventRunner.create(false);
// 需要对 EventRunner 的实例进行校验,不是任何线程都可以通过 create 创建,例如:当线程池已满时,不能再创建线程。
if (runner1 == null) {
return;
}
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
[外链图片转存中…(img-VWWi2sL1-1715639618734)]
[外链图片转存中…(img-92Zo6qGH-1715639618735)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新