Imagine I'm in a Service that already has a background thread. Can I do a request using volley in that same thread, so that callbacks happen synchronously?
There are 2 reasons for this:
First, I do not need another thread and it would be a waste to create it.
Second, if I'm in a ServiceIntent, the execution of the thread will finish before the callback, and therefor I will have no response from Volley. I know I can create my own Service that has some thread with a runloop I can control, but it would be desirable having this functionality in volley.
It looks like it is possible with Volley's RequestFuture class. For example, to create a synchronous JSON HTTP GET request, you can do the following:
RequestFuture<JSONObject> future = RequestFuture.newFuture();
JsonObjectRequest request = new JsonObjectRequest(URL, new JSONObject(), future, future);
requestQueue.add(request);
try {
JSONObject response = future.get(); // this will block
} catch (InterruptedException e) {
// exception handling
} catch (ExecutionException e) {
// exception handling
}
Note #Matthews answer is correct BUT if you are on another thread and you do a volley call when you have no internet, your error callback will be called on the main thread, but the thread you are on will be blocked FOREVER. (Therefore if that thread is an IntentService, you will never be able to send another message to it and your service will be basically dead).
Use the version of get() that has a timeout future.get(30, TimeUnit.SECONDS) and catch the error to exit your thread.
To match #Mathews answer:
try {
return future.get(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// exception handling
} catch (ExecutionException e) {
// exception handling
} catch (TimeoutException e) {
// exception handling
}
Below I wrapped it in a method & use a different request:
/**
* Runs a blocking Volley request
*
* #param method get/put/post etc
* #param url endpoint
* #param errorListener handles errors
* #return the input stream result or exception: NOTE returns null once the onErrorResponse listener has been called
*/
public InputStream runInputStreamRequest(int method, String url, Response.ErrorListener errorListener) {
RequestFuture<InputStream> future = RequestFuture.newFuture();
InputStreamRequest request = new InputStreamRequest(method, url, future, errorListener);
getQueue().add(request);
try {
return future.get(REQUEST_TIMEOUT, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Log.e("Retrieve cards api call interrupted.", e);
errorListener.onErrorResponse(new VolleyError(e));
} catch (ExecutionException e) {
Log.e("Retrieve cards api call failed.", e);
errorListener.onErrorResponse(new VolleyError(e));
} catch (TimeoutException e) {
Log.e("Retrieve cards api call timed out.", e);
errorListener.onErrorResponse(new VolleyError(e));
}
return null;
}
It is probably recommended to use the Futures, but if for whatever reason you don't want to, instead of cooking your own synchronized blocking thing you should use a java.util.concurrent.CountDownLatch. So that would work like this..
//I'm running this in an instrumentation test, in real life you'd ofc obtain the context differently...
final Context context = InstrumentationRegistry.getTargetContext();
final RequestQueue queue = Volley.newRequestQueue(context);
final CountDownLatch countDownLatch = new CountDownLatch(1);
final Object[] responseHolder = new Object[1];
final StringRequest stringRequest = new StringRequest(Request.Method.GET, "http://google.com", new Response.Listener<String>() {
#Override
public void onResponse(String response) {
responseHolder[0] = response;
countDownLatch.countDown();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
responseHolder[0] = error;
countDownLatch.countDown();
}
});
queue.add(stringRequest);
try {
countDownLatch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (responseHolder[0] instanceof VolleyError) {
final VolleyError volleyError = (VolleyError) responseHolder[0];
//TODO: Handle error...
} else {
final String response = (String) responseHolder[0];
//TODO: Handle response...
}
Since people seemed to actually try to do this and ran into some trouble I decided I'd actually provide a "real life" working sample of this in use. Here it is https://github.com/timolehto/SynchronousVolleySample
Now even though the solution works, it has some limitations. Most importantly, you can't call it on the main UI thread. Volley does execute the requests on the background, but by default Volley uses the main Looper of the application to dispatch the responses. This causes a deadlock as the main UI thread is waiting for the response, but the Looper is waiting for onCreate to finish before processing the delivery. If you really really want to do this you could, instead of the static helper methods, instantiate your own RequestQueue passing it your own ExecutorDelivery tied to a Handler using a Looper which is tied to different thread from the main UI thread.
You achieve this with kotlin Coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7"
private suspend fun request(context: Context, link : String) : String{
return suspendCancellableCoroutine { continuation ->
val queue = Volley.newRequestQueue(context)
val stringRequest = StringRequest(Request.Method.GET, link,
{ response ->
continuation.resumeWith(Result.success(response))
},
{
continuation.cancel(Exception("Volley Error"))
})
queue.add(stringRequest)
}
}
And call with
CoroutineScope(Dispatchers.IO).launch {
val response = request(CONTEXT, "https://www.google.com")
withContext(Dispatchers.Main) {
Toast.makeText(CONTEXT, response,Toast.LENGTH_SHORT).show()
}
}
As a complementary observation to both #Blundells and #Mathews answers, I'm not sure any call is delivered to anything but the main thread by Volley.
The Source
Having a look at the RequestQueue implementation it seems the RequestQueue is using a NetworkDispatcher to execute the request and a ResponseDelivery to deliver the result (the ResponseDelivery is injected into the NetworkDispatcher). The ResponseDelivery is in turn created with a Handler spawn from the main thread (somewhere around line 112 in the RequestQueue implementation).
Somewhere about line 135 in the NetworkDispatcher implementation it seems like also successful results are delivered through the same ResponseDelivery as any errors. Again; a ResponseDelivery based on a Handler spawn from the main thread.
Rationale
For the use-case where a request is to be made from an IntentService it's fair to assume that the thread of the service should block until we have a response from Volley (to guarantee a living runtime scope to handle the result in).
Suggested solutions
One approach would be to override the default way a RequestQueue is created, where an alternative constructor is used instead, injecting a ResponseDelivery which spawns from the current thread rather than the main thread. I haven't investigated the implications of this, however.
I want to add something to Matthew's accepted answer. While RequestFuture might seem to make a synchronous call from the thread you created it, it does not. Instead, the call is executed on a background thread.
From what I understand after going through the library, requests in the RequestQueue are dispatched in its start() method:
public void start() {
....
mCacheDispatcher = new CacheDispatcher(...);
mCacheDispatcher.start();
....
NetworkDispatcher networkDispatcher = new NetworkDispatcher(...);
networkDispatcher.start();
....
}
Now both CacheDispatcher and NetworkDispatcher classes extend thread. So effectively a new worker thread is spawned for dequeuing the request queue and the response is returned to the success and error listeners implemented internally by RequestFuture.
Although your second purpose is attained but you first purpose is not since a new thread is always spawned, no matter from which thread you execute RequestFuture.
In short, true synchronous request is not possible with default Volley library. Correct me if I am wrong.
I use a lock to achieve that effect now im wondering if its correct my way
anyone want to comment ?
// as a field of the class where i wan't to do the synchronous `volley` call
Object mLock = new Object();
// need to have the error and success listeners notifyin
final boolean[] finished = {false};
Response.Listener<ArrayList<Integer>> responseListener = new Response.Listener<ArrayList<Integer>>() {
#Override
public void onResponse(ArrayList<Integer> response) {
synchronized (mLock) {
System.out.println();
finished[0] = true;
mLock.notify();
}
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
synchronized (mLock) {
System.out.println();
finished[0] = true;
System.out.println();
mLock.notify();
}
}
};
// after adding the Request to the volley queue
synchronized (mLock) {
try {
while(!finished[0]) {
mLock.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
You can do sync request with volley but you must call the method in different thread otherwise your running app will block, it should be like this :
public String syncCall(){
String URL = "http://192.168.1.35:8092/rest";
String response = new String();
RequestQueue requestQueue = Volley.newRequestQueue(this.getContext());
RequestFuture<JSONObject> future = RequestFuture.newFuture();
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, URL, new JSONObject(), future, future);
requestQueue.add(request);
try {
response = future.get().toString();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return response;
}
after that you can call the method in thread :
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
String response = syncCall();
}
});
thread.start();
Related
I've a webservice client that invokes several webservices with same wsdl on different endpoint, so I decided to make asynchronous calls in a parallel way.
I generated wsimport async jax-ws client and I decided to use a Future invocation with Async callback (using a single AsyncHandler instance for all the futures operation),
The question is: is there a way in the handleResponse(Response response) method to know to which of the future in the futures list the response is referred? Anything that can be done in the request context and propagate to reponse context?
Should I indeed preserve a state in the AsyncHandler and instatiate a new Handler foreach future operation and store the response in a shared list (maybe a thread safe class member)?
Is there a way to Propagate Request Context to the Response as in here?
[https://docs.oracle.com/middleware/1213/wls/WSGET/jax-ws-async-roadmap.htm#BABFAFHD][1]
Thanks all. My snippet:
WsSoapClient ws = new ....;
List<Future> futures = new ArrayList<>();
for (String url : urlList) {
BindingProvider bp = (BindingProvider) ws;
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, url);
Future invokeAsync = ws.getAsync("foo", mh);
futures.add(invokeAsync);
}
futures.stream().parallel().forEach((t) -> {
try {
t.get(15L, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
}
});
class MessageHandler implements AsyncHandler<String> {
private final List<String> responses;
public MessageHandler() {
List<String> rr = new ArrayList<>();
responses = Collections.synchronizedList(rr);
}
#Override
public void handleResponse(Response<String> response) {
try {
String get = response.get();
responses.add(get);
} catch (Exception e) {
e.printStackTrace();
}
}
public List<String> getResponses() {
return responses;
}
}
[1]: https://docs.oracle.com/middleware/1213/wls/WSGET/jax-ws-async-roadmap.htm#BABFAFHD
I ended up implementing a custom callback handler that mantains a state. One different instance for each future.
I've MyDataService which collects data by multiple GetSomeDataThread in parallel. Each GetSomeDataThread requests data synchronously via RequestFuture and StringRequest.
I got a timeout. I solved it by wrapping the request with another Thread and Runnable.
The timeout is gone, but I'm now getting the data asynchronously (see the comments in call()).
I found a lot of good answers on SO, but no duplicate.
Any ideas? Thanks in advance!
EDIT: To clarify the goal: result[0] should contain the content of future.get(), but it contains the default value "nothing". I probably need to wait for run() to finish, but don't know how.
EDIT 2: I can use a StringRequest (asynchronous) in call(), but not with future (synchronous). If I use StringRequest without wrapping it with another Thread, the app freezes and I'll get a timeout exception after a while (the URLs are fine).
public class MyDataService extends Service {
// ...
protected Summary summary;
protected void loadSummary() throws Exception {
Collection<GetSomeDataThread> threads = new ArrayList<>();
// loop
threads.add(new GetSomeDataThread("a"));
threads.add(new GetSomeDataThread("b"));
threads.add(new GetSomeDataThread("c"));
ExecutorService executorService = Executors.newFixedThreadPool(threads.size());
List<Future<JSONObject>> results = executorService.invokeAll(threads);
for (Future<JSONObject> result : results) {
// do something with the result:
// result.get()
}
executorService.shutdown();
}
}
-
public class GetSomeDataThread implements Callable<JSONObject> {
// ...
public GetSomeDataThread(String actionId) {
// ...
url += "&actionId=" + actionId;
}
#Override
public JSONObject call() throws Exception {
final String[] result = {"nothing"};
Thread t = new Thread(new Runnable() {
#Override
public void run() {
RequestFuture<String> future = RequestFuture.newFuture();
StringRequest request = new StringRequest(Request.Method.GET, url, future, future);
requestQueue.add(request);
result[0] = future.get();
Log.d(LOG_TAG, result[0]); // outputs the correct value, but delayed
Thread.currentThread().interrupt();
}
});
t.start();
// TODO: wait for thread + runnable to finish
// t.join(); just blocks
// result[0] equals "nothing"
return new JSONObject().put("result", result[0]);
}
}
I'm struggling with a network connection class I've created. The result of the Runnable I create returns a JSON object that contains all the information needed from the server. The thread runs, and receives the data perfectly, but of course, the program keeps running in the meantime, which results in a JSONException as being NULL.
I created a class called NetworkManager, which has the following method (jsonResponse is initialized at the beginning of the class)
JSONObject jsonResponse;
public void createNetworkThread(Context context, final String requestURI, final RequestBody formParameters) {
Runnable runnable = new Runnable() {
#Override
public void run() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(requestURI).post(formParameters).build();
Response response = null;
try {
response = client.newCall(request).execute();
String stringResponse = response.body().string();
NetworkManager.this.jsonResponse = new JSONObject(stringResponse);
// This works perfectly, "message" is received and printed to the log //
Log.d("Net", NetworkManager.this.jsonResponse.getString("message"));
} catch (IOException e) {
Log.d("Net", "Failed");
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
};
Thread thread = new Thread(runnable);
thread.start();
}
The above is called from the Activity, as:
Net.createNetworkThread(SignupActivity.this, requestURI, formVars);
JSONObject jsonResponse = Net.jsonResponse;
The JSON object jsonResponse is returning as NULL because the Thread is still accessing the server for the response.
I need to figure out how to stop the jsonResponse Object from being populated by Net.jsonResponse until the thread completes in order to stop it from returning NULL.
Any help?
I would only agree to the comments on your question and let you know, what you can do here.
If you are creating a thread just to get of the main UI thread to do the Network call you probably want to use OkHttp feature which allows you to get the Network call off the thread and provides you with callbacks to get the result something like this. you can check some example here
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
}
#Override
public void onResponse(Response response) throws IOException {
// this is the callback which tells you the network call was successful, If like to make some changes to UI, you should call `runOnUiThread`.
"YourClassName".this.runOnUiThread(new Runnable() {
#Override
public void run() {
}
});
}
});
or you can use AsyncTask which also gets your job done off the main UI thread and gives you the result in the callbacks.
private class MyTask extends AsyncTask<Void, Void, Void> {
//you can change the Type Void, Void, Void here to something which you want
//First Void belongs to doInBackground(Void... avoid)
//Second Void belongs to onProgressUpdate(Void... progress)
//Third Void belongs to onPostExecute(Void result)
// you may change these as you fit,
//when you want to start this class with your argument you can do something like this.
//new MyTask().execute("your argument to doInBackground");
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
// this is the method where you provide your implementation for doing a task off the main UI thread.
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
// in this callback you are back in the main UI thread to make changes to UI depending on your response
}
}
here is an example of AsyncTask
If you want to offload the main thread, you should consider that the parallel task could finish it's execution after, generally speaking, any amount of time. Sure, you can wait in the main thread for the child thread to finish (using 'join()'), though this is kind of questionable in terms of speed gain.
Anyway, answering your question:
I need to figure out how to stop the jsonResponse Object from being
populated by Net.jsonResponse until the thread completes in order to
stop it from returning NULL.
I suggest you change
public void createNetworkThread(...
to
public Thread createNetworkThread(...
{
...
Thread thread = new Thread(runnable);
thread.start();
return thread;
}
And consequently
Thread t = Net.createNetworkThread(SignupActivity.this, requestURI, formVars);
t.join(); // Wait until 't' finishes -- try-catch is omitted for the sake of demo.
JSONObject jsonResponse = Net.jsonResponse;
This, apparently, opens question of performance, since main thread will be effectively completely blocked by 't.join()' until the child thread will finish.
Answering the question in the topic: in Java 8 you can use lambda functional interface like this:
package multithreaded;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Multithreaded {
public static void main(String[] args) throws Exception {
Logger logger = LoggerFactory.getLogger("Main");
Worker<String, String> worker = new Worker<String, String>(
(String s) ->
{ // This is actual call-back code.
// It will be called by method 'apply' of interface 'Function' in the 'Worker'.
// It will accept String parameter and pass it in this block as variable 's'
logger.info("Embrace the beauty and power of Java 8! "+s); // yes, we can use local variables of the parent thread.
return "Call-Back "+s;
}
);
logger.info("Application starts new Worker.");
worker.start();
logger.info("Worker is running in background.");
Thread.currentThread().sleep(500); // Simulate some activity here...
logger.info("Result is unpredictable (could be null): "+worker.getResult());
// Wait here until worker is fully finished
worker.join();
logger.info("Result is predictable: "+worker.getResult());
}
}
Worker.java:
package multithreaded;
import java.util.function.Function;
public class Worker<T extends String, R extends String> extends Thread {
private final Function<T, R> callBack;
private volatile R result;
public Worker(Function<T, R> callBack)
{ this.callBack = callBack; }
#Override
public void run()
{
try{
int i = (int)(Math.random()*1000);
// simulate some activity unpredictable in terms of duration
Thread.currentThread().sleep(i);
// After "activity" is finished -- call the call-back function and get result in local variable.
// (Synchronization ommited for the sake of simplicity)
result = this.callBack.apply((T)("Result "+i)); // now let's call the call-back function and save the result in local variable.
}
catch(InterruptedException e)
{e.printStackTrace();}
}
// Getter for the local variable, populated by call-back function.
// (Synchronization ommited for the sake of simplicity)
public R getResult()
{ return this.result; }
}
Running above code multiple times, you will notice that from the parent thread's perspective the result is still unpredictable until the child thread is completely finished.
P.s. I suggest you re-think entire logic of data processing in your app and consider re-factoring towards entirely independent multi-threaded processing (perhaps using producer-consumer logic).
I am trying to get the Authentication Token from an account in Android before I make my request to the server. I Am trying to control the flow with a CountdownLatch so that it waits until:
a) A timeout (10s)
b) We get the token
private CountDownLatch tokenLatch = new CountDownLatch(1);
final long tokenTimeoutSeconds = 10;
AccountManager manager = AccountManager.get(mContext);
Account userAccount = getCurrentAccount();
// Get the auth token
if (userAccount != null) {
AccountManagerFuture<Bundle> future = manager.getAuthToken(userAccount, AccountUtility.AUTHTOKEN_TYPE_FULL_ACCESS, true, new AccountManagerCallback<Bundle>() {
#Override
public void run(AccountManagerFuture<Bundle> future) {
try {
Bundle bundle = future.getResult();
currentAuthToken = bundle.get(AccountManager.KEY_AUTHTOKEN).toString();
tokenLatch.countDown();
} catch (Exception e) {
Log.e(LOG_TAG, "Problem getting auth token!", e);
}
}
}, null);
try {
tokenLatch.await(tokenTimeoutSeconds, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Log.e(LOG_TAG, "Interupted while getting auth token!", e);
}
Context is passed:
mContext = ... getApplicationContext();
Right now it exits before either of those two cases. It does, however, always reach the AccountManagerCallback after all other processes are finished. Strange. I am most definitely doing something wrong.
Thanks for the helperooni!
This explanation presumes the posted code is running on the main thread. Because the Handler parameter in the call to getAuthToken() is null, the callback will also run on the main thread. This is a deadlock situation. After calling getAuthToken() the main thread blocks on the latch await(). The callback cannot run because the main thread is blocked. The latch never counts down to zero because the callback can't run.
The code posted at this blog offers an example of how an auth token can be obtained on the main thread without blocking.
I haven't used an AsyncTask before neither do I understand some tutorials regarding it so I really don't know how to apply it on a HttpClient execution. Please kindly help me on this kind of implementation here's the initial code made:
public void commandModule(String url) {
try {
HttpClient httpClient = new DefaultHttpClient();
httpClient.execute(new HttpGet(url));
} catch (Exception e) {
}
}
#Override
public void onClick(View v) {
if (checkBox1.isChecked()) {
commandModule("http://192.168.1.102/?command1");
} else {
commandModule("http://192.168.1.102/?command2");
}
if (checkBox2.isChecked()) {
commandModule("http://192.168.1.102/?command3");
} else {
commandModule("http://192.168.1.102/?command4");
}
}
If you know about Thread in java, it will be easy for you to understand the working of Async Task in android. Basically, you can not perform any long running task on the main thread in android. It will block the main main thread and you will get ANR (Applicaton not responding) error. To avoid this you can either use thread or Async task.
Thread has one limitation, you can not update UI thread form any other thread. So, to update the UI you need to send message to main/UI thread using handler. You will have to do this every time you are implementing something using thread.
To simplify, android framework provide Async Task.
So, what ever you should put in the run() method of Thread, should go in doInBackground() method.
public void commandModule(String url) {
new RequestTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,url);
}
private class RequestTask extends AsyncTask<String,Void,Void>{
protected void doInBackground(String... args){
String url=args[0];
try {
HttpClient httpClient = new DefaultHttpClient();
httpClient.execute(new HttpGet(url));
} catch (Exception e) {
}
}
}
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
check this tutorial it will give ideas about your queries http://programmerguru.com/android-tutorial/android-asynctask-example/
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
public void commandModule(String url) {
try {
new RequestTask().execute(url);
} catch (Exception e) {
}
}
#Override
public void onClick(View v) {
if (checkBox1.isChecked()) {
commandModule("http://192.168.1.102/?command1");
} else {
commandModule("http://192.168.1.102/?command2");
}
if (checkBox2.isChecked()) {
commandModule("http://192.168.1.102/?command3");
} else {
commandModule("http://192.168.1.102/?command4");
}
}
private class RequestTask extends AsyncTask<String,Void,Void>{
#Override
protected void onPreExecute() {
super.onPreExecute();
}
protected void doInBackground(String... args){
String url=args[0];
try {
HttpClient httpClient = new DefaultHttpClient();
httpClient.execute(new HttpGet(url));
} catch (Exception e) {
}
}
#Override
protected void onPostExecute() {
}
}
onPreExecute() – Executed when execute() method is called inside commandModule() (In short When AsyncTask is triggered).
doInBackground() – Executed when onPreExecute() completed executing. Al the long task are handled here
onPostExecute() – Background job is finished