'Why is future.get() always timing out for Volley RequestFuture?
I am trying to make a synchronous Volley networking request. I am using request futures to wait on a response, but the future.get()
call always times out (no matter how long the timeout is set to). I have tested every component individually and nothing seems to be causing the error other than my use of futures. Any ideas on what I've don wrong here?
Activity.java: persistData()
postCampaign(campaign);
Activity.java: postCampaign()
private boolean postCampaign(final Campaign c) {
RequestFuture<String> future = RequestFuture.newFuture();
StringRequest request = new StringRequest(Request.Method.POST, url, future, future) {
@Override
protected Map<String, String> getParams()
{
Map<String, String> params = new HashMap<>();
// put data
return params;
}
};
NetworkController.getInstance(this).addToRequestQueue(request);
try {
String response = future.get(5, TimeUnit.SECONDS);
Log.d("Volley", "" + response);
return !response.contains("Duplicate");
} catch (InterruptedException|ExecutionException|TimeoutException e) {
Log.d("Volley", "[FAILED] " + e.getClass());
return false;
}
}
Strangely enough though, when stepping through the code, it appears that the RequestFuture's onResponse
method is invoked with the appropriate response. So it seems like the RequestFuture just isn't handling the response properly.
Solution 1:[1]
I think I've come to the conclusion that either Volley is not capable of fully synchronous networking requests or at the very least it isn't worth it. I ended up just showed a spinner on start and stopped it in the Volley request's onResponse
method when the server responded with a success message. As far as the user is concerned it works the same way.
Solution 2:[2]
I think I've come to the conclusion that either Volley is not capable of fully synchronous networking requests or at the very least it isn't worth it.
Not exactly. You can do it but it's not in the manner that we're used to when doing synchronous network calls.
There are a couple of things you need to remember when trying to do a synchronous request in volley:
- The synchronous request needs to run in another thread. This is almost obvious anyway especially in recent versions of Android it will not allow you to do network calls in the main thread.
- Once you launch that request in another thread you cannot block on that thread to wait for it to finish or the
future.get(...)
call fails.
so in the above example you can simply use an executor like this:
val campaign = ...
val executor = Executors.newSingleThreadExecutor()
val f = executor.execute {
postCampaign(campaign)
}
in that same strategy you CANNOT wait on the future f
to complete by doing this:
f.get() // this blocks thread; your volley requests will timeout and you will be sad
now, you're probably asking: How do i update UI depending on the result of future.get()
if i can't wait for it to finish? it's simple: the magic of closure variable capture you can still use the result of future.get()
and be able to update your UI but you do that on the main thread...with coroutines this is rather easy:
val response = future.get(5, TimeUnit.SECONDS);
Log.d("Volley", "" + response);
CoroutineScope(Dispatchers.Main).launch {
// you can do whatever UI updates here based on the value of result
binding.textView.text = result
}
You can also use View::post
but it has a bit more boilerplate and less elegant/flexible than coroutines (IMO).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Caleb Whittington |
Solution 2 | Dexter Legaspi |