Unity3d UI线程与其它线程之间的交互
2020-02-02 本文已影响0人
王广帅
在使用Unity3d开发游戏的时候,UI相关的操作只能在主线程(main)中操作,在别的线程中无法直接操作UI。在游戏开发的过程中,有些阻塞的操作是不能直接在主线程中实现的,因为它需要的时间可能会很长,所以一般都是放到一个新的线程中实现的。比如网络请求和响应线程,比如资源异步加载线程,热更新线程等,这就会出现的UI线程与网络线程的交互,及UI线程与其它线程间的交互。
在.net中,有一个类专门实现了跨线程的数据交互,比如在网络线程中,收到服务器的返回消息时,需要回调UI的更新线程,大部分都昌使用队列进行数据交互,现在可以通过使用SynchronizationContext
直接调用UI的回调方法。
- 获取UI线程的
SynchronizationContext
的实例
在UI线程调用异步方法时,可以在UI线程中直接使用
SynchronizationContext.Current
获取当前UI线程的SynchronizationContext 实例。
- 调用回调方法
在SynchronizationContext类中有两个方法,一个是Send方法,一个是Post方法。
- Send() 是简单的在当前线程上去调用委托来实现(同步调用)。也就是在子线程上直接调用UI线程执行,等UI线程执行完成后子线程才继续执行。
- Post() 是在线程池上去调用委托来实现(异步调用)。这是子线程会从线程池中找一个线程去调UI线程,子线程不等待UI线程的完成而直接执行自己下面的代码。
所以在使用异步方法的时候,需要把SynchronizationContext的实例传过去,在调用UI回调方法时,使用Send方法调用,如下面代码所示:
public void ConnectServer(Action<SocketStateEnum> callback)
{
//异步执行socket的连接
networkStatusExecutor.Execute(() =>
{
try
{
Debug.Log("开始连接服务器:" + host + ":" + port);
clientSocket.ConnectServer();
Debug.Log("连接服务器成功:" + host + ":" + port);
//使用UI线程的SynchronizationContext实例调UI的回调
uiContext.Send((state) =>
{
Debug.Log("连接成功之后回调线程:" + Thread.CurrentThread.ManagedThreadId);
callback.Invoke(SocketStateEnum.ConnectSuccess);
}, null);
//启动异步接收数据
receiveExecutor.Execute(() =>
{
messageReader.ReadData((byteBuf) =>
{
serverMessageDispatch.DispatchMessage(byteBuf);
});
});
}
catch (Exception e)
{
uiContext.Send((state) =>
{
callback.Invoke(SocketStateEnum.ConnectFailed);
}, null);
Debug.Log("网络连接失败,请检测网络," + e);
}
});
}
这个是一个异步连接socket的代码,在连接成功之后,可能会更新一些UI上面的展示,所以使用UI的SynchronizationContext调用回调方法。
![](https://img.haomeiwen.com/i3793531/2cd80c02aceec6fd.jpg)