ToLua SimpleFramework NGUI/UGUI基础知识[3]
原文地址:http://doc.ulua.org/default.asp?cateID=4
视频地址:http://pan.baidu.com/s/1gd8fG4N
昨天,痛骂完PMVC多么的操蛋,到了晚上,就遇到一个项目里面的问题,突然觉得接口无关性与PMVC的消息“无主”性比起来吧,还是PMVC更加科学、合理一些。至少简洁明了,不用拖泥带水的。
既然,首次觉得PMVC有好处,那么我们继续讲,关于昨天最后提供给大家一个“门面”facade,以及搭载它的顺风车的管理器们,
有一个问题,如果在普通的Unity对象上面,GameObject上面如何获得这些支持咧?其实 很简单,我们往常给一个类集成的时候都用Unity自带的MonoBehaviour,那现在用框架提供的,继承自BehaviourBase类即可,它本来也集成自MonoBehaviour,里面包装了所有管理器的获取、维护等操作。所有的子类都可以直接调用不同管理器,或者收发PMVC的消息。
其实这一次的改版,除了PMVC的集成引入外,还有个非常重要的变动,就是引入了另一个管理器“线程管理器”,引入它的目的在于真正的开发过程中,难免都需要做很多分包操作,你可以参考里面的实现,将一些费时操作交给线程去完成,完成后再通过PMVC通知主线程,完成一次echo,主线程就避免卡顿的用户体验。今天我们主要说下线程管理器跟更新系统的协同操作。
说线程类之前,首先说下,怎么传递消息给线程?当GameManager类中OnUpdateResource的时候,里面有个BeginDownload函数,是它启动了ThreadManager.AddEvent(ev, OnThreadCompleted); //线程下载。
线程管理器的代码并不多,短短150行而已,里面演示较多的无非是下载相关的代码,当主线程通过下面函数:
/// <summary>
///添加到事件队列
/// </summary>
public void AddEvent(ThreadEvent ev, Action<NotiData> func) {
lock (m_lockObj) {
this.func = func;
events.Enqueue(ev);
}
}
将事件传递给线程,记得加锁,我用消息队列保存了所有的事件请求,然后在每一此OnUpdate中,解析每一个消息,根据请求的类型做“解包”、“下载”操作,将来你可以增添自己的操作类型。我们这里主要就是下载文件OnDownloadFile,解析完里面的下载URL,就开始启动异步下载DownloadFileAsync。因为是异步的,所以每一次的下载更新操作都在ProgressChanged完成,比如更新下载进度等。
那在更新函数里面,我拿到一个更新的下载进度,如何传递给主线程,并且让它做出刷新界面操作呢?这里用到了delegate,封装了一个通知数据类实例:NotiData data = new NotiData(NotiConst.Update_PROGRESS, value); 里面是关于更新进度的操作,以及一些数据通过m_SyncEvent回调给主线程,其实当进入m_SyncEvent的时候,CPU已经身处主线程了,那就好说了嘛,
既然线程管理器也集成自BehaviourBase,那我直接获取父类的facade的成员变量,并且发送消息出去,关于谁接收?这里不关心。但是我们还是要找到接收的地方,怎么找?看到前面的NotiConst.Update_PROGRESS了嘛,查找它的引用地方在哪儿?发现监听此消息的是AppMediator,这是PMVC的V层了,主要处理V层的逻辑的,那通过它:
case NotiConst.Update_PROGRESS: //更新下载进度
view.UpdateProgress(body.ToString());
break;
通知View更新界面,也就完成了最后的操作,到达最后终点了。
当下载的这个文件完成以后,再次调用m_SyncEvent,这次传递的消息不是更新进度,而是更新完成消息:NotiConst.Update_DOWNLOAD。再通过事先AddEvent传进来的、保存到“完成事件回调函数”:func,回调给GameManager,它接收到知道线程完成当前操作,在回调函数OnThreadCompleted里面,将下载完成的文件名添加到下载队列中,然后更新协同开始接着请求下载下一个文件,直到下载全部完成为止。
当所有的操作都完成后,这个线程不会主动退出,而是一直等着主线程“交代”任务进来,这就是线程与下载的完整流程。
借楼层更新-----------------------------------------------------------------------------------------
今天周五,睡觉前再更新一篇帖子,这回咱们聊下在PMVC下的Socket跟NetworkManager如何交互细节。还记得前面的帖子有个地方记录了:在BootstrapCommands类注册了一个SocketCommand的地方吗?不记得自己翻去。里面添加了一条新消息Facade.RegisterCommand(NotiConst.DISPATCH_MESSAGE, typeof(SocketCommand));为了Socket消息做准备,下面呢,就是注册了一大堆的管理器。
直接打开SocketCommand.cs文件,看看有啥?哦~~这不是原来NetworkManager里面Update函数里面的事件检测函数么?是的,就是从它复制来的,也就是说,当从NetworkManager接收到消息后,它一定会把消息通过facade发送出去,而且没有指定谁来接收,然后这里会接收,并且处理消息派发给Lua的网络管理器:Network组件进行再次分发。为啥?还用问,它不关心接受者,自然也就解耦了,解除了原来的强引用。
为了确定猜想,我们打开NetworkManager.cs文件,果不其然的代码如下:
/// <summary>
/// 交给Command,这里不想关心发给谁。
/// </summary>
void Update() {
if (sEvents.Count > 0) {
while (sEvents.Count > 0) {
KeyValuePair<int, ByteBuffer> _event = sEvents.Dequeue();
facade.SendNotification(NotiConst.DISPATCH_MESSAGE, _event);
}
}
}
其他的代码都是原来的,没什么可讲的,尽管如此,但是里面有个变量却不得不重点看下,就是下面的
SocketProxy SocketClient {
get {
if (socket == null) {
socket = facade.RetrieveProxy(SocketProxy.NAME) as SocketProxy;
}
return socket;
}
}
这个是新的框架才具备,这是虾米东东?其实就是原来框架的SocketClient.cs类,这里是我忘了在哪里看到的,把它当作的Moudule层的代理类。距离网络底层最近的地方,由他来接收网络数据,并且通过添加静态队列AddEvent()将消息传递给NetworkManager,它在通过PMVC的解耦消息发送出去,被SocketCommand类监听截获到之后,再次分发给C#还是LUA的Network组件,以便再次分发给Lua的模块。这就是这一块的思路流程。好不好,自做评判吧。