HarmonyOS —线程间通信开发指导

HarmonyOS —线程间通信开发指导

场景介绍

EventHandler开发场景

EventHandler的主要功能是将InnerEvent事件或者Runnable任务投递到其他的线程进行处理,其使用的场景包括:

  • InnerEvent事件:开发者需要将InnerEvent事件投递到新的线程,按照优先级和延时进行处理。投递时,EventHandler的优先级可在IMMEDIATE、HIGH、LOW、IDLE中选择,并设置合适的delayTime。
  • Runnable任务:开发者需要将Runnable任务投递到新的线程,并按照优先级和延时进行处理。投递时,EventHandler的优先级可在IMMEDIATE、HIGH、LOW、IDLE中选择,并设置合适的delayTime。
  • 开发者需要在新创建的线程里投递事件到原线程进行处理。

EventRunner工作模式

EventRunner的工作模式可以分为托管模式和手动模式。两种模式是在调用EventRunner的create()方法时,通过选择不同的参数来实现的,详见API参考。默认为托管模式。

  • 托管模式:不需要开发者调用run()和stop()方法去启动和停止EventRunner。当EventRunner实例化时,系统调用run()来启动EventRunner;当EventRunner不被引用时,系统调用stop()来停止EventRunner。
  • 手动模式:需要开发者自行调用EventRunner的run()方法和stop()方法来确保线程的启动和停止。

接口说明

EventHandler

  • EventHandler的属性Priority(优先级)介绍:EventRunner将根据优先级的高低从事件队列中获取事件或者Runnable任务进行处理。

开发步骤

EventHandler投递InnerEvent事件

EventHandler投递InnerEvent事件,并按照优先级和延时进行处理,开发步骤如下:

  1. 创建EventHandler的子类,在子类中重写实现方法processEvent()来处理事件。
private static final int EVENT_MESSAGE_NORMAL = 1;
private static final int EVENT_MESSAGE_DELAY = 2;

private class MyEventHandler extends EventHandler {
    private MyEventHandler(EventRunner runner) {
        super(runner);
    }
    // 重写实现processEvent方法
    @Override
    public void processEvent(InnerEvent event) {
        super.processEvent(event);
        if (event == null) {
            return;
        }
        int eventId = event.eventId;
        switch (eventId) {
            case EVENT_MESSAGE_NORMAL:
                // 待执行的操作,由开发者定义
                break;
            case EVENT_MESSAGE_DELAY:
                // 待执行的操作,由开发者定义
                break;
            default:
                break;
        }
    }
}

创建EventRunner,以手动模式为例。

EventRunner runner = EventRunner.create(false);// create()的参数是true时,则为托管模式

创建EventHandler子类的实例。

MyEventHandler myHandler = new MyEventHandler(runner);

获取InnerEvent事件。

// 获取事件实例,其属性eventId, param, object由开发者确定,代码中只是示例。
long param = 0L; 
Object object = null; 
InnerEvent normalInnerEvent = InnerEvent.get(EVENT_MESSAGE_NORMAL, param, object);
InnerEvent delayInnerEvent = InnerEvent.get(EVENT_MESSAGE_DELAY, param, object);

投递事件,投递的优先级以IMMEDIATE为例,延时选择0ms和2ms。

// 优先级IMMEDIATE,投递之后立即处理,延时为0ms,该语句等价于同步投递sendSyncEvent(event1,EventHandler.Priority.IMMEDIATE);
myHandler.sendEvent(normalInnerEvent, 0, EventHandler.Priority.IMMEDIATE);
myHandler.sendEvent(delayInnerEvent, 2, EventHandler.Priority.IMMEDIATE); // 延时2ms后立即处理

启动和停止EventRunner,如果为托管模式,则不需要此步骤。

runner.run();
// 待执行操作
runner.stop();// 开发者根据业务需要在适当时机停止EventRunner

EventHandler投递Runnable任务

EventHandler投递Runnable任务,并按照优先级和延时进行处理,开发步骤如下:

  1. 创建EventHandler的子类,创建EventRunner,并创建EventHandler子类的实例,步骤与EventHandler投递InnerEvent场景的步骤1-3相同。
  2. 创建Runnable任务。
Runnable normalTask = new Runnable() {
    @Override
    public void run() {
        // 待执行的操作,由开发者定义
    }
};
Runnable delayTask = new Runnable() {
    @Override
    public void run() {
        // 待执行的操作,由开发者定义
    }
};

投递Runnable任务,投递的优先级以IMMEDIATE为例,延时选择0ms和2ms。

// 优先级为immediate,延时0ms,该语句等价于同步投递myHandler.postSyncTask(task1,EventHandler.Priority.IMMEDIATE);
myHandler.postTask(normalTask, 0, EventHandler.Priority.IMMEDIATE);

myHandler.postTask(delayTask, 2, EventHandler.Priority.IMMEDIATE);// 延时2ms后立即执行

启动和停止EventRunner,如果是托管模式,则不需要此步骤。

runner.run();
// 待执行操作

runner.stop();// 停止EventRunner

在新创建的线程里投递事件到原线程

EventHandler从新创建的线程投递事件到原线程并进行处理,开发步骤如下:

  1. 创建EventHandler的子类,在子类中重写实现方法processEvent()来处理事件。
private static final int EVENT_MESSAGE_CROSS_THREAD = 1;

