Unity3d与Firebase。无法启动Coroutine

问题描述 投票:1回答:1

问候。

我现在面临一个问题,我的coroutine无法启动。这是我第一次面临这个问题,我在网上找不到合适的解决方案。如果有谁能给我指出解决这个问题的正确方向,我将非常感激。

下面是代码。

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);
    }
}'
firebase unity3d coroutine
1个回答
0
投票

Firebase返回的任务可能是在主线程以外的线程上完成执行的,而Unity的coroutine只能在主线程上运行。

Unity对多线程和异步的支持非常不到位,包括 "吃掉 "一些错误,如果这些错误的延续会在主线程以外的另一个线程上执行。

要解决这个问题,你需要改变启动你的coroutine的函数。

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);
}

顺便说一下,我通常在我所有的项目中都有一些扩展方法来处理这个问题,而不是呆在async世界而不是coroutine世界(因为至少在async中我可以捕捉到错误,而不是像Unity的coroutine那样 "停止并着火")。

主要的是。

public static Task ToTask(this YieldInstruction self, MonoBehaviour owner) {
    var source = new TaskCompletionSource<object>();

    IEnumerable Routine() {
        yield return self;
        source.SetResult(null);
    }

    return source.Task;
}

private static Task SendAsync(this UnityWebRequest self, MonoBehaviour owner) {
    var source = new TaskCompletionSource<object>();

    await self.SendWebRequest().ToTask(owner);

    if (
        self.isHttpError
        || self.isNetworkError
    ) {
        source.SetException(new Exception(request.error));
        yield break;
    }

    source.SetResult(null);
}

你可以这样使用,在一个 MonoBehaviour:

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

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

注意,这些方法不需要 ConfigureAwait由于他们的 SetResultSetException 调用是由Unity提供的coroutine延续运行的。

© www.soinside.com 2019 - 2024. All rights reserved.