In Java, I've gotten used to working with Futures
. Now I'm looking at Android, and AsyncTask
implements almost all the same methods and covers similar lifecycles. But, if I want to be consistent and use Future all over my code, I have to wrap AsyncTask in a stupid wrapper, cause it doesn't actually implement Future.
All they'd need to add is an isDone()
method, which seems like it would be trivial, then add implements Future<Result>
. (added later: see my answer below for just how trivial it would be).
Any Android experts know some good reason / obscure bug it might cause why this hasn't been done?
In summary, the three most common issues with AsyncTask are: Memory leaks. Cancellation of background work. Computational cost.
This class was deprecated in API level 30. AsyncTask was intended to enable proper and easy use of the UI thread. However, the most common use case was for integrating into UI, and that would cause Context leaks, missed callbacks, or crashes on configuration changes.
java - The AsyncTask API is deprecated in Android 11.
Alternative 1: Using Executor and Handler The executor will help in performing any task in the background and the handler will help to make UI changes.
From reading the actual code of AsyncTask.java
it actually uses a Future
task and then some more. A Future
is a task that executes asynchronously on the go. An AsyncTask
is scheduled on a queue for a single (or pool of) background thread(s).
An AsyncTask
is actually more "superior" than a Future
task. It does fancy scheduling and optimizations on top of Future
's functionality. Just look at the API introduction levels. Future
was introduced right from the start API 1.0. The AsyncTask
object was introduced in API 3.
An AsyncTask has-a Future task, not is-a Future.
AsyncTask.java
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
I'm still interested in the theoretical reasons "why" not to use AsyncTask for a Future.
But, for the record, I ended up creating my own little class (shown below). Just extend it instead of AsyncTask if you want a Future. IMO, a cleaner way than the @Eng.Fouad idea of accessing the private mFuture within the code. (But thanks for the idea, it got me looking into the source code a bit!) YMMV.
public abstract class FutureAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> implements Future<Result>{
@Override
public boolean isDone() {
return AsyncTask.Status.FINISHED == getStatus();
}
}
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