【发布时间】:2014-12-16 09:30:46
【问题描述】:
当我从 websockets 获取一些数据并尝试通过协程显示它时,我遇到了一些麻烦。
首先,我有一个 classA 附加到一个打开 websocket 并显示我收到的数据的对象:
public class ClassA : MonoBehaviour {
...
public IEnumerator ConnectWebSocket(url)
{
// in the websocket class, start the websocket connection, which
// will return data through a callback inside the return string
WebSocketClass.WebSocketStart(url, delegate(string result)
{
// receive websocket data and call the functions that displays it
WebSocketData(result);
});
// wait for the socket connection
while (WebSocketClass.WebSocketGetState() == WebSocketSharp.WebSocketState.CONNECTING)
{
yield return 0;
}
if (WebSocketClass.WebSocketGetState() == WebSocketSharp.WebSocketState.OPEN)
{
break;
}
...
}
// function that gets websocket data and starts couroutine to display it
public void WebSocketData(string data)
{
StartCoroutine(DisplayMessage(data));
}
}
但 Unity 抱怨下一个错误:
StartCoroutine_Auto 只能被调用 从主线程。构造函数和 字段初始化器将被执行 加载时从加载线程 场景。请勿在 构造函数或字段初始值设定项, 而是将初始化代码移动到 唤醒或启动功能。
我在unity论坛搜索,找到了这个解决方案:
public class ClassA : MonoBehaviour {
...
public IEnumerator ConnectWebSocket(url)
{
// in the websocket class, start the websocket connection, which
// will return data through a callback inside the return string
WebSocketClass.WebSocketStart(url, delegate(string result)
{
// receive websocket data and call the functions that displays it
WebSocketData(result);
});
// wait for the socket connection
while (WebSocketClass.WebSocketGetState() == WebSocketSharp.WebSocketState.CONNECTING)
{
yield return 0;
}
if (WebSocketClass.WebSocketGetState() == WebSocketSharp.WebSocketState.OPEN)
{
break;
}
...
}
// function that gets websocket data and starts couroutine to display it
public void WebSocketData(string data)
{
DoOnMainThread.ExecuteOnMainThread.Enqueue(() => { StartCoroutine(DisplayMessage(data)); });
}
}
// class to manage the websocket data display inside the main thread
public class DoOnMainThread : MonoBehaviour
{
public readonly static Queue<Action> ExecuteOnMainThread = new Queue<Action>();
public virtual void Update()
{
// dispatch stuff on main thread
while (ExecuteOnMainThread.Count > 0)
{
ExecuteOnMainThread.Dequeue().Invoke();
}
}
}
而且它有效!问题是即使我在同一个cs文件中编写了两个类并附加到一个对象,当我改变场景,返回那个场景,并从websocket接收任何数据时,会显示下一个错误:
MissingReferenceException:对象 'ClassA' 类型的已被销毁 但您仍在尝试访问它。 您的脚本应该检查它是否 为空,否则您不应销毁 目的。 UnityEngine.MonoBehaviour.StartCoroutine (IEnumerator 例程)(在 C:/BuildAgent/work/d63dfc6385190b60/artifacts/EditorGenerated/UnityEngineMonoBehaviour.cs:62)
如文档所述,我尝试在加载新场景时不破坏对象:
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
但错误仍然出现。
奇怪的是,虽然有错误,但是从websocket接收到的数据显示没有任何问题。
有人知道如何避免这个问题吗?有什么方法可以在不使用第二个类的情况下触发主线程内的协程?或其他解决方案来避免此错误?
谢谢!
【问题讨论】:
-
对
ExecuteOnMainThread的访问应该在lock部分中(使用ExecuteOnMainThread 作为保护)。
标签: c# multithreading unity3d websocket coroutine