AsyncManager hopes to keep management of background threads as simple as possible, by keeping the creation and termination of background tasks to just one API call respectively. Callback, which will be processed on the UI thread, can be overridden to process the result returned from the background operation.
SDK Version 11 & above (Lower version is not tested)
- Create & maintain background threads for you.
- Contain callbacks to handle the result from a background job.
- Pass in data to be used in the long operation.
- Prevent memory leaks from the usual pitfalls of background threads & AsyncTask.
- Runs all operations asynchronously over 4 threads. (More can be set through the API)
Maven:
repositories {
maven { url "http://dl.bintray.com/populov/maven" }
}
dependencies {
compile 'com.github.boxme:asyncmanager:1.0.0'
}
jCenter:
repositories {
jcenter()
}
dependencies {
compile 'com.github.boxme:asyncmanager:1.0.0'
}
AsyncManager will be instantiated automatically as a Singleton.
Start a background task. Assign the type of result expected, if any. Extra data for the operation can also be passed in through #setParams(). Otherwise, Void it. You can use the API checkForThreadInterruption() to check for early termination, especially for extremely long running operation.
// A BackgroundTask object will be returned from this method. Reference it if require.AsyncManager.runBackgroundTask(newTaskRunnable<Params, Result, Void>() {
@OverridepublicResultdoLongOperation(Paramsparams) throwsInterruptedException {
// checkForThreadInterruption();// Your long operationreturnresult;
}
// Override this callback if you need to handle the result on the UI thread@Overridepublicvoidcallback(Resultresult) {
// Handle the result from doLongOperation()
}
}.setParams(params));Start a background task that will be persisted and allowed to run till its completion. It's still a best practice to instantiate it as a static inner class first before using.
// Bad practice if your long operation is extremely time consuming.AsyncManager.runBackgroundTask(newPersistedTaskRunnable<Void, Result, Void>() {
@OverridepublicResultdoLongOperation(Voidvoid) throwsInterruptedException {
// Your long operationreturnresult;
}
// Override this callback if you need to handle the result on the UI thread@Overridepublicvoidcallback(Resultresult) {
// Handle the result from doLongOperation()
}
});
// Instantiate it first as a static inner classprivatestaticclassLongBackGroundPersistedTaskextendsPersistedTaskRunnable<String[], Void, Void> {
@OverridepublicVoiddoLongOperation(String[] strings) throwsInterruptedException {
// Long operationreturnnull;
}
}
String[] params = newString[2];
params[0] = "data";
params[1] = "data;
AsyncManager.runBackgroundTask(new LongBackGroundPersistedTask().setParams(params));Start a background task that will assign a handler to handle the result
AsyncManager.runBackgroundTask(newTaskRunnable<Void, Result, MainActivity>() {
@OverridepublicResultTypedoLongOperation() throwsInterruptedException {
// checkForThreadInterruption();// Your long operationreturnresult;
}
// handler is weakly referenced, if it has been GC, this callback // will not be triggered@Overridepublicvoidcallback(MainActivityhandler, Resultresult) {
// handler to handle the result
}
}.setResultHandler(MainActivity));It is good to clear the task if it's no longer required, so that BackgroundTask can be used for future work as soon as possible. Example: clear them in onDestroyView() or onDestroy()
// Cancel one taskAsyncManager.cancelOneTask(BackgroundTask, booleanshouldClearPersistedTask);
// To clear all non persisted tasksAsyncManager.cancelAllNonPersistedTasks();
// To clear all tasks, including persisted onesAsyncManager.cancelAllTasks();Qn: Does this take care of configuration changes?
Ans: UI updates will not be delivered because the tasks should be cancelled by the API as soon as possible if it's not required, hence it's important to check for any thread interruptions using #checkForThreadInterruption() in the long running operation. #cancelAllNonPersistedTasks() will then be able to clean up the tasks and free the memory in used.
Qn: Why not just use the AsyncTask?
Ans:
If your AsyncTasks are required to run concurrently, an easy way to do so is to execute using THREAD_POOL_EXECUTOR. On a quad-core device, this means that any up to 5 AsyncTasks can be handled concurrently, If a 6th task is started before the any of the previous 5 is done, it will be placed in the waiting queue. The way to increase the number of concurrent tasks executed is to implement your own custom Executor.
This library hopes to keep that simple for you, you can increase the number easily by AsyncManager.setThreadPoolSize(int)
AsyncTask termination also requires you to keep a reference to the executed task individually, and terminate them when you no longer require them to continue its operations. This result in a lot more code and management on the developer's part.
AsyncManager is already keeping track of all your background tasks and you can terminate all of them with just 1 API call. As stated above, you will still be able to keep a reference to the started task if you want to terminate them selectively.
Execution differences on different platform version can also be a hassle to manage.
| API level | execute | executeOnExecutor |
|---|---|---|
| 11 - 12 | Concurrent | Sequential/concurrent (customizable) |
| 13+ | Sequential | Sequential/concurrent (customizable) |
| Furthermore, all AsyncTask instances also share an application-wide, global execution property. This means that if two different threads launch two different instances at the same time, they will still be executed sequentially. |
If all you need is one single thread to process your background thread sequentially, you should consider using IntentService.