Last active
August 29, 2015 14:04
-
-
Save jmartinesp/275c4f31bda9d0445fc4 to your computer and use it in GitHub Desktop.
First version of a class that makes async processing a lot cleaner than using an AsyncTask, for example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.os.Handler; | |
import android.os.Looper; | |
import java.util.concurrent.ExecutorService; | |
import java.util.concurrent.FutureTask; | |
/** | |
* Created by Arasthel on 08/07/14. | |
*/ | |
public class AsyncJob<JobResult> { | |
private static Handler uiHandler = new Handler(Looper.getMainLooper()); | |
// Action to do in background | |
private AsyncAction actionInBackground; | |
// Action to do when the background action ends | |
private AsyncResultAction actionOnMainThread; | |
// An optional ExecutorService to enqueue the actions | |
private ExecutorService executorService; | |
// The thread created for the action | |
private Thread asyncThread; | |
// The FutureTask created for the action | |
private FutureTask asyncFutureTask; | |
// The result of the background action | |
private JobResult result; | |
/** | |
* Instantiates a new AsyncJob | |
*/ | |
public AsyncJob() { | |
} | |
/** | |
* Executes the provided code immediately on the UI Thread | |
* @param onMainThreadJob Interface that wraps the code to execute | |
*/ | |
public static void doOnMainThread(final OnMainThreadJob onMainThreadJob) { | |
uiHandler.post(new Runnable() { | |
@Override | |
public void run() { | |
onMainThreadJob.doInUIThread(); | |
} | |
}); | |
} | |
/** | |
* Executes the provided code immediately on a background thread | |
* @param onBackgroundJob Interface that wraps the code to execute | |
*/ | |
public static void doInBackground(final OnBackgroundJob onBackgroundJob) { | |
new Thread(new Runnable() { | |
@Override | |
public void run() { | |
onBackgroundJob.doOnBackground(); | |
} | |
}).start(); | |
} | |
/** | |
* Executes the provided code immediately on a background thread that will be submitted to the | |
* provided ExecutorService | |
* @param onBackgroundJob Interface that wraps the code to execute | |
* @param executor Will queue the provided code | |
*/ | |
public static FutureTask doInBackground(final OnBackgroundJob onBackgroundJob, ExecutorService executor) { | |
FutureTask task = (FutureTask) executor.submit(new Runnable() { | |
@Override | |
public void run() { | |
onBackgroundJob.doOnBackground(); | |
} | |
}); | |
return task; | |
} | |
/** | |
* Begins the background execution providing a result, similar to an AsyncTask. | |
* It will execute it on a new Thread or using the provided ExecutorService | |
*/ | |
public void start() { | |
if(actionInBackground != null) { | |
Runnable jobToRun = new Runnable() { | |
@Override | |
public void run() { | |
result = (JobResult) actionInBackground.doAsync(); | |
onResult(); | |
} | |
}; | |
if(getExecutorService() != null) { | |
asyncFutureTask = (FutureTask) getExecutorService().submit(jobToRun); | |
} else { | |
asyncThread = new Thread(jobToRun); | |
asyncThread.start(); | |
} | |
} | |
} | |
/** | |
* Cancels the AsyncJob interrupting the inner thread. | |
*/ | |
public void cancel() { | |
if(actionInBackground != null) { | |
if(executorService != null) { | |
asyncFutureTask.cancel(true); | |
} else { | |
asyncThread.interrupt(); | |
} | |
} | |
} | |
private void onResult() { | |
if (actionOnMainThread != null) { | |
uiHandler.post(new Runnable() { | |
@Override | |
public void run() { | |
actionOnMainThread.onResult(result); | |
} | |
}); | |
} | |
} | |
public ExecutorService getExecutorService() { | |
return executorService; | |
} | |
public void setExecutorService(ExecutorService executorService) { | |
this.executorService = executorService; | |
} | |
public AsyncAction getActionInBackground() { | |
return actionInBackground; | |
} | |
/** | |
* Specifies which action to run in background | |
* @param actionInBackground the action | |
*/ | |
public void setActionInBackground(AsyncAction actionInBackground) { | |
this.actionInBackground = actionInBackground; | |
} | |
public AsyncResultAction getActionOnResult() { | |
return actionOnMainThread; | |
} | |
/** | |
* Specifies which action to run when the background action is finished | |
* @param actionOnMainThread the action | |
*/ | |
public void setActionOnResult(AsyncResultAction actionOnMainThread) { | |
this.actionOnMainThread = actionOnMainThread; | |
} | |
public interface AsyncAction<ActionResult> { | |
public ActionResult doAsync(); | |
} | |
public interface AsyncResultAction { | |
public void onResult(Object result); | |
} | |
public interface OnMainThreadJob { | |
public void doInUIThread(); | |
} | |
public interface OnBackgroundJob { | |
public void doOnBackground(); | |
} | |
/** | |
* Builder class to instantiate an AsyncJob in a clean way | |
* @param <JobResult> the type of the expected result | |
*/ | |
public static class AsyncJobBuilder<JobResult> { | |
private AsyncAction<JobResult> asyncAction; | |
private AsyncResultAction asyncResultAction; | |
private ExecutorService executor; | |
public AsyncJobBuilder() { | |
} | |
/** | |
* Specifies which action to run on background | |
* @param action the AsyncAction to run | |
* @return the builder object | |
*/ | |
public AsyncJobBuilder<JobResult> doInBackground(AsyncAction<JobResult> action) { | |
asyncAction = action; | |
return this; | |
} | |
/** | |
* Specifies which action to run when the background action ends | |
* @param action the AsyncAction to run | |
* @return the builder object | |
*/ | |
public AsyncJobBuilder<JobResult> doWhenFinished(AsyncResultAction action) { | |
asyncResultAction = action; | |
return this; | |
} | |
/** | |
* Used to provide an ExecutorService to launch the AsyncActions | |
* @param executor the ExecutorService which will queue the actions | |
* @return the builder object | |
*/ | |
public AsyncJobBuilder<JobResult> withExecutor(ExecutorService executor) { | |
this.executor = executor; | |
return this; | |
} | |
/** | |
* Instantiates a new AsyncJob of the given type | |
* @return a configured AsyncJob instance | |
*/ | |
public AsyncJob<JobResult> create() { | |
AsyncJob<JobResult> asyncJob = new AsyncJob<JobResult>(); | |
asyncJob.setActionInBackground(asyncAction); | |
asyncJob.setActionOnResult(asyncResultAction); | |
asyncJob.setExecutorService(executor); | |
return asyncJob; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.widget.Toast; | |
import java.util.concurrent.ExecutorService; | |
import java.util.concurrent.Executors; | |
/** | |
* Created by Arasthel on 26/07/14. | |
*/ | |
public class AsyncJobSample { | |
public void asyncStaticCall(final Context context) { | |
AsyncJob.doInBackground(new AsyncJob.OnBackgroundJob() { | |
@Override | |
public void doOnBackground() { | |
// Pretend it's doing some background processing | |
try { | |
Thread.sleep(1000); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
// Create a fake result (MUST be final) | |
final boolean result = true; | |
// Send the result to the UI thread and show it on a Toast | |
AsyncJob.doOnMainThread(new AsyncJob.OnMainThreadJob() { | |
@Override | |
public void doInUIThread() { | |
Toast.makeText(context, "Result was: "+ result, Toast.LENGTH_SHORT).show(); | |
} | |
}); | |
} | |
}); | |
} | |
public void asyncJobWithResult(final Context context) { | |
new AsyncJob.AsyncJobBuilder<Boolean>() | |
.doInBackground(new AsyncJob.AsyncAction<Boolean>() { | |
@Override | |
public Boolean doAsync() { | |
try { | |
Thread.sleep(1000); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
return true; | |
} | |
}).doWhenFinished(new AsyncJob.AsyncResultAction() { | |
@Override | |
public void onResult(Object result) { | |
Toast.makeText(context, "Result was: " + result, Toast.LENGTH_SHORT).show(); | |
} | |
}).create().start(); | |
} | |
public void asyncStaticJobWithExecutor(final Context context) { | |
// Create a job to run on background | |
AsyncJob.OnBackgroundJob job = new AsyncJob.OnBackgroundJob() { | |
@Override | |
public void doOnBackground() { | |
// Pretend to do some background processing | |
try { | |
Thread.sleep(1000); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
// This toast should show a difference of 1000ms between calls | |
AsyncJob.doOnMainThread(new AsyncJob.OnMainThreadJob() { | |
@Override | |
public void doInUIThread() { | |
Toast.makeText(context, "Finished on: "+System.currentTimeMillis(), Toast.LENGTH_SHORT).show(); | |
} | |
}); | |
} | |
}; | |
// This ExecutorService will run only a thread at a time | |
ExecutorService executorService = Executors.newSingleThreadExecutor(); | |
// Send 5 jobs to queue which will be executed one at a time | |
for(int i = 0; i < 5; i++) { | |
AsyncJob.doInBackground(job, executorService); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Changed ThreadPoolExecutor for ExecutorService interface.