OpenHarmony的线程间通信EventHandler

一、初识EventHandler

​ 在OpenHarmony的开发过程中,如果遇到处理下载、运算等较为耗时的操作时,会阻塞当前线程,但是实际操作中又不希望当前线程受到阻塞。比如:我们的app在界面上有一个下载文件的处理按钮,如果在按钮按下时,直接处理下载任务时,当前的界面就会阻塞,不允许操作界面上的任何控件。解决此阻塞的办法,一般的处理方式是通过新开一个线程或进程的来处理此耗时的操作,然后通过同步数据的方式来进行界面上关于下载进度的刷新。

​ OpenHarmony系统为此提供了统一的EventHandler机制来处理线程间通信。以下通过简单的实例来比较EventHandler机制的与一般的线程之间的方便性与易理解性。

1.1 使用EventHandler

1.1.1 EventHandler投递InnerEvent事件

  • 首先创建EventHandler的子类,在子类中重写实现ProcessEvent来处理事件。
// base\telephony\core_service\services\network_search\include\network_search_handler.h
class NetworkSearchHandler : public AppExecFwk::EventHandler {
public:
...void ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event) override;
...void AutoTimeChange(const AppExecFwk::InnerEvent::Pointer &);
...
private:static const std::map<uint32_t, NsHandlerFunc> memberFuncMap_;
};
// base\telephony\core_service\services\network_search\src\network_search_handler.cpp
const std::map<uint32_t, NetworkSearchHandler::NsHandlerFunc> NetworkSearchHandler::memberFuncMap_ = {
...{ SettingEventCode::MSG_AUTO_TIME, &NetworkSearchHandler::AutoTimeChange },
...
};
...
void NetworkSearchHandler::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
{if (event == nullptr) {return;}auto msgType = event->GetInnerEventId();TELEPHONY_LOGD("NetworkSearchHandler::ProcessEvent received event slotId:%{public}d msgType:%{public}d", slotId_, msgType);auto itFunc = memberFuncMap_.find(static_cast<RadioEvent>(msgType));if (itFunc != memberFuncMap_.end()) {auto memberFunc = itFunc->second;if (memberFunc != nullptr) {(this->*memberFunc)(event);}}
}

在ProcessEvent中根据事件类型Id映射对应的处理接口。

  • 创建EventRunner事件循环器,EventRunner创建新线程,从EventQueue队列中获取InnerEvent事件,分发到EventHandler的子类的ProcessEvent进行处理。
  • 关联EventRunner至EventHandler的子类NetworkSearchHandler
// base\telephony\core_service\services\network_search\src\network_search_manager.cpp
bool NetworkSearchManager::InitPointer(std::shared_ptr<NetworkSearchManagerInner> &inner, int32_t slotId)
{if (inner == nullptr) {TELEPHONY_LOGE("NetworkSearchManager::InitPointer failed . inner is null");return false;}std::string name = "NetworkSearchManager_";name.append(std::to_string(slotId));// 创建EventRunner事件循环器inner->eventLoop_ = AppExecFwk::EventRunner::Create(name.c_str());if (inner->eventLoop_.get() == nullptr) {TELEPHONY_LOGE("NetworkSearchManager failed to create EventRunner slotId:%{public}d", slotId);return false;}
...// 关联EventRunner至EventHandler的子类NetworkSearchHandlerinner->networkSearchHandler_ = std::make_shared<NetworkSearchHandler>(inner->eventLoop_, shared_from_this(), telRilManager_, simManager_, slotId);if (inner->networkSearchHandler_ == nullptr) {TELEPHONY_LOGE("failed to create new NetworkSearchHandler slotId:%{public}d", slotId);return false;}
...return true;
}
  • 启动EventRunner: eventLoop_->Run();
// base\telephony\core_service\services\network_search\include\network_search_manager.h
bool Init()
{
...if (eventLoop_ != nullptr) {eventLoop_->Run();}
...return true;
}
  • InnerEvent事件投递: networkSearchHandler_->SendEvent(event);
// base\telephony\core_service\services\network_search\src\setting_utils.cpp
void AutoTimeObserver::OnChange()
{std::shared_ptr<SettingUtils> settingHelper = SettingUtils::GetInstance();if (settingHelper == nullptr) {TELEPHONY_LOGI("settingHelper is null");return;}TELEPHONY_LOGI("AutoTimeObserver::OnChange");if (networkSearchHandler_ != nullptr) {InnerEvent::Pointer event = InnerEvent::Get(SettingEventCode::MSG_AUTO_TIME);networkSearchHandler_->SendEvent(event);}
}

