Unity3d 实现 NotificationCenter

2012年时候还在做iOS,OC里有个NotifationCenter蛮好用的,之后做Coscos2d也有这个, 然Unity并没有这个,且Unity SendMessage的消息机制效率低下,而且inactive的物件收不到消息,还只能带一个参数,忒不好用。 C#的Action和委托倒是好,但是公司项目里用多播注册事件的地方,很多人忘记取消注册,导致各种bug,我心酸。心想还是自己写个NotificationCenter吧。

代码如下:

/*
  Author: Danny
  CreateDate: 2016-08-27 09:22:01
  Desc: Custom NotificationCenter
*/

using UnityEngine;
using System.Collections.Generic;
using System;
using System.Collections;

public class NotificationCenter
{
	public static NotificationCenter DefaultCenter
	{
		get
		{
			if (defaultCenter == null)
			{
				defaultCenter = new NotificationCenter();
			}
			return defaultCenter;
		}
	}

	private static NotificationCenter defaultCenter;

	private NotificationCenter()
	{
		notifications = new Hashtable();
	}

	private Hashtable notifications;

	public delegate void NotificationHandler0();

	public delegate void NotificatonHandlerN(params object[] args);

	public void AddObserver(object observer, string notification, NotificationHandler0 handler)
	{
		AddObserverFunc(observer, notification, handler);
	}

	public void AddObserver(object observer, string notification, NotificatonHandlerN handler)
	{
		AddObserverFunc(observer, notification, handler);
	}

	private void AddObserverFunc(object observer, string notification, object handler)
	{
		if (string.IsNullOrEmpty(notification))
		{
			Debug.Log("Null notification specified for notification in AddObserver.");
			return;
		}

		if (observer == null)
		{
			Debug.Log("Null observer specified for notification in AddObserver.");
			return;
		}

		if (notifications[notification] == null)
		{
			notifications[notification] = new Dictionary<object, object>();
		}

		var handlers = notifications[notification] as Dictionary<object, object>;
		if (!handlers.ContainsKey(observer))
		{
			handlers.Add(observer, handler);
		}
	}

	public void RemoveObserver(object observer, string notification)
	{
		if (notifications[notification] == null)
		{
			Debug.LogWarning("No need to remove notification not exist");
			return;
		}

		var handlers = notifications[notification] as Dictionary<object, object>;

		if (handlers != null)
		{
			if (handlers.ContainsKey(observer))
			{
				handlers.Remove(observer);
			}
		}

		if (handlers.Count == 0)
		{
			notifications.Remove(notification);
		}
	}

	private List<object> observersToRemove = new List<object>();

	public void PostNotification(string notification, params object[] args)
	{
		var handlers = notifications[notification] as Dictionary<object, object>;

		observersToRemove.Clear();

		if (handlers != null)
		{
			foreach (var handler in handlers)
			{
				if (handler.Key != null)
				{
					if (handler.Value != null)
					{
						if (handler.Value is NotificationHandler0)
						{
							(handler.Value as NotificationHandler0)();

							if (args.Length != 0)
							{
								Debug.LogWarning(string.Format("handler '{0}' receive useless paramter. 
                                                 notfication: {1}", handler.Value, notification));
							}

						}
						else
						{
							(handler.Value as NotificatonHandlerN)(args);
						}
					}
					else
					{
						Debug.LogError(string.Format("Opps! Receive notification '{0}', 
                                       but handler has been destroyed ", notification));
					}
				}
				else
				{
					Debug.LogError(string.Format("Opps! Receive notification '{0}', 
                                   but observer has been destroyed ", notification));
                                   
					observersToRemove.Add(handler.Key);
				}
			}
		}

		if (observersToRemove.Count > 0)
		{
			foreach (var o in observersToRemove)
			{
				handlers.Remove(o);
			}
		}
	}
}

接口:

public void AddObserver(object observer, string notification, NotificationHandler0 handler)
public void AddObserver(object observer, string notification, NotificatonHandlerN handler)
public void RemoveObserver(object observer, string notification)
public void PostNotification(string notification, params object[] args)

需要注意的是,observer的handler可以无参数或者有参数, handler在observer里声明的时候,如果有参数,形参类型必须是object[],用的时候做类型转换, 调用PostNotification()的时候需注意参数数目和顺序。

具体实例如下:

using UnityEngine;
using System.Collections;
public class TestView: MonoBehaviour
{
    void Start()
    {
        NotificationCenter.DefaultCenter.AddObserver(this, "HideTestViewNotify", HideUI);
        NotificationCenter.DefaultCenter.AddObserver(this, "ModelChangeNotify", RefreshUI);
    }

    void OnDestroy()
    {
        NotificationCenter.DefaultCenter.RemoveObserver(this, "HideTestViewNotify");
        NotificationCenter.DefaultCenter.RemoveObserver(this, "ModelChangeNotify");
    }

    void HideUI()
    {
        // to hdie ui
    }

    void RefreshUI(object[] data)
    {
        var model = data[0] as ModelDataStructure;

        // do more thing..
    }
}


public class ModelManager
{
    void OnModelDataChanged(ModelDataStructure data)
    {
        NotificationCenter.DefaultCenter.PostNotification("ModelChangeNotify", data);
    }

    void DoSomethingToHideUI()
    {
        NotificationCenter.DefaultCenter.PostNotification("HideTestViewNotify");
    }
}

public class ModelDataStructure
{

}

–EOF–

王小兵 /
Published under (CC) BY-NC-SA in categories Unity3d  tagged with Unity3d