简体   繁体   English

使用Queue的主线程协程<Action>

[英]Main thread coroutine using Queue<Action>

I am having a little trouble when i get some data from websockets and try to display it through coroutines. 当我从websockets获取一些数据并尝试通过协程显示数据时,我遇到了一些麻烦。

First, I have a classA attached to an object that opens the websocket and displays the data I receive: 首先,我将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));       
     }
}

But Unity complains with the next error: 但是Unity抱怨下一个错误:

StartCoroutine_Auto can only be called from the main thread. 只能从主线程调用StartCoroutine_Auto。 Constructors and field initializers will be executed from the loading thread when loading a scene. 加载场景时,将从加载线程执行构造函数和字段初始化程序。 Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function. 不要在构造函数或字段初始化程序中使用此函数,而应将初始化代码移至Awake或Start函数。

I searched in the unity forum and found this solution: 我在统一论坛中搜索,找到了以下解决方案:

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();
    }
  }
}

And it works! 而且有效! the problem is that even though I wrote the two classes in the same cs file and attached to an object, when I change the scene, return to that scene, and receive any data from the websocket, the next error is displayed: 问题是,即使我在同一个cs文件中编写了两个类并附加了一个对象,当我更改场景,返回该场景并从websocket接收任何数据时,仍显示下一个错误:

MissingReferenceException: The object of type 'ClassA' has been destroyed but you are still trying to access it. MissingReferenceException:类型'ClassA'的对象已被破坏,但您仍在尝试访问它。 Your script should either check if it is null or you should not destroy the object. 您的脚本应检查其是否为null或不破坏该对象。 UnityEngine.MonoBehaviour.StartCoroutine (IEnumerator routine) (at C:/BuildAgent/work/d63dfc6385190b60/artifacts/EditorGenerated/UnityEngineMonoBehaviour.cs:62) UnityEngine.MonoBehaviour.StartCoroutine(IEnumerator例程)(在C:/BuildAgent/work/d63dfc6385190b60/artifacts/EditorGenerated/UnityEngineMonoBehaviour.cs:62)

I tried not destroying the object when a new scene is loaded, as the documentation says: 如文档所述,我尝试在加载新场景时不破坏对象:

void Awake()
    {
        DontDestroyOnLoad(transform.gameObject);
    }

But the error still appears. 但是错误仍然出现。

The weird thing is that although there is an error, the data received from the websocket is displayed without any problem. 奇怪的是,尽管有错误,但是从websocket接收的数据显示没有问题。

Does someone know how to avoid this problem? 有人知道如何避免这个问题吗? Any way to trigger a coroutine inside the main thread without using a second class? 有什么方法可以在不使用第二类的情况下在主线程中触发协程? Or other solution to avoid this error? 还是其他解决方案来避免此错误?

Thanks! 谢谢!

I found the problem: 我发现了问题:

public readonly static Queue<Action> ExecuteOnMainThread = new Queue<Action>();

It is static, so it becomes a problem when a public class is instantiated and generates another ExecuteOnMainThread. 它是静态的,因此当实例化一个公共类并生成另一个ExecuteOnMainThread时,它将成为一个问题。

So just deleted "static" and made it destroy and generate itself every time ClassA is created by Unity. 因此,每次Unity创建ClassA时,只需删除“静态”并使其销毁并生成自身即可。

Now it works like a charm : ) 现在它就像一个魅力:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM