第三十四篇:在SOUI中使用异步通知

概述

异步通知是客户端开发中常见的需求,比如在一个网络处理线程中要通知UI线程更新等等。

通常在Windows编程中,为了方便,我们一般会向UI线程的窗口句柄Post/Send一个窗口消息从而达到将非UI线程的事件切换到UI线程处理的目的。

在SOUI引入通知中心以前要在SOUI中处理非UI线程事件我也推荐用上面的方法。

使用窗口消息至少有以下两个不足:

1、需要在线程中持有一个窗口句柄。

2、发出的消息只能在该窗口句柄的消息处理函数里处理。

SNotifyCenter

最新的SOUI引入了一个新的单例对象:SNotifyCenter,专门用来处理这类问题。

新的SNotifyCenter解决了窗口消息存在的上面的两个问题:

1、通过使用全局单例,SNotifyCenter可以在代码任意位置获取它的指针(前提当然是要在它的生命周期内);

2、使用SNotifyCenter产生的通知采用SOUI的事件系统来派发,通过结合SOUI的事件订阅系统,用户可以在任意位置处理发出的事件。

在介绍如何使用SNotifyCenter前,先看一下NotifyCenter.h的代码:

 1 #pragma once
 2
 3 #include <core/SSingleton.h>
 4
 5 namespace SOUI
 6 {
 7     template<class T>
 8     class TAutoEventMapReg
 9     {
10         typedef TAutoEventMapReg<T> _thisClass;
11     public:
12         TAutoEventMapReg()
13         {
14             SNotifyCenter::getSingleton().RegisterEventMap(Subscriber(&_thisClass::OnEvent,this));
15         }
16
17         ~TAutoEventMapReg()
18         {
19             SNotifyCenter::getSingleton().UnregisterEventMap(Subscriber(&_thisClass::OnEvent,this));
20         }
21
22     protected:
23         bool OnEvent(EventArgs *e){
24             T * pThis = static_cast<T*>(this);
25             return !!pThis->_HandleEvent(e);
26         }
27     };
28
29     class SOUI_EXP SNotifyCenter : public SSingleton<SNotifyCenter>
30                         , public SEventSet
31     {
32     public:
33         SNotifyCenter(void);
34         ~SNotifyCenter(void);
35
36         /**
37         * FireEventSync
38         * @brief    触发一个同步通知事件
39         * @param    EventArgs *e -- 事件对象
40         * @return
41         *
42         * Describe  只能在UI线程中调用
43         */
44         void FireEventSync(EventArgs *e);
45
46         /**
47         * FireEventAsync
48         * @brief    触发一个异步通知事件
49         * @param    EventArgs *e -- 事件对象
50         * @return
51         *
52         * Describe  可以在非UI线程中调用,EventArgs *e必须是从堆上分配的内存,调用后使用Release释放引用计数
53         */
54         void FireEventAsync(EventArgs *e);
55
56
57         /**
58         * RegisterEventMap
59         * @brief    注册一个处理通知的对象
60         * @param    const ISlotFunctor &slot -- 事件处理对象
61         * @return
62         *
63         * Describe
64         */
65         bool RegisterEventMap(const ISlotFunctor &slot);
66
67         /**
68         * RegisterEventMap
69         * @brief    注销一个处理通知的对象
70         * @param    const ISlotFunctor &slot -- 事件处理对象
71         * @return
72         *
73         * Describe
74         */
75         bool UnregisterEventMap(const ISlotFunctor & slot);
76     protected:
77         void OnFireEvent(EventArgs *e);
78
79         void ExecutePendingEvents();
80
81         static VOID CALLBACK OnTimer( HWND hwnd,
82             UINT uMsg,
83             UINT_PTR idEvent,
84             DWORD dwTime
85             );
86
87         SCriticalSection    m_cs;            //线程同步对象
88         SList<EventArgs*>    *m_evtPending;//挂起的等待执行的事件
89         DWORD                m_dwMainTrdID;//主线程ID
90
91         UINT_PTR            m_timerID;    //定时器ID,用来执行异步事件
92
93         SList<ISlotFunctor*>    m_evtHandlerMap;
94     };
95 }

