Unity3d с Firebase: не удается запустить Coroutine - PullRequest
1 голос
/ 28 мая 2020

Приветствие,

Сейчас я столкнулся с проблемой, из-за которой моя сопрограмма не может запуститься. Я впервые сталкиваюсь с этой проблемой и не могу найти подходящее решение в Интернете. Очень признателен, если кто-нибудь может указать мне правильное направление для решения этой проблемы.

Вот код.

path_reference.GetDownloadUrlAsync().ContinueWith((Task<Uri> task) => {

if (!task.IsFaulted && !task.IsCanceled)
            {
                Debug.Log("Download URL: " + task.Result);

                StartCoroutine(DownloadStuff(task.Result));
            }
            else
            {
                Debug.Log(task.Exception.ToString());
            }
        });
    }
IEnumerator DownloadStuff(Uri uri)
{
    Debug.Log("Start Download");

    using (var www = UnityWebRequestTexture.GetTexture(uri))
    {
        yield return www.SendWebRequest();

        if (www.isNetworkError || www.isHttpError)
        {
            Debug.Log(www.error);
        }
        else
        {
            var texture = DownloadHandlerTexture.GetContent(www);

            //Texture2D texture = new Texture2D(1, 1);

            //if you need sprite for SpriteRenderer or Image
            Sprite sprite = Sprite.Create(texture, new Rect(0.0f, 0.0f, texture.width,
                    texture.height), new Vector2(0.5f, 0.5f), 100.0f);
            Debug.Log("Finished downloading!");
        }

        Debug.Log(www.downloadProgress);
    }
}'

1 Ответ

0 голосов
/ 28 мая 2020

Задача, возвращаемая Firebase, вероятно, завершает выполнение в потоке, отличном от основного, а сопрограммы Unity могут работать только в основном потоке.

Поддержка Unity многопоточности и асинхронности c довольно нестабильна, включая "съедание" некоторых ошибок, если продолжение этих ошибок будет выполняться в другом потоке, отличном от основного.

Чтобы исправить это, вам нужно изменить функцию, запускающую вашу сопрограмму:

try {
    // Important: ConfigureAwait(true) ensures the code after this will run in the
    // same thread as the code before (which is the main thread!)
    var url = await path_reference.GetDownloadUrlAsync().ConfigureAwait(true);
    StartCoroutine(DownloadStuff(url));
} catch (Exception ex) {
    // Tip: when logging errors, use LogException and pass the whole exception,
    // that way you will get pretty links to the error line in the whole stack trace.
    Debug.LogException(ex);
}

Кстати, у меня обычно есть несколько методов расширения для всех моих проектов, чтобы справиться с этим, оставаясь в asyn c -world вместо coroutine-world (потому что, по крайней мере, с asyn c я могу поймать ошибки, а не просто «остановиться и загореться», как сопрограммы Unity) *

await new WaitForSeconds(0.2f).ToTask(this);

UnityWebRequest request = /* etc */;
await request.SendAsync(this);
var texture = DownloadHandlerTexture.GetContent(request);

Обратите внимание, что эти методы не требуют ConfigureAwait, поскольку их вызовы SetResult / SetException выполняются из продолжений сопрограмм, предоставляемых Unity.

...