20

这些天我正在学习如何使用 Google Volley。快速联网非常方便。似乎所有请求都在 Volley 的后台运行。例如:

volleyRequestQueue.add(new JsonObjectRequest(Method.POST, SIGNUP_URL, reqBody, new SignUpResponseListener(), new MyErrorListener()));

使用上面的代码,我们可以进行一个后台运行的 POST 调用(非阻塞方式)。现在我的问题是:是否可以以阻塞方式进行 POST 调用?为什么我需要一种阻塞方式来进行 REST 调用?因为有些调用,比如登录,应该在做其他事情之前完成。

谢谢

4

5 回答 5

31

Volley 支持通过 RequestFutures 阻塞请求。您创建一个普通请求,但将其回调设置为您的请求未来,这只是 volley 对标准 java 期货的扩展。对 future.get() 的调用将被阻塞。

它看起来像这样

RequestFuture<JSONObject> future = RequestFuture.newFuture();
JsonObjectRequest request = new JsonObjectRequest(Method.POST, SIGNUP_URL, reqBody, future, future)
volleyRequestQueue.add(request);

try {
    JSONObject response = future.get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
于 2013-08-30T21:36:15.470 回答
4

这是一个更清晰的答案,可以InterruptedException正确处理以及超时。请注意,您唯一想要吞下中断并继续的情况是您特别打算使用中断来取消对请求的响应。

RequestFuture<JSONObject> future = RequestFuture.newFuture();
JsonObjectRequest request = new JsonObjectRequest(Method.POST, SIGNUP_URL, reqBody, future, future);
volleyRequestQueue.add(request);

try {
    JSONObject response = null;
    while (response == null) {
        try {
            response = future.get(30, TimeUnit.SECONDS); // Block thread, waiting for response, timeout after 30 seconds
        } catch (InterruptedException e) {
            // Received interrupt signal, but still don't have response
            // Restore thread's interrupted status to use higher up on the call stack
            Thread.currentThread().interrupt();
            // Continue waiting for response (unless you specifically intend to use the interrupt to cancel your request)
        }
    }
    // Do something with response, i.e.
    new SignUpResponseListener().onResponse(response);
} catch (ExecutionException e) {
    // Do something with error, i.e.
    new MyErrorListener().onErrorResponse(new VolleyError(e));
} catch (TimeoutException e) {
    // Do something with timeout, i.e.
    new MyErrorListener().onErrorResponse(new VolleyError(e));
}
于 2015-05-02T01:23:18.370 回答
1

如果您想在 Volley 请求之后执行某些操作,请使用回调侦听器 onSuccess(在这种情况下为 SignUpResponseListener)并将代码放在那里。这是最佳实践。

于 2013-07-14T03:10:20.647 回答
1

我无法让 RequestFuture 工作,所以我只使用了 Makibo 建议的回调监听器。我不知道他为什么被否决,这可能是解决不同 Volley 请求的原始常见问题的最佳解决方案,这些请求都取决于初始登录或其他内容。在这个例子中,我想上传一张照片,但首先我要检查用户是否登录。如果没有,我必须登录,然后在上传照片之前等待成功。如果已经登录,直接上传照片。

这是我的示例代码:

// interface we'll use for listener
public interface OnLoginListener {
    public void onLogin();
}

public void uploadPhoto(final String username, final String password, final String photo_location) {
    // first setup callback listener that will be called if/when user is logged in
    OnLoginListener onLoginListener=new OnLoginListener() {
        @Override
        public void onLogin() {
            uploadPhotoLoggedIn(photo_location);
        }
    };
    // simplistic already logged in check for this example, just checking if username is null
    if (loggedInUsername==null) {
        // if it null, login and pass listener
        httpLogin(username, password, onLoginListener);
    } else {
        // if not null, already logged in so just call listener method
        onLoginListener.onLogin();
    }
}

public void httpLogin(String username, String password, final OnLoginListener onLoginListener) {
    StringRequest loginRequest = new StringRequest(Request.Method.POST, "https://www.example.com/login.php", new Response.Listener<String>() { 
        @Override
        public void onResponse(String txtResponse) {
            Log.d("STACKOVERFLOW",txtResponse);
            // call method of listener after login is successful. so uploadPhotoLoggedIn will be called now
            onLoginListener.onLogin();
        } }, 
        new Response.ErrorListener() 
        {
            @Override
            public void onErrorResponse(VolleyError error) {
                // TODO Auto-generated method stub
                Log.d("VOLLEYERROR","error => "+error.toString());
            }
        }
            ) {
    };    
    // Just getting the Volley request queue from my application class (GetApplicatio.java), and adding request
    GetApplication.getRequestQueue().add(loginRequest);
}
于 2014-12-15T01:17:18.537 回答
1

我想在加布里埃尔的回答中添加一些内容。虽然RequestFuture阻塞了调用它的线程并服务于您的目的,但网络请求本身并未在该线程中执行。相反,它是在后台线程上执行的。

根据我在浏览库后的理解,RequestQueue在它的方法中发送请求start()

    public void start() {
        ....
        mCacheDispatcher = new CacheDispatcher(...);
        mCacheDispatcher.start();
        ....
           NetworkDispatcher networkDispatcher = new NetworkDispatcher(...);
           networkDispatcher.start();
        ....
    }

现在CacheDispatcherNetworkDispatcher类都扩展了线程。因此,有效地产生了一个新的工作线程来使请求队列出队,并将响应返回给内部实现的成功和错误侦听器RequestFuture

所以我认为创建一个单独的阻塞线程来使用没有意义RequestFuture。相反,正如 Makibo 在他的回答中提到的那样 - “使用回调监听器 onSuccess (在这种情况下为 SignUpResponseListener )并将代码放在那里。”

于 2016-12-17T06:26:44.867 回答