zoukankan      html  css  js  c++  java
  • 第三十四篇:在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

  • 相关阅读:
    SpringRequestContext源码阅读
    MyBatis事务管理源码阅读
    linux查找依赖文件
    GitHub
    Qt Quick
    centos7下安装chrome
    软件使用
    排序算法之冒泡排序
    c++学习
    cent6.4使用
  • 原文地址:https://www.cnblogs.com/setoutsoft/p/5642056.html
Copyright © 2011-2022 走看看