I'm using an API that makes calls for results, but doesn't return the result itself. Once the call is made, a separate method (a listener) is invoked, which contains the result. Here's an example of what I'm trying to achieve:
public static void main (String[] args) {
Object obj = someMethod();
System.out.println("The object is" + obj + ", wooh!");
}
public void callObject() {
// This is the call that sends a request for the object
}
public void receiveObject(Object object) {
// This is the API method that is invoked with the result (cannot be changed)
}
// What I want to be able to do
public Object someMethod() {
callObject();
// return received object once received, but how?
}
The callObject() doesn't return an object, only initiates the retrieval of it. I want to have a method that calls for the object, then returns it when it has been received. I've been looking into Callables and Future results, but I'm not sure how to implement them.
Any idea? Thanks!
Simplest case: you send your request in an ordinary blocking way and want to be able to do something on the main thread while it's being performed. For that, use ExecutorService
, usually created by a call to Executors
, e.g.:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class ToyConc1 {
public static void main(String[] args) throws InterruptedException,
ExecutionException {
ExecutorService exec = Executors.newCachedThreadPool();
try {
Callable<String> op1 = new Callable<String>() {
@Override
public String call() throws Exception {
return slowlyGetHttpPage("http://www.google.com");
}
};
Callable<String> op2 = new Callable<String>() {
@Override
public String call() throws Exception {
return slowlyGetHttpPage("http://edition.cnn.com/");
}
};
Future<String> resF1 = exec.submit(op1);
Future<String> resF2 = exec.submit(op2);
for (int i = 0; i < 20; i++) {
System.out.println("doing useful work on the main thread...");
}
System.out.println("The object 1 is " + limit(resF1.get(), 1000) + ", wooh!");
System.out.println("The object 2 is " + limit(resF2.get(), 1000) + ", wooh!");
} finally {
exec.shutdown();
exec.awaitTermination(60, TimeUnit.SECONDS);
}
}
private static String slowlyGetHttpPage(String urlName) throws InterruptedException,
IOException {
Thread.sleep(2000);
URL url = new URL(urlName);
URLConnection conn = url.openConnection();
InputStream in = conn.getInputStream();
InputStreamReader reader = new InputStreamReader(in); // wrong charset maybe
BufferedReader br = new BufferedReader(reader);
StringBuilder sb = new StringBuilder();
try {
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return sb.toString();
} finally {
br.close();
}
}
private static String limit(String s, int length) {
if (s == null) {
return null;
}
if (s.length() <= length) {
return s;
}
return s.substring(0, length) + " [and " + (s.length() - length) + " more]";
}
}
Alternatively, the library/framework/technique that you use for sending the request and returning the result might already give you something like a Future
or accept something like a callback (e.g. AsyncHttpClient does both).