In Java threads, you could have some number of threads in a list, start them off, and have a main thread join
one, then another, going through and waiting for all processes to complete before moving on.
In other models, I'm not sure how you would do that. Take the RootTools 3.0 Command class for example. You create a Command
which has three methods, commandOutput
, commandFinished
, commandTerminated
, and while you can use a callback to do something at the end of a process, I don't know how you would wait for multiple processes (For example, going through listing of several directories and summing the file-sizes).
I believe the Android Asynctask would have a similar problem - you can easily make a callback, but there is no way to wait for several tasks. Unless I'm missing something?
##Introduction
I had gone through this topic for one of my previous project and found different solutions to the problem .I finally used the first method for the project because it was the best suited one for that specific project.
Let ImageDownloader
be a class to download an image from a URL asynchronously and it has the following properties.
ImageDownloadCallback
to get the callback when the task is completed. It has two methodsvoid onSuccess(String imagePath)
: called when the task is completed successfully.void onFailure()
: called when the task is failed to complete.download(String url, ImageDownloadCallback callback)
to start the download taskPauseModeCallbackHandler
, ChainModeCallbackHandler
and ParallelModeCallbackHandler
are wrapper classes of the callbacks for the three methods respectively. You can customize them according to what task you want to do.
##Method 1: Execute the tasks one by one by pausing the starter thread.
Pros
Gets the results in the original thread
Cons
Need to make the thread waiting
import java.util.concurrent.atomic.AtomicReference;
/**
* @author Ahamad Anees P.A
* @version 1.0
* @param <T> type
*/
public class ThreadLockedTask<T> {
private AtomicReference<ResultWrapper<T>> mReference;
public ThreadLockedTask() {
mReference = new AtomicReference<>(new ResultWrapper<T>());
}
public T execute(Runnable runnable) {
runnable.run();
if (!mReference.get().mIsSet)
lockUntilSet();
return mReference.get().mResult;
}
private void lockUntilSet() {
synchronized (this) {
while (!mReference.get().isSet()) {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public void setResult(T result) {
synchronized (this) {
ResultWrapper<T> wrapper = mReference.get();
wrapper.setResult(result);
wrapper.setIsSet(true);
notify();
}
}
public static class ResultWrapper<T> {
private boolean mIsSet;
private T mResult;
public boolean isSet() {
return mIsSet;
}
public T getResult() {
return mResult;
}
void setIsSet(boolean isCompleted) {
this.mIsSet = isCompleted;
}
void setResult(T result) {
this.mResult = result;
}
}
}
###Sample
import java.util.ArrayList;
import java.util.List;
public class PauseModeCallbackHandler {
// List of results
private static List<String> results;
public static void start(final List<String> urls, final ImageDownloader.ProgressUpdateListener listener) {
new Thread(new Runnable() {
@Override
public void run() {
results = new ArrayList<>();
// Do tasks one by one
for (final String url :
urls) {
//Here the result is a String. Change "String" in the following two lines for other datatypes.
final ThreadLockedTask<String> task = new ThreadLockedTask<>();
final String imagePath = task.execute(new Runnable() {
@Override
public void run() {
//Start the task here
ImageDownloader.getInstance(listener).download(url,
new ImageDownloader.ImageDownloadCallback() {
@Override
public void onSuccess(String imagePath) {
//Set the result on success
task.setResult(imagePath);
}
@Override
public void onFailure() {
//Set result as null on failure
task.setResult(null);
}
});
}
});
if (imagePath!=null)
results.add(imagePath);
}
afterCallbacks();
}
}).start();
}
private PauseModeCallbackHandler() {}
private static void afterCallbacks() {
// All tasks completed. List "results" now holds the result
DemoActivity.isTasksInProgress = false;
}
}
##Method 2: Execute tasks from the callback of the previous one like a chain reaction.
import java.util.ArrayList;
import java.util.List;
public class ChainModeCallbackHandler implements ImageDownloader.ImageDownloadCallback {
// List of args to start the task. Use pojo classes if your task has multiple args
private static List<String> urls;
// List of results
private static List<String> results;
// Optional.
private static ImageDownloader.ProgressUpdateListener progressUpdateListener;
// Leave it as it is
private int index;
public static void start(List<String> urls, ImageDownloader.ProgressUpdateListener listener) {
ChainModeCallbackHandler.urls = urls;
results = new ArrayList<>();
progressUpdateListener = listener;
//Start with the first task
ImageDownloader.getInstance(listener).download(urls.get(0), new ChainModeCallbackHandler(0));
}
private ChainModeCallbackHandler(int index) {
this.index = index;
}
@Override
public void onSuccess(String imagePath) {
results.add(imagePath);
afterCallback();
}
@Override
public void onFailure() {
afterCallback();
}
private void afterCallback() {
int nextIndex = index+1;
if (nextIndex<urls.size()) {
//Tasks are not completed yet. Do next task
ImageDownloader.getInstance(progressUpdateListener).download(urls.get(nextIndex),
new ChainModeCallbackHandler(nextIndex));
} else {
// All tasks completed. List "results" now holds the result
DemoActivity.isTasksInProgress = false;
}
}
}
##Method 3: Execute tasks in parallel.
Pros
Parallel execution helps to save time sometimes
import java.util.ArrayList;
import java.util.List;
public class ParallelModeCallbackHandler {
// List of args to start the task. Use pojo classes if your task has multiple args
private static List<String> urls;
// List of results
private static List<String> results;
// Leave it as it is
private static int count;
public static void start(List<String> urls, ImageDownloader.ProgressUpdateListener listener) {
ParallelModeCallbackHandler.urls = urls;
results = new ArrayList<>();
count = 0;
// Start all tasks
for (String url :
urls) {
//Replace with your task and its callback
ImageDownloader.getInstance(listener).download(url, new ImageDownloader.ImageDownloadCallback() {
@Override
public void onSuccess(String imagePath) {
results.add(imagePath);
afterCallback();
}
@Override
public void onFailure() {
afterCallback();
}
});
}
}
private ParallelModeCallbackHandler() {}
private static void afterCallback() {
if (++count==urls.size()) {
// All tasks completed. List "results" now holds the result
DemoActivity.isTasksInProgress = false;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With