JHandler——一套简单易用的 C++ 事件循环机制

零、JHandler

JHandler 是一套 C++ 的事件循环机制。 可在自行创建的线程中使用,也可以使用 JHandler 已封装好的独立线程处理事件。

项目地址:github.com/zincPower/J...

一、集成

将项目中 jhandler 文件夹拷贝添加到项目中,并在项目的 CMakeLists.txt 中添加以下配置即可:

cmake 复制代码
include_directories("添加的 jhandler 目录相对于当前 CMakeLists.txt 文件的路径"/jhandler/include)
add_subdirectory(jhandler)

target_link_libraries("链接目标名称" PUBLIC jhandler)

二、常规使用

1、使用 JHandler 自带的线程

JHandler 中已经准备好了 HandlerThread内部会在调用 start 方法后创建独立线程,按照放入消息和闭包的顺序,串行分发事件消息或执行闭包。

cpp 复制代码
// 创建 HandlerThread
auto handlerThread = jhandler::HandlerThread::create();
// 启动 HandlerThread ,内部会启动线程
handlerThread->start();

// 对 HandlerThread 进行使用

// 退出 HandlerThread ,会执行完已经放入的事件消息和闭包
handlerThread->quit();

quit 方法不会阻塞当前线程,会让 HandlerThread 内部线程在处理完所有的消息和闭包后关闭线程。

2、添加事件消息、闭包

启动 HandlerThread 后,可以放入闭包事件消息 Message

闭包: 调用 Handler->post(std::function<void()> fun) 方法放入闭包,具体下所示:

cpp 复制代码
auto name = "江澎涌";
handler->post([name]() {
jhandler::Log::i(TAG, "【runClosure】运行闭包 name=", name, " Looper 线程 id=", std::this_thread::get_id());
});

// 输出
// 【CommonUse】 【runClosure】运行闭包 name=江澎涌 Looper 线程 id=0x700000339000

事件消息 Message: 调用 Handler->sendMessage(std::unique_ptr<Message> message) 方法放入事件消息。

cpp 复制代码
auto message = jhandler::Message::obtain();             // 获取事件消息
message->what = SAY_HI;                                 // 事件类别
message->data = std::make_shared<std::string>("江澎涌"); // 事件数据
message->arg1 = 1994;
message->arg2 = 170;
handler->sendMessage(std::move(message));               // 放入事件消息

// 输出
// 【FirstCommonUseHandler】 【handleMessage】你好,江澎涌(1994,170) Looper 线程 id=0x70000589c000

如何处理事件消息,请查看 "自定义事件处理的 Handler" 小节。

3、移除消息

可以通过 Handler->removeMessage(int32_t what) 移除与 what 相同的事件消息。

cpp 复制代码
handler->removeMessage(SAY_HI);

可以通过 Handler->removeAllMessages() 移除所有的闭包和事件消息。

cpp 复制代码
handler->removeAllMessages();

4、定义处理事件消息的 Handler

放入的事件消息,需要开发者继承 jhandler::Handler 编写自定义事件处理的 Handler 进行接收处理。

在重写的 handleMessage 方法中接收放入的事件消息,编写相应业务的逻辑。具体编写如下:

cpp 复制代码
// 定义事件消息 what
static constexpr int SAY_HI = 10000;

// 定义 Handler
class FirstCommonUseHandler : public jhandler::Handler {
private:
    static std::string TAG;
public:
    explicit FirstCommonUseHandler(std::shared_ptr<jhandler::Looper> looper) {}
    void handleMessage(const std::unique_ptr<jhandler::Message> &message) override{
        // 此处接收 Message 编写自己的业务逻辑
        switch (message->what) {
            case SAY_HI: {
                auto name = message->getData<std::string>();
                auto year = message->arg1;
                auto height = message->arg2;
                Log::i(TAG, "【handleMessage】你好,", *name, "(", year, ",", height, ")", " Looper 线程 id=", std::this_thread::get_id());
                break;
            }
            case SHOW_DESCRIPTION: {
                Log::i(TAG, "【handleMessage】我是一个 C++ 事件循环机制 Looper 线程 id=", std::this_thread::get_id());
                break;
            }
        }
    }
};

