Android - Volley RequestFuture 超时问题

5

在使用Volley的RequestFuture类时,我遇到了一个问题。实际上,在下面的RequestFuture类中的doGet()函数中的wait(0)处停止运行,并且没有被onResponseonErrorResponse唤醒,我认为它应该被唤醒。

private synchronized T doGet(Long timeoutMs)
        throws InterruptedException, ExecutionException, TimeoutException {
    if (mException != null) {
        throw new ExecutionException(mException);
    }

    if (mResultReceived) {
        return mResult;
    }

    if (timeoutMs == null) {
        wait(0);
    } else if (timeoutMs > 0) {
        wait(timeoutMs);
    }

    if (mException != null) {
        throw new ExecutionException(mException);
    }

    if (!mResultReceived) {
        throw new TimeoutException();
    }

    return mResult;
}

@Override
public boolean isCancelled() {
    if (mRequest == null) {
        return false;
    }
    return mRequest.isCanceled();
}

@Override
public synchronized boolean isDone() {
    return mResultReceived || mException != null || isCancelled();
}

@Override
public synchronized void onResponse(T response) {
    mResultReceived = true;
    mResult = response;
    notifyAll();
}

@Override
public synchronized void onErrorResponse(VolleyError error) {
    mException = error;
    notifyAll();
}

这是我尝试调用上述所有内容的方式。
    RequestFuture<JSONObject> future = RequestFuture.newFuture();
    JsonObjectRequest myReq = new JsonObjectRequest(Request.Method.POST, url, jsonObj, future, future);
    requestQueue.add(myReq);

    try {

        JSONObject response = future.get();
    } catch (InterruptedException e) {
        // handle the error
    } catch (ExecutionException e) {
        // handle the error
    }

我也尝试替换这行代码:
requestQueue.add(myReq);
为以下两种方式之一,但都没有帮助:
future.setRequest(requestQueue.add(myReq));
或者
future.setRequest(myReq);
我已经尝试使用通常的Volley请求,使用这些参数可以正常工作,因此不应该是原因。我猜问题在于请求实际上从未被执行,这就是为什么响应监听器永远不会被触发的原因。我还尝试了requestQueue.start(),但没有任何变化。
希望我已经足够清楚地解释了我的问题, 提前感谢您!

你为什么要使用RequestFuture?你能分享一下你的使用场景吗? - bogdan
我遇到的问题是,我有三个请求,其中最后一个请求依赖于前两个请求的响应。我已经尝试使用不同的RequestQueues,但它总是在实际开始请求之前构建所有请求。因此,我从未能够存储前两个请求的值,以便在最后一个请求中使用它们。我目前的解决方法是使用自定义事件监听器来响应每个请求的响应,并在前一个请求完成后启动新的请求。 - user2700475
但是您已经为Volley请求设置了2个监听器:成功监听器和错误监听器。您可以在成功监听器中获取结果(并根据需要在错误监听器中设置一些自定义值),然后从那里启动您的后续请求 - 成功和/或错误监听器。这样,您的请求是同步的,而且您不必费心实现RequestFuture。 - bogdan
好的,我会使用它们。我本来认为使用RequestFuture会是更好/更干净的方法,但似乎它并没有正常工作。非常感谢! - user2700475
1
我希望有人能够回答这个问题。我也遇到了同样的问题。唉。 - nachoburton
1
请参考@Blundell对类似问题的回答 - John Cummings
4个回答

6

给get方法添加超时时间将使得能够捕获错误,如果没有设置超时时间,则会将错误发送回主线程。因此,将 JSONObject response = future.get(); 更改为 JSONObject response = future.get(REQUEST_TIMEOUT, TimeUnit.SECONDS); 可以解决问题,并在超时时使用try catch包装。


3

问题解决!

JSONObject response = future.get();

始终在单独的线程中运行Future请求。它将无法在主线程中工作。我正在IntentService中运行Future请求调用,它完美地工作。

愉快的编码 :)


0

你需要在另一个线程中调用future.get()。尝试将其包装在AsyncTask中。

从源代码来看,RequestQueue启动了一长串调用以加载响应,并最终以RequestFuture.onResponse结束(后者又调用notifyAll通知线程停止等待,正如你所提到的)。我认为问题在于wait(0)RequestQueue链都在UI线程中运行,因此当调用wait(0)时,RequestQueue链也会等待,因此onResponse永远不会被调用,这就是为什么那行代码会一直挂起(因为wait(0)会永远等待)。


0
除了 Blair 和 Farhan 的解决方案之外,将重试策略附加到请求中也可以完成任务。
request.setRetryPolicy(new DefaultRetryPolicy(RETRY_TIME, RETRY_ATTEMPTS, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接