Reputation: 143
I am currently porting a networking library written in Objective-C to Java, and I need the functionality to make asynchronous HTTP requests to a server, without relying on any third-party libraries (so, no Apache dependencies). I am using HTTPUrlConnection
to do this; however, as you know it is a synchronous process.
I am trying to implement concurrency into this process using the ExecutorService
and Future<>
structures. I need to use Callable
instead of Runnable
, because I need to process the response message the server sends back to me. Here is a small overview of what I am doing:
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<String> future = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return postRequest(reqMsg);
}
});
where reqMsg is the request message (in XML), and the postRequest method returns the response message as a String (also in XML). Now, in order to retrieve the return value of this Callable task, I need to use future.get()
. However, this method is a blocking call, meaning it blocks the main thread until a response is available. This is not what I want.
I am porting an iOS application to Android, and I am going to be using J2ObjC to have a cross-platform shared library between these platforms. In the iOS version (meaning the Obj-C version of the library), there are completion handlers that handle the results from HTTP request, and it is made asynchronously. Java, unfortunately, introduced this callback way of handling it in Java 8, with CompletableFuture. However, Android only supports CompletableFuture starting with API level 24. I want to be able to support API levels going back to Jelly Bean (API 16). And as far as I know, "for a JAR file to be compatible with Android, it can only reference classes available as part of Android and other classes implemented specifically in the JAR itself". You might suggest using AsyncTasks; however, I want to handle the concurrency of HTTP requests on the Java networking side, as this library will most likely be shared across two platforms.
I have tried using Threads explicitly; however, as I researched it, I found out that in order to use Callables, you need to use ExecutorService and Future (plus, there seems to be some performance overheads related to creating Threads explicitly - though I think an overhead of < 1000ms is acceptable). And again, just to reiterate (i.e. TL:DR):
I don't want to rely on third party libraries, unless it's ABSOLUTELY necessary.
I cannot use CompletableFuture
, as I want my minimum API level to be 16.
I don't want to handle this concurrency on the Android side with AsyncTasks
, as originally, this is handled in the networking library with a CompletionHandler
(Objective-C).
Is there a way to use Future.get()
without blocking? (A kind reminder that a while loop checking Future.isDone()
also blocks the main thread).
Upvotes: 2
Views: 2811
Reputation: 551
Calling Future.get()
is a blocking operation and you cannot change that.
What you want here is to get a callback once the job is done. For this you do not have to use a Future
at all. You can always use Executor.execute()
with a Runnable
doing exactly the same thing as your Callable
but instead of returning a value it should call a custom - provided in the method parameter - callback with the value. Basically an equivalent of Consumer
interface that was introduced in Java 8.
ExecutorService executorService = Executors.newSingleThreadExecutor();
public void execute(YourRequestObject reqMsg, Consumer<String> consumer) {
executorService.execute(new Runnable() {
@Override
public void run() {
String result = postRequest(reqMsg);
consumer.accept(result);
}
});
}
Also don't create executor each time. Just use one executor for all your operations. Perhaps a cached one instead of singleThread one.
Remember that your callback will be called on the executor thread. If you want to update the UI you need to make a post on UI handler.
Upvotes: 2
Reputation: 5948
You question does not make much sense. On one hand you want to fetch data in separate thread but at the same time get it in another thread without waiting the fetch thread to complete.
What you need to do is wrap fetch and "do whatever with the fetched data" into Runnable and run it in a separate thread.
Make sure to update UI in event dispatch thread in case you need to update it with the fetched data.
Upvotes: 0