【问题标题】:Unity - Waiting for HTTP request to resolveUnity - 等待 HTTP 请求解析
【发布时间】:2017-11-24 17:28:45
【问题描述】:

这里是函数,不知道有没有更简洁的写法:

private static WWW WaitUntilResolved (WWW request)
{
    bool success = true;
    float timeout = 5000, timer = 0;

    while (!request.isDone) {
        if (timer > timeout) {
            success = false;
            break;
        }
        timer += Time.deltaTime;
    }

    if (success && request.error == null)
        return request;
    else {
        request.Dispose ();
        return null;
    }
}

ps。 WWW 是原生统一类:https://docs.unity3d.com/ScriptReference/WWW.html

【问题讨论】:

  • 您的代码在轮询循环中阻塞。这是非常不可取的。您是否有理由不能使用非阻塞异步 HttpClient 类?
  • 我对Unity不太熟悉,WWW是Unity中的类还是别的什么?
  • 另外,请在上下文中发布您的代码。什么代码调用WaitUntilResolved?你有多个线程吗?
  • Unity 在他们的教程中有这个。您应该使用枚举器。 docs.unity3d.com/Manual/…

标签: c# unity3d


【解决方案1】:

您确实使用了WWWisDone 错误。如果你必须使用isDone,你必须把它放在while循环中。您还必须使用yield return null; 在while 循环中让步,否则游戏将冻结直到下载完成。整个事情都需要coroutine,所以这个函数必须是一个协程函数。

你真的不需要isDone。这在您想知道下载进度时使用。

这是使用isDone的正确方法:

private static IEnumerator WaitUntilResolved(WWW request)
{
    while (!request.isDone)
    {
        Debug.Log("Download Stat: " + request.progress);

        //Wait each frame in each loop OR Unity would freeze
        yield return null;
    }

    if (string.IsNullOrEmpty(request.error))
    {
        //Success
    }
}

如果您不需要知道下载进度,那么您应该使用以下内容:

private static IEnumerator WaitUntilResolved(WWW request)
{
    yield return request;
    if (string.IsNullOrEmpty(request.error))
    {
        //Success
    }
}

最后,你不能直接调用协程函数。你必须使用StartCoroutine 函数来做到这一点:

WWW www = new WWW("www.yahoo.com");
StartCoroutine(WaitUntilResolved(www));

编辑:

如何设置协程的超时时间?

大多数WebRequest 教程使用计时器。您无需在 Unity 中使用 WWW API 执行此操作。这里没有必要,因为这是一个非阻塞操作。如果您必须查看下面的代码。

private static IEnumerator WaitUntilResolved(WWW request)
{
    float timeout = 5000, timer = 0;

    while (!request.isDone)
    {
        Debug.Log("Download Stat: " + request.progress);

        timer += Time.deltaTime;
        if (timer >= timeout)
        {
            Debug.Log("Timeout happened");
            //Break out of the loop
            yield break;
        }
        //Wait each frame in each loop OR Unity would freeze
        yield return null;
    }

    if (string.IsNullOrEmpty(request.error))
    {
        //Success
    }
}

如果您需要返回下载状态,请参阅 this 帖子,其中说明了如何执行此操作。

【讨论】:

  • 如何设置协程的超时时间?
  • @Ja.L 你不需要需要超时。仅当 WWW 不是异步时才需要它。有关更多信息,请参阅编辑后的答案。
  • 如果我将返回类型设置为 IEnumerator 那么我不能再返回 WWW 对象?
  • 没有。不是直接的,因为它必须是IEnumerator。尽管我在答案末尾提供了一个链接,该链接显示了如何以Action 作为参数返回一个值。您可以添加Action 作为额外参数。我链接的示例从带有Action<bool> reqStat 的协程返回bool,但您可以使它返回带有Action<WWW> reqStatWWW。我会留给你做的。
  • 我应该在超时/错误时调用 WWW.dispose() 还是没有必要?
【解决方案2】:

这是一个等待异步调用的例子。

string WebGet()
{
    Response result = new Response();
    IEnumerator e = GetStuff(result);

    // blocks here until UnityWebRequest() completes
    while (e.MoveNext());

    Debug.Log(result.result);
}

public class Response
{
    public string result = "";
}

IEnumerator GetStuff(Response res)
{
    UnityWebRequest www = UnityWebRequest.Get("http://some.add.com/");

    yield return www.SendWebRequest();

    while (!www.isDone)
        yield return true;

    if (www.isNetworkError || www.isHttpError)
        res.result = www.error;
    else
        res.result = www.downloadHandler.text;
}

【讨论】:

  • 我试过这个但给了uncaught exception: abort("Cannot enlarge memory arrays...
猜你喜欢
  • 1970-01-01
  • 2017-07-30
  • 2019-01-08
  • 2018-11-13
  • 1970-01-01
  • 2011-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多