Synchronize two concurrent network calls in AsyncTask
I’m trying to make multiple concurrent HTTP GET calls that may return a response after different times.
Once I have the data, I’ll use it to create a custom adapter for the ListView. Due to the high risk of NullPointerException, I need to make sure that all data exists before trying to create an adapter.
HTTP calls are currently done using AsyncTask, which is convenient for executing them in the background and later calling the UI thread to update the View. But they are not concurrent – each call is executed after the previous call completes.
The issue I’m grappling with is ensuring that all HTTP calls have returned a response before creating the adapter, while still maintaining concurrency.
Is there a way to run multiple concurrent network calls and have the onPostExecute method do what it does after all concurrent HTTP calls are complete?
Or do I need to use more complex threads, locks, etc.?
Solution
If you do not need the response for the HTTP call
A CountDownLatch
Tricks that might be done for you. You initialize it with a count and then call countDown(),
which returns immediately after each HTTP call. Regarding the onPostExecute
side, await
() block until countDown()
has been called count
.
So:
- Build a constructor for the number of HTTP calls
in CountDownLatch
andAsyncTask
- Call
latch.countDown()
after each HTTP call - The thread calls
onPostExecute
callslatch.await(),
which blocks until all of the above threads have completed their HTTP calls
If you do need a reply
The above method works (there is a prior relationship between each countDown
() and await()
return), but there is another way.
Wrap each HTTP call in Callable<Response>
and submit it ExecutorService
; It will immediately give you a Future<Response>
which you can then provide to the object that defines the onPostExecute
. The method can get the actual response via Response r = future.get(),
which will block until the specific callable function completes. If you do this for all HTTP calls, then after you call futureWhatever.get()
for each of those futures, you will make sure that the HTTP calls are complete.
One advantage of this approach is that onPostExecute
does not have to block until all HTTP calls have completed; It can make progress until the one it needs at the time is completed. For example, if it does:
Future callA = httpA.get();
processCallA(callA); this could take a while
Future callB = httpB.get();
...
… ProcessCallA
can then perform its operation even though the HTTP call B is completing as long as the HTTP call A has completed.