在 Unity 开发中,出现 UnityException: can only be called from the main thread 错误通常是因为某些 Unity API 被调用时不在主线程中。这篇博客将为你总结解决此问题的方法。
1. 问题背景
Unity 的 API 主要要求在主线程(也称为主游戏线程)中调用。get_isActiveAndEnabled 和其他 Unity 的 API(如 PlayerPrefs.GetInt、StartCoroutine 等)只能在主线程中使用。由于多线程环境中调用这些 API 可能导致异常,因此你会遇到这些错误。
2. 错误信息解释
错误信息中的 UnityException: get_isActiveAndEnabled can only be called from the main thread 表示你尝试从非主线程调用 get_isActiveAndEnabled,导致 Unity 抛出异常。构造函数和字段初始化器在加载场景时由加载线程执行,因此不能直接在这些位置调用 Unity 的 API。
3. 解决方案
要解决这个问题,可以采取以下几种方法:
3.1 将 Unity API 调用移到 Awake 或 Start 方法中
在 Unity 脚本中,将 Unity API 调用从构造函数或字段初始化器中移到 Awake 或 Start 方法中。这些方法会在主线程中执行。
示例代码:
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,将调用调度到主线程。
示例代码:
-
创建
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); } } } -
在其他线程中调用:
csharp 复制代码 UnityMainThreadDispatcher.Enqueue(() => { // 这部分代码将会在主线程中执行 });