Unity:UnityException: can only be called from the main thread

887 阅读1分钟

在 Unity 开发中,出现 UnityException: can only be called from the main thread 错误通常是因为某些 Unity API 被调用时不在主线程中。这篇博客将为你总结解决此问题的方法。

1. 问题背景

Unity 的 API 主要要求在主线程(也称为主游戏线程)中调用。get_isActiveAndEnabled 和其他 Unity 的 API(如 PlayerPrefs.GetIntStartCoroutine 等)只能在主线程中使用。由于多线程环境中调用这些 API 可能导致异常,因此你会遇到这些错误。

2. 错误信息解释

错误信息中的 UnityException: get_isActiveAndEnabled can only be called from the main thread 表示你尝试从非主线程调用 get_isActiveAndEnabled,导致 Unity 抛出异常。构造函数和字段初始化器在加载场景时由加载线程执行,因此不能直接在这些位置调用 Unity 的 API。

3. 解决方案

要解决这个问题,可以采取以下几种方法:

3.1 将 Unity API 调用移到 AwakeStart 方法中

在 Unity 脚本中,将 Unity API 调用从构造函数或字段初始化器中移到 AwakeStart 方法中。这些方法会在主线程中执行。

示例代码

csharp
复制代码
public class MyComponent : MonoBehaviour
{
    void Awake()
    {
        // Safe to call Unity API here
        if (gameObject.activeAndEnabled)
        {
            // Perform actions that need the gameObject to be active and enabled
        }
    }
}

3.2 使用 Unity 主线程调度工具

如果你需要从其他线程(如后台线程)访问 Unity API,可以使用主线程调度工具,如 UnityMainThreadDispatcher,将调用调度到主线程。

示例代码

  1. 创建 UnityMainThreadDispatcher 脚本

       using System;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class UnityMainThreadDispatcher : MonoBehaviour
    {
            private static readonly Queue<Action> _executionQueue = newQueue<Action>();
    
    public void Update()
    {
        while (_executionQueue.Count > 0)
        {
            _executionQueue.Dequeue().Invoke();
        }
    }
    
    public static void Enqueue(Action action)
    {
        lock (_executionQueue)
        {
            _executionQueue.Enqueue(action);
        }
    }
    }
    
    
  2. 在其他线程中调用

    csharp
    复制代码
       UnityMainThreadDispatcher.Enqueue(() =>
                    {
                    // 这部分代码将会在主线程中执行
    
                    });