Избранное Все заметки Главная

Unity API из другого потока (can only be called from the main thread)

Наверняка многие из вас пытались вызывать методы из api юньки или обращаться к объектам из другого потока.
Если ещё не пробывали — попробуйте, компилятор заорёт примерно такой ошибкой — can only be called from the main thread
Вообщем-то погуглив я понял,что не я один с этим встречался,поэтому на будущее оставлю решение здесь,может кому пригодится. Совет нашел на SO,но ссылку привести не смогу,утерял.

Условие простое, хотим работать с unity api — проворачиваем свои делишки только в главном потоке,иначе никак.
Поскольку метод Update крутится в главном потоке,проверку будем производить там. Поехали...
Итак, допустим я в дополнительном потоке получаю сообщения от сервера. Мне необходимо каждое сообщение добавлять в Text UI. Если попытаюсь из дополнительного потока поработать с UI,то получу ошибку,исправляется следующим образом:

Для начала объявим в нашем скрипте очередь из делегатов и некоторые промежуточные переменные

private Queue<Action> mainThread = new Queue<Action>(); 
private string data = null;

Теперь для примера напишем метод,который будет взаимодействовать с UI.

private void OnWriteMessageChat()
    {
        if (data != null)
        {
            chatfield.text += data + "\n";
            data = null;
        }
    }

А это пускай будет тот самый метод,который принимает от сервера сообщения :

private void Communication()
                        {
data = "msg from server";
// бла бла , допустим мы уже получили сообщение от сервера и храним её в переменной data ,которую изначально объявили в теле класса.

                                mainThread.Enqueue(new Action(OnWriteMessageChat));
                                Debug.Log("Делегат добавлен в очередь");

                            }

У mainThread есть метод Enqueue,которые добавляет наши делегаты в очередь.
Остается только достать из очереди делегат и вызвать Invoke(). Для этого пригодится Update (я уже упоминал его в начале,не забыли?)

private void Update()
    {
        if(mainThread.Count > 0)
        {
            mainThread.Dequeue().Invoke();
        }

    }

Вот и всё,статья получилось довольно сжатой,но, думаю , смысл понятен.

Поделиться
Отправить
1 комментарий
Fk

Если есть интерес посмотри в сторону новой job system в 2018.1 Там можно работать с движком из любого потока, но есть ограничения

Аристотель Младший

Спасибо за комментарий!Слышал о job system,очень порадовало,статья скорее для тех,кто до сих пор на стареньких версиях сидит или кому лень переносить проект ( для таких как я ).