Search code examples
javaandroidmultithreadingandroid-volley

How do I wait for another response listener to complete in android volley?


Is it possible to synchronise two volley requests so that one listener will always be executed after the other, regardless of the order their requests return in?

I am making two calls to an external (owned/run by others) API, where the first call provides some data and the second adds some necessary information. However, I cannot add the information from the second response before processing the first one (an example would be to consider that request 1 returns text, and request 2 is a list of words that should be bold).

The approaches I have tried so far are to share an AtomicBoolean between my two listeners, where the first one does its processing and runs complete.set(true). The second listener also has the same AtomicBoolean and does the following to wait:

while (!complete.get()) {
    try {
        Thread.sleep(50);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

The other approach I have already attempted is to use a semaphore to achieve the same - a semaphore with one permit, which is pre-acquired before sending the requests. The first listener releases this permit, while the second waits to acquire it.

Both approaches fail when the second request returns before the first, and my swipe-to-refresh view just freezes up. I would prefer not to resort to making the second request from the onResponse for the first one, as the API is quite slow - doing the requests synchronously will double the time to display all information.

I also considered taking the first response as a RequestFuture and passing this into the second request's listener. Then using RequestFuture.get() to wait for the result, but I cannot find a way to attach my first response callback to the future to run on completion - I can't inherit from RequestFuture as the super constructor is private.

Thanks.


Solution

  • With some further debugging, I found that the issue is that Volley runs the onResponse method on the main thread. So when my second request completes before the first one, it would wait on the main thread and the onResponse for the first listener would never run - this meant the wait on the second listener would never stop, freezing the app.

    I was able to get around this by doing the same thing as before, but calling both onResponse methods in their own threads using runnables. E.g.

    public void onResponse(final JSONObject response) {
        Runnable actualRunnable = new Runnable() {
            public void run() {
                oldOnResponse(response);
            }
        };
    
        (new Thread(actualRunnable)).start();
    }
    

    If you are going to use this approach and need the responses to affect the UI at all, note that you need to pass your activity into your response and call any code that references views on the UI thread using:

    activity.runOnUiThread(new Runnable() {
        public void run() {
            // This code changes the UI
        }
    });