在这个文件中提供了两个类,一个就是SNotifyCenter,另一个是TAutoEventMapReg<T>。

可以看到SNotifyCenter中除构造外只有4个public方法:

FireEventSync, FireEventAsync用来触发事件。

RegisterEventMap,UnregisterEventMap则用来提供事件处理订阅。

如何使用SNotifyCenter?

1、在main中实例化SNotifyCenter。(不明白可以参考demo)

2、定义需要通过通知中心分发的事件类型,首先定义事件,然后向通知中心注册,参见下面代码:

 1 void CMainDlg::OnBtnStartNotifyThread()
 2 {
 3     if(IsRunning()) return;
 4     SNotifyCenter::getSingleton().addEvent(EVENTID(EventThreadStart));
 5     SNotifyCenter::getSingleton().addEvent(EVENTID(EventThreadStop));
 6     SNotifyCenter::getSingleton().addEvent(EVENTID(EventThread));
 7
 8     EventThreadStart evt(this);
 9     SNotifyCenter::getSingleton().FireEventSync(&evt);
10     BeginThread();
11 }
12
13 void CMainDlg::OnBtnStopNotifyThread()
14 {
15     if(!IsRunning()) return;
16
17     EndThread();
18     EventThreadStop evt(this);
19     SNotifyCenter::getSingleton().FireEventSync(&evt);
20
21     SNotifyCenter::getSingleton().removeEvent(EventThreadStart::EventID);
22     SNotifyCenter::getSingleton().removeEvent(EventThreadStop::EventID);
23     SNotifyCenter::getSingleton().removeEvent(EventThread::EventID);
24 }

3、使需要处理通知中心分发的事件的对象从TAutoEventMapReg继承,实现事件的自动订阅(方便在事件映射表中统一处理事件),这一步是可选的,你也可以直接使用SOUI提供的事件订阅机制向通知中心订阅特定事件。

4、在事件映射表里处理事件(没有第3步时,则同样没有这一步)。

具体用法参见SOUI的demo。

时间: 2025-01-04 08:38:10

第三十四篇:在SOUI中使用异步通知的相关文章

Egret入门学习日记 --- 第六十四篇(书中 19.4 节 内容)

第六十四篇(书中 19.4 节 内容) 昨天的问题,是 images 库自己本身的问题. 我单独使用都报错. 这是main.js文件代码: let images = require("images"); console.log(images); 这是cmd运行命令历史: Microsoft Windows [版本 10.0.16299.15] (c) 2017 Microsoft Corporation.保留所有权利. C:\Users\Administrator\Desktop\a&

Egret入门学习日记 --- 第二十四篇(书中 9.12~9.15 节 内容)

第二十四篇(书中 9.12~9.15 节 内容) 开始 9.12节 内容. 重点: 1.TextInput的使用,以及如何设置加密属性. 操作: 1.TextInput的使用,以及如何设置加密属性. 创建exml文件,拖入组件,设置好id. 这是显示密码星号处理的属性. 创建绑定类. 实例化,并运行. 但是焦点在密码输入框时,密码是显示的. 暂时不知道怎么设置 “焦点在密码框上时,还是显示为 * 号” 的方法. 至此,9.12节 内容结束. 开始 9.13节 . 这个,和TextInput的使用

Egret入门学习日记 --- 第三十六篇(书中 10.7 ~ 10.8 节 内容)

