赞
踩
最近在做资源更新时,需要显示现在的进度调。我在Unity中开启了一个线程来做下载任务,然后实时刷新下载进度。然后Unity报了一个错误。
get_isActiveAndEnabled can only be called from the main thread.
意思是Unity中的组件只能运行在Unity的主线程中,无法在新开的线程中调用Unity的组件。
用Loom实现多线程与主线程交互
using UnityEngine; using System.Collections; using System.Collections.Generic; using System; using System.Threading; using System.Linq; public class Loom :MonoBehaviour { public static int maxThreads = 8; static int numThreads; private static Loom _current; //private int _count; public static Loom Current { get { Initialize(); return _current; } } //用于初始化一次,在程序入口调用一次 public void StartUp() {} static bool initialized; public static void Initialize() { if (!initialized) { if (!Application.isPlaying) return; initialized = true; var g = new GameObject("Loom"); _current = g.AddComponent<Loom>(); #if !ARTIST_BUILD UnityEngine.Object.DontDestroyOnLoad(g); #endif } } public struct NoDelayedQueueItem { public Action<object> action; public object param; } private List<NoDelayedQueueItem> _actions = new List<NoDelayedQueueItem>(); public struct DelayedQueueItem { public float time; public Action<object> action; public object param; } private List<DelayedQueueItem> _delayed = new List<DelayedQueueItem>(); List<DelayedQueueItem> _currentDelayed = new List<DelayedQueueItem>(); public static void QueueOnMainThread(Action<object> taction, object tparam) { QueueOnMainThread(taction, tparam, 0f); } public static void QueueOnMainThread(Action<object> taction, object tparam, float time) { if (time != 0) { lock (Current._delayed) { Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = taction, param = tparam }); } } else { lock (Current._actions) { Current._actions.Add(new NoDelayedQueueItem { action = taction, param = tparam }); } } } public static Thread RunAsync(Action a) { Initialize(); while (numThreads >= maxThreads) { Thread.Sleep(100); } Interlocked.Increment(ref numThreads); ThreadPool.QueueUserWorkItem(RunAction, a); return null; } private static void RunAction(object action) { try { ((Action)action)(); } catch { } finally { Interlocked.Decrement(ref numThreads); } } void OnDisable() { if (_current == this) { _current = null; } } // Use this for initialization void Start() { } List<NoDelayedQueueItem> _currentActions = new List<NoDelayedQueueItem>(); // Update is called once per frame void Update() { if (_actions.Count > 0) { lock (_actions) { _currentActions.Clear(); _currentActions.AddRange(_actions); _actions.Clear(); } for (int i = 0; i < _currentActions.Count; i++) { _currentActions[i].action(_currentActions[i].param); } } if (_delayed.Count > 0) { lock (_delayed) { _currentDelayed.Clear(); _currentDelayed.AddRange(_delayed.Where(d => d.time <= Time.time)); for (int i = 0; i < _currentDelayed.Count; i++) { _delayed.Remove(_currentDelayed[i]); } } for (int i = 0; i < _currentDelayed.Count; i++) { _currentDelayed[i].action(_currentDelayed[i].param); } } } }
未使用Loom报错方法
public Text mText;
void Start ()
{
Thread thread = new Thread(RefreshText);
thread.Start();
}
void Update ()
{
}
private void RefreshText()
{
mText.text = "Hello Loom!";
}
更改后
using UnityEngine; using System.Collections; using UnityEngine.UI; using System.Threading; public class testLoom : MonoBehaviour { public Text mText; void Start () { Loom.Current.StartUp(); // 用Loom的方法调用一个线程 Loom.RunAsync( () => { Thread thread = new Thread(RefreshText); thread.Start(); } ); } void Update () { } private void RefreshText() { // 用Loom的方法在Unity主线程中调用Text组件 Loom.QueueOnMainThread((param) => { mText.text = "Hello Loom!"; },null); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。