Future and asynchronism

248 Views Asked by At

I use a extern api (ESRI API for Android) where I have a loop for which me return a class Future

...
for (Layer layer : layers) {

// ListenableFuture extends Future<V>
final ListenableFuture<FeatureQueryResult> future= gdbFeatureTable.queryFeaturesAsync(query);

future.addDoneListener(() -> {
                try {
                    FeatureQueryResult result = future.get();
...
}

OR

try {
                FeatureQueryResult result = future.get();


    }
    ...

Is it possible to launch all queryFeaturesAsync and obtain the global result (result1 + result2 + etc..) with asynchronously after the loop for ? What's the best way ? promises? ThreadPoolExecutor ?

Thanks for your help

2

There are 2 best solutions below

5
On BEST ANSWER

I think method queryFeaturesAsync() inside already uses ThreadPoolService, and using ThreadPoolService to retreive result from another ThreadPoolService is overkill, IMHO.

I would recomend you to use AsyncTask becuse it is native Android SDK tool and very simple to use:

AsyncTask<ListenableFuture<FeatureQueryResult>, Integer, List<FeatureQueryResult>> task =
        new AsyncTask<ListenableFuture<FeatureQueryResult>, Integer, List<FeatureQueryResult>>() {
    @Override
    protected List<FeatureQueryResult> doInBackground(ListenableFuture<FeatureQueryResult>[] futures) {
        int counter = 0;
        List<FeatureQueryResult> results = new ArrayList<>();
        for (ListenableFuture<FeatureQueryResult> future : futures) {
            try {
                results.add(future.get());
                publishProgress(++counter); // Optional feature
            } catch (ExecutionException | InterruptedException e) {
                Log.w("Huh?", "Interrupted!");
            }
        }
        return results;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        notifyMainThreadAboutProgress(values[0]); // Optional feature
    }

    @Override
    protected void onPostExecute(List<FeatureQueryResult> featureQueryResults) {
        doSomethingWithResultsInMainThread(featureQueryResults);
    }
};

ListenableFuture<FeatureQueryResult> future1 = gdbFeatureTable.queryFeaturesAsync(query);
ListenableFuture<FeatureQueryResult> future2 = gdbFeatureTable.queryFeaturesAsync(another_query);
ListenableFuture<FeatureQueryResult> future3 = gdbFeatureTable.queryFeaturesAsync(yet_another_query);

task.execute(future1, future2, future3);

I made AsyncTask as an anonymous class for shortening of example. On production it must be static class.

1
On

If I use CompletableFuture is it the best way ? I don't understand all ...

List<CompletableFuture<FeatureQueryResult>> futures = new ArrayList<>();                
for (Layer layer : layers) {
    FeatureTable gdbFeatureTable = ((FeatureLayer) layer).getFeatureTable();
    CompletableFuture<FeatureQueryResult>  completableFuture = new CompletableFuture<>();
    ListenableFuture<FeatureQueryResult> future = gdbFeatureTable.queryFeaturesAsync(query);
    future.addDoneListener(() -> {
                        FeatureQueryResult result = future.get();
                        completableFuture.complete(result);
    }
    futures.add(future);
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));

Do you have a another solution with completablefuture ?

Thanks for your reponse