根据投递的事件SettingEventCode::MSG_AUTO_TIME,在NetworkSearchHandler的memberFuncMap_中找到对应的实现AutoTimeChange

// base\telephony\core_service\services\network_search\src\network_search_handler.cpp
void NetworkSearchHandler::AutoTimeChange(const AppExecFwk::InnerEvent::Pointer &)
{TELEPHONY_LOGD("NetworkSearchHandler::AutoTimeChange");if (nitzUpdate_ != nullptr) {nitzUpdate_->AutoTimeChange();}
}

至此通过InnerEvent事件完成了异步的事件处理。

1.1.2 EventHandler投递Runnable任务

此种使用方式基本同上.

  • 首先创建EventHandler的子类,在子类中重写实现ProcessEvent来处理事件。
  • 创建回调函数
  • 投递Runnable任务
// base\account\os_account\services\accountmgr\src\appaccount\app_account_subscribe_manager.cpp
Callback callback = std::bind(&AppAccountSubscribeManager::OnAccountsChanged, this, eventRecordPtr);
return handler_->PostTask(callback);

二、原理概述

​ EventHandler是一种用户在当前线程上投递InnerEvent事件或者Runnable任务到异步线程上处理的机制。每一个EventHandler和指定的EventRunner所创建的线程绑定,并且该线程内部有一个事件队列。

​ EeventHandler可以投递指定的InnerEvent事件或Runnable任务到这个队列。EventRunner从事件队列里循环地取出事件,如果取出的事件是InnerEvent事件,将在EventRunner所在线程执行ProcessEvent回调。如果取出的是Runnable任务,将在EventRunner所在线程执行Runnable的run回调。

​ 一般来说,EventHandler有两个主要作用:

  • 在不同线程间分发和处理InnerEvent事件或Runnable任务。
  • 延迟处理InnerEvent事件或Runnable任务。

三、运行机制

在这里插入图片描述

使用EventHandler实现线程间通信的主要流程

  • EventHandler投递具体的InnerEvent事件或者Runnable任务到EventRunner所创建的线程的事件队列。
  • EventHandler循环从事件队列中获取InnerEvent事件或者Runnable任务
  • 处理事件或任务,如果取出的事件是InnerEvent事件,将在EventRunner所在线程执行ProcessEvent回调。如果取出的是Runnable任务,将在EventRunner所在线程执行Runnable的run回调。

四、约束条件

​ 在进行线程间通信时,EventHandler只能和EventRunner所创建的线程进行绑定,EventRunner创建时需要判断是否创建成功,只有确保获取的EventRunner实例非空时,才可以使得EventHandler绑定EventRunner.

​ 一个EventHandler只能同时与一个EventRunner绑定,一个EventRunner可以同时绑定多个EventHandler.

五、其它

5.1 关于sendEvent方法

sendEvent(InnerEvent event, long delayTime, EventHandler.Priority priority)
  • delayTime:Indicates the time period after which the event will be processed, in milliseconds. The value must be greater than 0. Otherwise, the event will not be delayed.

  • priority:Indicates the event priority.四类:HIGH、IDLE、IMMEDIATE、LOW

5.2 关于sendEvent传参的示例

