【问题标题】:Unity3d with Firebase: Can't Start CoroutineUnity3d 与 Firebase:无法启动协程
【发布时间】:2020-09-15 12:11:37
【问题描述】:

问候,

我目前面临协程无法启动的问题。这是我第一次遇到这个问题,我在网上找不到合适的解决方案。如果有人能指出正确的方向来解决这个问题,我们将不胜感激。

这里是代码。

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

【问题讨论】:

  • 当你说“无法开始?”你到底是什么意思?当你尝试运行它时会发生什么?
  • 代码运行了,但是当它应该启动协程时,什么也没发生。
  • 是否给出了任何调试消息?
  • NO,即使在协程 "Debug.Log("Start Download");"甚至没有出现。
  • 看起来协程被正确调用,所以问题可能出在其他地方。 “不”是指甚至不是Debug.Log("Download URL: etc..?如果是这样,那么问题肯定出在其他地方。尝试将!task.IsFaulted &amp;&amp; !task.IsCanceled 更改为true

标签: firebase unity3d coroutine


【解决方案1】:

Firebase返回的任务可能在主线程以外的线程上执行完毕,Unity协程只能在主线程上运行。

Unity 对多线程和异步的支持参差不齐,包括“吃掉”一些错误,如果这些错误的延续将在主线程以外的另一个线程上执行。

要解决这个问题,您需要更改启动协程的函数:

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-world 而不是 coroutine-world(因为至少使用 async 我可以捕获错误,而不仅仅是“暂停并捕获” fire”就像 Unity 的协程一样)

主要有:

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,因为它们的 SetResult/SetException 调用是从 Unity 提供的协程延续中运行的。

【讨论】:

  • try { path_reference.GetDownloadUrlAsync().ContinueWith((Task&lt;Uri&gt; task) =&gt; { Debug.Log("Download URL: " + task.Result); // ... now download the file via WWW or UnityWebRequest. StartCoroutine(DownloadStuff(task.Result)); }); }catch (Exception ex) { Debug.LogException(ex); } 所以,我是这样做的吗? @Kroltan
  • 不,不要使用ContinueWith,因为这样您就无法更改ConfigureAwait。你必须用async标记你的外部方法,这样你就可以awaitGetDownloadUrlAsync返回的任务。
猜你喜欢
  • 2020-07-15
  • 1970-01-01
  • 2019-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-04
  • 1970-01-01
  • 2012-10-17
相关资源
最近更新 更多