第三十六篇(书中 10.7 ~ 10.8 节 内容) 开始 书中 10.7 节内容. 书中 10.7 节内容结束. 书中重点: 1.导出素材. 2.配置粒子库. 3.播放动画. 开始操作: 1.导出素材. 我设置好了雪花的效果. 接着是导出. 这是导出后的资源文件. 导入Egret的预加载资源组中. 2.配置粒子库. 下载好官方的粒子库. https://github.com/egret-labs/egret-game-library 拷贝粒子库到项目外,记住 项目文件夹外! 配置好 egret

第二十八篇:SOUI中自定义控件开发过程

在SOUI中已经提供了大部分常用的控件,但是内置控件不可能满足用户的所有要求,因此一个真实的应用少不得还要做一些自定义控件. 学习一个新东西,最简单的办法就是依葫芦画瓢.事实上在SOUI系统中内置控件和自定义控件的开发流程是完全一样的,因此只需要打开SOUI的源代码,随便找一个控件看一下就大体差不多了. 下面我以controls.extend目录下的的SRadioBox2控件为例对控件开发过程需要注意的地方做一点说明. 要开发一个控件,首先要确定的是应该从哪个控件来继承.选择一个合适的基类是正确

第三十四篇 Python面向对象之 反射(自省)

什么是反射? 反射的概念是由Smith在1982年提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成就. 四个可以实现自省的函数,是Python的内置函数 下列方法适用于类和对象 先看这四个方法对实例(b1)的使用 # 演示代码 class BlackMedium: feature = 'Ugly' def __init__(self, nam

第三十四篇:Quartz2D绘图

1.Quartz2D在iOS开发中的价值 ?自定义view(自定义UI控件) 2.图形上下文 1)图形上下文(Graphics Context):是一个CGContextRef类型的数据 2)图形上下文的作用 ?保存绘图信息.绘图状态 ?决定绘制的输出目标(绘制到什么地方去?) (输出目标可以是PDF文件.Bitmap或者显示器的窗口上) 3)相同的一套绘图序列,指定不同的GraphicsContext,就可将相同的图像绘制到不同的目标上 4)Quartz2D提供了以下几种类型的Graphics

LeetCode第三十四题-寻找数组中对应目标值的首尾索引

Find First and Last Position of Element in Sorted Array 问题简介:给定按升序排序的整数数组,找到给定目标值的起始位置和结束位置. 注: 1.算法的运行时复杂度必须为O(log n) 2.如果在数组中找不到目标,则返回[-1,-1] 举例: 1: 输入: nums = [5,7,7,8,8,10], target = 8 输出: [3,4] 2: 输入: nums = [5,7,7,8,8,10], target = 6 输出: [-1,-1

小刘同学的第一百三十四篇日记

坚持果然是最艰难的事. 今天还是更新不了博文,不过也不想勉强自己. 的确被论文所困,老师总是很严格的指出我的问题,并且让我逐一修改. 其实一直以来都很讨厌这样的自己. 什么事情都拖到最后-- 总是提前做完休息活动.娱乐活动-- 最应该,也是最需要做的东西,结果什么都没做-- 这样的自己,真是连自己都看不起呢. 马上就要变成社会人士了. 自己不在校园,更应该把任务和工作提前做好做完. 再考虑娱乐和休息. 说了这么多,也只是想提醒自己,也提醒大家. 一定是先完成工作.再休息娱乐ヽ(`Д′)? 牢记小

[原创]ActionScript3游戏中的图像编程(连载三十四)

2.2.7 关于Photoshop的图层挖空投影 在Photoshop里面,不管图层挖空投影的复选框是否处于勾选状态,显示出来的效果都几乎没有任何差别.那这个挖空的作用何在?不急,我们看看Flash里的挖空选项. Flash里的挖空很明显,图 2.23展示了挖空后的效果. 图 2.23 Flash的挖空投影 Flash的投影滤镜把常规显示的像素颜色都掏空了.从挖空的现象和隐藏对象的字面意思来看,两者含义似乎一致,但结果却出乎我的意料.(图 2.24) 图 2.24 隐藏对象 可见,投影与文字本身