zoukankan      html  css  js  c++  java
  • MVVMLight消息通知实现机制详解(二)

      接上文 MVVMLight消息通知实现机制详解(一)

    1. 该工具的内部主要逻辑是以字典模式进行储存持有订阅对象设置的传入参数Type类型、Key值、Action、Target(订阅对象本身)
    2. 在发生订阅事件和触发订阅事件时都会调用通过查询上述字典进行匹配,找到Key值相同&&Type类型相同的值,执行target的action并传入参数
    3. 扩展1:可发生没有key值的订阅事件,只要传参类型相同就可以
    4. 扩展2:可发生静态类的订阅事件,其内部有判断是否为static,static时target可为空

      找到源码看到,订阅事件部分代码:

      public virtual void Register<TMessage>( object recipient,object token,bool receiveDerivedMessagesToo,Action<TMessage> action,bool keepTargetAlive = false)
            {
                lock (_registerLock)
                {
                    var messageType = typeof(TMessage);
    
                    Dictionary<Type, List<WeakActionAndToken>> recipients;
    
                    if (receiveDerivedMessagesToo)
                    {
                        if (_recipientsOfSubclassesAction == null)
                        {
                            _recipientsOfSubclassesAction = new Dictionary<Type, List<WeakActionAndToken>>();
                        }
    
                        recipients = _recipientsOfSubclassesAction;
                    }
                    else
                    {
                        if (_recipientsStrictAction == null)
                        {
                            _recipientsStrictAction = new Dictionary<Type, List<WeakActionAndToken>>();
                        }
    
                        recipients = _recipientsStrictAction;
                    }
    
                    lock (recipients)
                    {
                        List<WeakActionAndToken> list;
    
                        if (!recipients.ContainsKey(messageType))
                        {
                            list = new List<WeakActionAndToken>();
                            recipients.Add(messageType, list);
                        }
                        else
                        {
                            list = recipients[messageType];
                        }
    
                        var weakAction = new WeakAction<TMessage>(recipient, action, keepTargetAlive);
    
                        var item = new WeakActionAndToken
                        {
                            Action = weakAction,
                            Token = token
                        };
    
                        list.Add(item);
                    }
                }
    
                RequestCleanup();
            }
    

      以上是源码上订阅事件代码,其具体逻辑如下:

    1. 以Dictionary<Type, List<WeakActionAndToken>> 类型持有数据,对每一个订阅事件都是先在Dictionary的Key上查找是否存在该传参类型,不存在就添加该类型(Add(type,new List<WeakActionAndToken>)),存在就添加到该类型对应的Value列表中

    2. 在其Value值上是List<WeakActionAndToken>类型,WeakActionAndToken包含本次订阅事件的Action和Key值

      

      源码Send部分代码:

     private void SendToTargetOrType<TMessage>(TMessage message, Type messageTargetType, object token)
            {
                var messageType = typeof(TMessage);
    
                if (_recipientsOfSubclassesAction != null)
                {
                    // Clone to protect from people registering in a "receive message" method
                    // Correction Messaging BL0008.002
                    var listClone =
                        _recipientsOfSubclassesAction.Keys.Take(_recipientsOfSubclassesAction.Count()).ToList();
    
                    foreach (var type in listClone)
                    {
                        List<WeakActionAndToken> list = null;
    
                        if (messageType == type
                            || messageType.IsSubclassOf(type)
                            || type.IsAssignableFrom(messageType))
                        {
                            lock (_recipientsOfSubclassesAction)
                            {
                                list = _recipientsOfSubclassesAction[type].Take(_recipientsOfSubclassesAction[type].Count()).ToList();
                            }
                        }
    
                        SendToList(message, list, messageTargetType, token);
                    }
                }
    
                if (_recipientsStrictAction != null)
                {
                    List<WeakActionAndToken> list = null;
    
                    lock (_recipientsStrictAction)
                    {
                        if (_recipientsStrictAction.ContainsKey(messageType))
                        {
                            list = _recipientsStrictAction[messageType]
                                .Take(_recipientsStrictAction[messageType].Count())
                                .ToList();
                        }
                    }
    
                    if (list != null)
                    {
                        SendToList(message, list, messageTargetType, token);
                    }
                }
    
                RequestCleanup();
            }
    

      以上是源码上发送事件消息代码,其具体逻辑如下:

    • 根据传参Type值在Dictionary<Type, List<WeakActionAndToken>>上查找对应List<WeakActionAndToken>列表
    • 然后对该列表内WeakActionAndToken进行匹配,对应Key值是否相同
    • 找到Key值相同的WeakActionAndToken执行其Action

      备注:在Send()部分应该加异步发送消息,个人自测频率太快的调用会造成卡顿延迟(类似心跳包这种就有点费劲)

      源码:MVVMLight的消息发送工具源码,可单独使用

  • 相关阅读:
    由@Convert注解引出的jackson对枚举的反序列化规则
    List.contains()与自动拆箱
    Utf-8+Bom编码导致的读取数据部分异常问题
    ResouceUtils.getFile()取不到Jar中资源文件源码小结
    Java自动装箱中的缓存原理
    Javaconfig形式配置Dubbo多注册中心
    logback多环境配置
    Spring @Scheduled @Async联合实现调度任务(2017.11.28更新)
    Nginx的Access日志记录的时机
    Mysql索引引起的死锁
  • 原文地址:https://www.cnblogs.com/Khan-Sadas/p/10072214.html
Copyright © 2011-2022 走看看