由于线程原因,实例化无法工作

本文关键字:实例化 工作 于线程 线程 | 更新日期: 2023-09-27 18:07:30

我收到以下错误

" internal_call_internal_instantiatessingle只能从主线程调用。"当加载场景时,构造函数和字段初始化函数将从加载线程执行。"不要在构造函数或字段初始化器中使用此函数,而是将初始化代码移动到Awake或Start函数中。"

每当我尝试使用这个函数实例化一些GameObject's时:

public void DisplayCalls () {
    for (int i = 0; i < calls [0].Count; i++) {
        for (int j = 0; j < impFields.Length; j++) {
            GameObject textClone = Instantiate (textBox, Vector3.zero, Quaternion.Euler(Vector3.zero)) as GameObject;
            textClone.transform.SetParent (canvas.transform);
            Text text = textClone.GetComponent <Text> ();
            text.text = calls[impFields [j]][i];
            text.alignment = TextAnchor.MiddleCenter;
            textClone.transform.localPosition = new Vector3 (-262.5f + (175f * j), (182f + (30f * i)), 0f);
        }
    }
}

这个函数是通过另一个函数调用的:

public void GetPanelInfo () {
    string file = "getpanelinfo.php";
    string hash = Md5Sum (mostRecentID.ToString () + SecretKey1 + SecretKey2);
    string parameters = "?mostrecentid=" + mostRecentID.ToString () + "&hash=" + hash;
    string fullURL = baseURL + file + parameters;
    Uri fullURI = new Uri (fullURL);
    WebClient client = new WebClient ();
    string jsonString = string.Empty;
    client.DownloadStringCompleted += (sender, e) => {
        if (!e.Cancelled && e.Error == null) {
            jsonString = e.Result;
            JSONNode json = JSON.Parse (jsonString);
            for (int i = 0; i < json["calls"].Count; i++) {
                for (int j = 0; j < calls.Length; j++) {
                    calls[j].Add (json["calls"][i][names [j]]);
                }
                mostRecentID = json["calls"][i]["callID"].AsInt;
            }
        } else if (e.Cancelled && e.Error == null) {
            Debug.Log ("Cancelled");
        } else {
            Debug.Log ("Error: " + e.Error);
        }
        loading = false;
        LogCalls ();
        DisplayCalls ();
    };
    client.DownloadStringAsync (fullURI);
}

使用按钮调用一次。

我似乎找不到问题,但如上所述,错误说这是一个线程问题,我不能从主线程以外的另一个线程调用instantiate。我不知道如何将实例化更改为另一个线程,但任何帮助解决这个问题将非常感激。

由于线程原因,实例化无法工作

你可以尝试使用UnityEvent来通知主线程事件。代码看起来像下面这样:

using UnityEngine.Events;
public class YourClass : MonoBehaviour
{
    private UnityEvent m_MyEvent = new UnityEvent();
    void Start()
    {
        m_MyEvent.AddListener(DisplayCalls);
    }
    public void GetPanelInfo () {
        ...
        // instead of this : 
        // DisplayCalls (); 
        // do this:
        m_MyEvent.Invoke();
    }
}

摘自我在游戏开发交流会上提出的相同问题。


查看WebClient文档,该方法描述为:

从资源下载string,不阻塞调用线程。

并给出错误信息:

INTERNAL_CALL_Internal_InstantiateSingle只能从主线程调用

很明显,您需要下载数据并存储它,并且在下载完成后仅在主线程中调用DisplayCells。这与Cocoa不同,例如,你只能在主线程上调用与ui相关的API方法。

我花了一些时间在谷歌上寻找有关这方面的合适信息(我是Unity/c#的初学者),但我认为这个可以做到:

创建一个布尔值,表示有数据要显示:

private bool _callsToDisplay = false;

数据下载完成后设置:

client.DownloadStringCompleted += (sender, e) => {
    ...
    loading = false;
    LogCalls ();
    _callsToDisplay = true;
};

,然后在Update()方法(运行在主线程上)中,如果设置了该布尔值,则调用DisplayCalls():

void Update()
{
    if (_callsToDisplay) {
        DisplayCalls();
        _callsToDisplay = false;
    }
}