// base\telephony\call_manager\services\call\include\call_request_handler.h
struct AnswerCallPara {int32_t callId;int32_t videoState;
};// base\telephony\call_manager\services\call\src\call_request_handler.cpp
CallRequestHandler::CallRequestHandler(const std::shared_ptr<AppExecFwk::EventRunner> &runner): AppExecFwk::EventHandler(runner), callRequestProcessPtr_(nullptr)
{memberFuncMap_[CallRequestHandlerService::HANDLER_DIAL_CALL_REQUEST] = &CallRequestHandler::DialCallEvent;memberFuncMap_[CallRequestHandlerService::HANDLER_ANSWER_CALL_REQUEST] = &CallRequestHandler::AcceptCallEvent;
...
}
...
void CallRequestHandler::AcceptCallEvent(const AppExecFwk::InnerEvent::Pointer &event)
{if (event == nullptr) {TELEPHONY_LOGE("CallRequestHandler::ProcessEvent parameter error");return;}auto object = event->GetUniqueObject<AnswerCallPara>();if (object == nullptr) {TELEPHONY_LOGE("object is nullptr!");return;}AnswerCallPara acceptPara = *object;if (callRequestProcessPtr_ == nullptr) {TELEPHONY_LOGE("callRequestProcessPtr_ is nullptr");return;}callRequestProcessPtr_->AnswerRequest(acceptPara.callId, acceptPara.videoState);
}
...
int32_t CallRequestHandlerService::AnswerCall(int32_t callId, int32_t videoState)
{if (handler_.get() == nullptr) {TELEPHONY_LOGE("handler_ is nullptr");return TELEPHONY_ERR_LOCAL_PTR_NULL;}std::unique_ptr<AnswerCallPara> para = std::make_unique<AnswerCallPara>();if (para.get() == nullptr) {TELEPHONY_LOGE("make_unique AnswerCallPara failed!");return TELEPHONY_ERR_LOCAL_PTR_NULL;}para->callId = callId;para->videoState = videoState;if (!handler_->SendEvent(HANDLER_ANSWER_CALL_REQUEST, std::move(para))) {TELEPHONY_LOGE("send accept event failed!");CallManagerHisysevent::WriteAnswerCallFaultEvent(INVALID_PARAMETER, callId, videoState,CALL_ERR_SYSTEM_EVENT_HANDLE_FAILURE, "send HANDLER_ANSWER_CALL_REQUEST event failed");return TELEPHONY_ERR_LOCAL_PTR_NULL;}return TELEPHONY_SUCCESS;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/352932.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

cocos 的EventHandler 事件派发器

cocos 的EventHandler 事件派发器 cc.Component.EventHandler 类 官方说明 “EventHandler” 类用来设置场景中的事件回调&#xff0c;该类允许用户设置回调目标节点&#xff0c;目标组件名&#xff0c;组件方法名&#xff0c;并可通过 emit 方法调用目标函数。 */export clas…

C# 的 事件 与 EventHandler

事件接受与发送是通过 委托来实现的&#xff0c;随意&#xff0c;在学习事件之前一定要知道委托。 首先我们先看下图&#xff1a;上的图不完整人&#xff0c;但大概是这个意思。 我们要创建一个事件管理。 来处理发布者发送消息和订阅者的接受消息中间转接。 然后订阅者去创建…

C# 实例解析事件委托之EventHandler

概述 事件属于委托的一个子集&#xff0c;像我们平时界面上的鼠标点击按钮后响应事件、事件的发布和订阅等都需要用到委托.通过委托可以很好的实现类之间的解耦好。事件委托EventHandler的 函数原型如下&#xff1a;delegate 表示这个个委托&#xff0c;事件委托没有返回值&…

wpf中EventHandler的使用

应用情景&#xff1a;比如点击A界面的a按钮&#xff0c;跳转到B界面了&#xff0c;点击b按钮后&#xff0c;触发了业务逻辑&#xff0c;然后需要回到A界面中执行某一个方法。不是唯一的方法&#xff0c;可以使用别的方法&#xff0c;类似观察者模式&#xff0c;有变化了&#x…

使用Transformer模型进行计算机视觉任务的端对端对象检测

Transformer模型是google团队在2017在论文attention is all you need中提出的一个用于NLP领域的模型,但是随着VIT模型与Swin Transformer模型的发布,把Transformer模型成功应用到计算机视觉任务中。 上期图文,我们使用hugging face的transformers模型进行了VIT模型的对象分…

3、线程通信EventHandler使用

作者&#xff1a;韩茹 公司&#xff1a;程序咖&#xff08;北京&#xff09;科技有限公司 鸿蒙巴士专栏作家 一、使用场景 EventHandler开发场景 EventHandler的主要功能是将InnerEvent事件或者Runnable任务投递到其他的线程进行处理&#xff0c;其使用的场景包括&#xff1a…

ChatGPT市场营销指南震撼出炉,你错过了?!

ChatGPT是一种基于AI技术的语言模型&#xff0c;它可以与用户进行对话和交互。它被广泛应用于各个领域&#xff0c;包括市场营销。作为一名市场营销人员&#xff0c;您可以使用ChatGPT来获得创意、解决问题和生成内容。 下面是190个ChatGPT提示&#xff0c;可帮助营销人员更好…

专业分析┃微电子专业介绍及发展前瞻

不知道提到微电子&#xff0c;你最先想到的是什么&#xff1f;芯片&#xff1f;卡脖子&#xff1f;摩尔定律&#xff1f; 因为近两年芯片被限制的原因&#xff0c;大家经常可以从各路媒体上看到“芯片”一词。微电子作为一个学科&#xff0c;简单的说&#xff0c;就是研究如何…

Cookie和session工作流程详解

目录 cookie机制 session会话 理解会话机制 Servlet中对Cookie和Session提供的 HttpServletrequest类中的方法&#xff1a; 模拟实现登录功能 首先实现功能分为两个界面&#xff1a; &#xff08;1&#xff09;登录页面代码&#xff08;前端代码&#xff09; (2) 编写Lo…

Mac - 鼠标拖尾特效 By CursorEffect2

目录 一.引言 二.安装 CursorEffect2 三.使用 CursorEffect2 四.使用效果 五.内存消耗 六.一键关闭 七.总结 一.引言 在自己搭建的 Hexo 博客上可以定义鼠标点击的特效&#xff0c;如图点击后可以产生彩色的斑点。 于是想着除了浏览 Hexo 博客外&#xff0c;能不能别的也…

MyBatis深入学习总结

MyBatis总结 MyBatis入门操作 简介 原始jdbc操作&#xff08;查询数据&#xff09; 原始jdbc操作&#xff08;插入数据&#xff09; 原始jdbc操作的分析 原始jdbbc开发存在的问题如下&#xff1a; 数据库连接创建、释放频繁造成系统资源的浪费从而影响系统性能sql语句在代…

window11中QQ登录“无法访问个人文件夹”解决方案

window11刚发行不久&#xff0c;安装各种软件或多或少会遇到各种bug&#xff0c;例如安装QQ后&#xff0c;打开时会提醒你“无法访问个人文件夹”而打开QQ失败。 可以通过改变你自己设置的个人文件夹的权限来解决这个问题。 找到文件夹所在位置&#xff0c;右击文件夹&#xf…

QQ登录显示无法访问个人文件夹解决办法

之前QQ登录出错&#xff0c;一直显示无法访问个人文件夹&#xff0c;是否自动修复个人文件权限 直接找到你安装qq的文件路径&#xff0c;右键--》授予访问权限--》删除访问&#xff0c;就可以正常登录了 &#xff01;

如何解决Windows10启动QQ时报错无法访问个人文件夹?

1、首先不要安装其他电脑管家&#xff0c;因为这会使Windows10自带的安全中心出现变化&#xff0c;第一步打开自带安全中心。 2、进入之后找到病毒和威胁防护&#xff0c;进入病毒和威胁防护设置。 3、进入病毒和威胁防护设置后&#xff0c;找到管理受控制文件夹访问权限。 4、…

启动QQ时无法访问个人文件夹XXX,是否自动修复个人文件夹权限

如图 点击确定显示修复权限失败 找到上图显示的文件路径 右键属性 -> 安全 -> 编辑 -> 选中Users -> 勾选完全控制

腾讯QQ登录“无法访问个人文件夹”解决方法

今天&#xff0c;登录QQ时出现“无法访问个人文件夹&#xff0c;个人文件将被保存到我的文档”的问题 上网搜索了一下&#xff0c;还是没有解决问题。然后自己思考了一下&#xff0c;可能与我修改了“我的文档”的路径有关&#xff0c;我刚刚安装的QQ个人文件夹也正好指定放在…

解决QQ显示“无法访问个人文件夹”方法

在qq登录的过程中&#xff0c;显示“无法访问个人文件夹”这样的提示&#xff0c;该怎解决&#xff1f; 尝试过把qq卸载之后重新装&#xff0c;改变一下qq的属性-兼容性&#xff0c;以及管理员的方式运行&#xff0c;查了不少的攻略&#xff0c;始终无法解决&#xff1b; 经过…

Win11 “qq无法访问个人文件夹”解决方法(原创)

今天登QQ&#xff0c;突然弹窗显示“qq无法访问个人文件夹”&#xff0c;网上搜了一堆方法都没用&#xff0c;也不想卸载重装qq&#xff0c;我就寻思是不是文件夹权限的问题。 右键显示的无法访问的个人文件夹&#xff0c;选择“安全”&#xff0c;我把Users的权限选中&#xf…

qq 微信 无法访问个人文件夹

昨天某个时刻开始&#xff0c;QQ会出现所有图片无法加载的状况&#xff0c;微信会出现截图发到聊天框是文件的问题。 一开始不以为然&#xff0c;直到第二天重启电脑发现两个软件都登陆不上去了。对应显示的是标题的关键字&#xff0c;因为问题已经解决就不截图了。 解决方案&…

android 新建桌面文件夹在哪里,添加并管理桌面文件夹

添加并管理桌面文件夹 我们在使用Android手机的时候&#xff0c;随着手机内安装的软件越来越多&#xff0c;比如说笔者的这个手机里&#xff0c;算了一下&#xff0c;一共装了110个应用程序&#xff0c;七个分页&#xff0c;每页显示16个图标。那么在这里我们设想一下&#xff…