private class MyEventHandler extends EventHandler {
    private MyEventHandler(EventRunner runner) {
        super(runner);
    }
    // 重写实现processEvent方法
    @Override
    public void processEvent(InnerEvent event) {
        super.processEvent(event);
        if (event == null) {
            return;
        }
        int eventId = event.eventId;
        switch (eventId) {
            case EVENT_MESSAGE_CROSS_THREAD:
                Object object = event.object;
                if (object instanceof EventRunner) {
                    // 将原先线程的EventRunner实例投递给新创建的线程
                    EventRunner runner2 = (EventRunner) object;
                    // 将原先线程的EventRunner实例与新创建的线程的EventHandler绑定
                    EventHandler myHandler2 = new EventHandler(runner2) {
                        @Override
                        public void processEvent(InnerEvent event) {
                            // 需要在原先线程执行的操作
                        }
                    };
                    int eventId2 = 1; 
                    long param2 = 0L; 
                    Object object2 = null; 
                    InnerEvent event2 = InnerEvent.get(eventId2, param2, object2);
                    myHandler2.sendEvent(event2); // 投递事件到原先的线程
                }
                break;
            default:
                break;
        }
    }
}

创建EventRunner,以手动模式为例。

EventRunner runner = EventRunner.create(false);// create()的参数是true时,则为托管模式。

创建EventHandler子类的实例。

MyEventHandler myHandler = new MyEventHandler(runner);

获取InnerEvent事件。

// 获取事件实例,其属性eventId, param, object由开发者确定,代码中只是示例。
long param = 0L; 
InnerEvent event = InnerEvent.get(EVENT_MESSAGE_CROSS_THREAD, param, EventRunner.current());

投递事件,在新线程上直接处理。

// 将与当前线程绑定的EventRunner投递到与runner创建的新线程中
myHandler.sendEvent(event);

启动和停止EventRunner,如果是托管模式,则不需要此步骤。

runner.run();
// 待执行操作

runner.stop();// 停止EventRunner

完整代码示例

非托管情况:

// 全局:
public static final int CODE_DOWNLOAD_FILE1 = 1;
public static final int CODE_DOWNLOAD_FILE2 = 2;
public static final int CODE_DOWNLOAD_FILE3 = 3;

// 线程A:
EventRunner runnerA = EventRunner.create(false);
runnerA.run(); // run之后一直循环卡在这里,所以需要新建一个线程run

// 线程B:
// 1.创建类继承EventHandler
public class MyEventHandler extends EventHandler {
    private MyEventHandler(EventRunner runner) {
        super(runner);
    }

    @Override
    public void processEvent(InnerEvent event) {
        super.processEvent(event);
        if (event == null) {
            return;
        }

        int eventId = event.eventId;
        switch (eventId) {
            case CODE_DOWNLOAD_FILE1: {
                // 待执行的操作,由开发者定义
                break;
            }
            case CODE_DOWNLOAD_FILE2: {
                // 待执行的操作,由开发者定义
                break;
            }
            case CODE_DOWNLOAD_FILE3: {
                // 待执行的操作,由开发者定义
                break;
            }
            default:
                break;
        }
    }
}

// 2.创建MyEventHandler实例
MyEventHandler handler = new MyEventHandler(runnerA);

// 3.向线程A发送事件
handler.sendEvent(CODE_DOWNLOAD_FILE1);
handler.sendEvent(CODE_DOWNLOAD_FILE2);
handler.sendEvent(CODE_DOWNLOAD_FILE3);

// 4.runnerA不再使用后,退出
runnerA.stop();

托管情况:

// 全局:
public static final int CODE_DOWNLOAD_FILE1 = 1;
public static final int CODE_DOWNLOAD_FILE2 = 2;
public static final int CODE_DOWNLOAD_FILE3 = 3;

// 1.创建EventRunner A:
EventRunner runnerA = EventRunner.create("downloadRunner"); // 内部会新建一个线程

// 2.创建类继承EventHandler
public class MyEventHandler extends EventHandler {
    private MyEventHandler(EventRunner runner) {
        super(runner);
    }

    @Override
    public void processEvent(InnerEvent event) {
        super.processEvent(event);
        if (event == null) {
            return;
        }

        int eventId = event.eventId;
        switch (eventId) {
            case CODE_DOWNLOAD_FILE1: {
                // 待执行的操作,由开发者定义
                break;
            }
            case CODE_DOWNLOAD_FILE2: {
                // 待执行的操作,由开发者定义
                break;
            }
            case CODE_DOWNLOAD_FILE3: {
                // 待执行的操作,由开发者定义
                break;
            }
            default:
                break;
        }
    }
}

// 3.创建MyEventHandler实例
MyEventHandler handler = new MyEventHandler(runnerA);

// 4.向线程A发送事件
handler.sendEvent(CODE_DOWNLOAD_FILE1);
handler.sendEvent(CODE_DOWNLOAD_FILE2);
handler.sendEvent(CODE_DOWNLOAD_FILE3);

// 5.runnerA没有任何对象引入时,线程会自动回收
runnerA = null;

相关实例

针对线程间通信,有以下示例工程可供参考:

  • EventHandler本示例演示了将InnerEvent事件投递到新的线程、将Runnable任务投递到新的线程、在新创建的线程里投递事件到原线程进行处理三种场景。

针对线程间通信,有以下Codelabs可供参考:

0 0 投票数
文章评分
订阅评论
提醒
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x