// 创建 HandlerThread
auto handlerThread = jhandler::HandlerThread::create();
// 启动 HandlerThread
handlerThread->start();
// 获取 Looper
auto looper = handlerThread->getLooper();
// 创建自己的 Handler
auto handler = std::make_shared<FirstCommonUseHandler>(looper);
// 事件消息传递
auto message = jhandler::Message::obtain();
message->what = SAY_HI;
message->data = std::make_shared<std::string>("江澎涌");
message->arg1 = 1994;
message->arg2 = 170;
handler->sendMessage(std::move(message));

message = jhandler::Message::obtain();
message->what = SHOW_DESCRIPTION;
handler->sendMessage(std::move(message));

// 输出 
// 【FirstCommonUseHandler】 【handleMessage】你好,江澎涌(1994,170) Looper 线程 id=0x70000589c000
// 【FirstCommonUseHandler】 【handleMessage】我是一个 C++ 事件循环机制 Looper 线程 id=0x70000589c000

5、多个 Handler 解耦逻辑

有时需要将处理事件消息的逻辑解耦,可以考虑通过 Looper 创建多个 Handler ,将事件消息发送到对应的 Handler ,后续会由该 Handler 执行对应逻辑,并且多个 Handler 都是运行在同一个线程中,按添加顺序进行执行。

具体编写如下:

cpp 复制代码
auto handlerThread = jhandler::HandlerThread::create();
handlerThread->start();

auto looper = handlerThread->getLooper();
// 创建两个 Handler
auto handler1 = std::make_shared<FirstCommonUseHandler>(looper);
auto handler2 = std::make_shared<SecondCommonUseHandler>(looper);

// 向 handler1 发送 SAY_HI 类型的 message ,由 handler1 进行处理 
auto message = jhandler::Message::obtain();
message->what = SAY_HI;
message->data = std::make_shared<std::string>("江澎涌");
message->arg1 = 1994;
message->arg2 = 170;
handler1->sendMessage(std::move(message));

// 向 handler2 发送 SAY_HI 类型的 message ,由 handler2 进行处理 
message = jhandler::Message::obtain();
message->what = SAY_HI;
message->data = std::make_shared<std::string>("jiang peng yong");
message->arg1 = 2025;
message->arg2 = 100;
handler2->sendMessage(std::move(message));

// 会看到以下输出,虽然是同一类型消息,但由不同 Handler 进行处理,并且线程是相同的且按顺序执行
//【FirstCommonUseHandler】 【handleMessage】你好,江澎涌(1994,170) Looper 线程 id=0x700009ae3000
//【SecondCommonUseHandler】 【handleMessage】hello, jiang peng yong(2025,100) Looper 线程 id=0x700009ae3000

FirstCommonUseHandlerSecondCommonUseHandler 请查看源码不再赘述。

三、自定义线程中使用 JHandler

有些情况下,需要在自己的线程中使用事件循环机制,所以 JHandler 也支持在自定义线程中增加事件循环机制。

例如在鸿蒙中,需要封装一个 OpenGL 线程给到相机使用,OpenGL 是线程相关的,需要一个事件循环不断的处理每一帧数据,同时处理好 Surface 、滤镜等数据。以下便是一个 OpenGL 的模拟样例:

完整代码可以查看 thread_use.cpp

在自定义线程中,按照如下步骤进行:

  1. 增加 egl 的创建,通过 jhandler::Looper::create() 创建 Looper ,然后创建内部的 Handler 用于处理后续的相机帧、滤镜管理等。
  2. 调用 Looper::loop() 方法,进入事件循环,直到外部调用 Looper::quit() 终止事件循环。
  3. 释放和回收 egl 相关资源。
cpp 复制代码
void GLThread::loop(const std::shared_ptr<GLThread> &glThread) {
    Log::i(TAG, "------------------------ 进入 GLThread 启动 GL 逻辑 ------------------------ thread id=", std::this_thread::get_id());

    Log::i(TAG, "------------------------ 模拟创建 EGL 相关环境 ------------------------ thread id=", std::this_thread::get_id());
    // 睡眠了 500 毫秒,模拟创建 EGL
    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    Log::i(TAG, "------------------------ 进入事件循环 ------------------------ thread id=", std::this_thread::get_id());
    glThread->mLooper->loop();
    Log::i(TAG, "------------------------ 退出事件循环 ------------------------ thread id=", std::this_thread::get_id());

    Log::i(TAG, "------------------------ 开始释放资源 ------------------------ thread id=", std::this_thread::get_id());

    Log::i(TAG, "------------------------ 释放 EGL ------------------------ thread id=", std::this_thread::get_id());

    Log::i(TAG, "------------------------ 释放 Handler ------------------------ thread id=", std::this_thread::get_id());
    glThread->mHandler->removeAllMessages();
    glThread->mHandler = nullptr;

    Log::i(TAG, "释放 Looper");
    glThread->mLooper = nullptr;
    quitLoop(glThread);
    Log::i(TAG, "------------------------ 退出 GLThread 线程 ------------------------ thread id=", std::this_thread::get_id());
}

同样也支持多个 Handler 解耦逻辑,通过获取内部的 Looper 创建对应的 Handler 即可。

cpp 复制代码
void threadUse() {
    auto glThread = std::make_shared<GLThread>();
    glThread->start();

    // 创建业务需要的 handler ,可以不耦合 gl 的相关流程
    auto businessHandler = std::make_shared<BusinessHandler>(glThread->getLooper());
    businessHandler->sayHello();

    auto glHandler = glThread->getHandler();
    glHandler->addFilter();
    glHandler->requestRender();
    glHandler->removeFilter();

    businessHandler->sayHello();

    glThread->quit();

    // 为了让内部执行外,才结束整个项目运行。
    std::this_thread::sleep_for(std::chrono::seconds(1));
    
    // 输出
    // 【GLHandler】 添加滤镜 filterName=0x600002314048 thread id=0x700009ae3000
    // 【GLHandler】 进行渲染 thread id=0x700009ae3000
    // 【GLHandler】 移除滤镜 filterName=0x600002314078 thread id=0x700009ae3000
    // 【BusinessHandler】 你好 thread id=0x700009ae3000
}

四、作者简介

掘金:juejin.im/user/5c3033...

csdn:blog.csdn.net/weixin_3762...

公众号:微信搜索 "江澎涌"

相关推荐
liu****1 小时前
5.C语言数组
c语言·开发语言·c++
毛甘木1 小时前
Unity MonoPInvokeCallback 使用教程
c++·unity
吗~喽2 小时前
【LeetCode】滑动窗口_水果成篮_C++
c++·算法·leetcode
心疼你的一切2 小时前
Unity开发Rokid应用之离线语音指令交互模型
android·开发语言·unity·游戏引擎·交互·lucene
BestOrNothing_20152 小时前
【C++基础】Day 4:关键字之 new、malloc、constexpr、const、extern及static
c++·八股文·static·extern·new与malloc·constexpr与const
爱笑的眼睛112 小时前
HarmonyOS运动健康应用开发:构建智能计步器的深度实践
华为·harmonyos
无敌最俊朗@2 小时前
如何把一个压缩的视频文件,解压成一张张原始图片-decode_video.c
c++
fpcc2 小时前
C++编程实践——手动实现std::visit
c++
重启的码农2 小时前
enet源码解析(4)多通道机制 (Channels)
c++·网络协议