
1. Overview
In this article, we will learn the alternative solutions to the deprecated AsyncTask in Android using Java.
An AsyncTask is an asynchronous task that runs on a background thread and publishes the result on the UI thread.
This API is deprecated in API level 30 and recommended using
java.util.concurrent- Kotlin concurrency utilities.
Here, we will use the java.util.concurrent.
2. Why AsyncTask is deprecated in Android
AsyncTask could cause
- Context leaks
- Missed callbacks
- Crashes on configuration changes
- Inconsistent behavior on different versions of the platform
- Swallows exceptions from
doInBackground. Error hiding or Swallowing exception is the practice of catching an error or exception, and then continuing without logging, processing, or reporting the error to other parts of the app. Swallowing exceptions are considered bad practice as information about the error is lost and makes it very hard to track down the root cause of the problems. - Provide little utility when compared with
Executors directly.
AsyncTask is a helper class around Thread and Handler and does not have any components that can manage threads efficiently.
You can use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.
3. AsyncTask deprecated alternative Android - Java
Here, we are using the Executor class as an alternative to the deprecated AsyncTask.
First, create an instance of the executor by using any of the factory methods:
private final Executor executor = Executors.newSingleThreadExecutor();
A Handler gives you a mechanism to push tasks into the UI thread queue from any other threads thus allowing other threads to communicate with the UI thread. Looper includes a helper function, getMainLooper(), which retrieves the Looper of the main thread. To learn more about Handler, see this article.
Now, let’s retrieve the handler of the UI thread to publish error or results back from the asynchronous task.
private final Handler handler = new Handler(Looper.getMainLooper());
You can use execute method of the Executor class to execute any task asynchronously and publish error or result back to the UI thread by using the handler.
executor.execute(() -> {
final R result;
try {
// perform task asynchronously
// you can also execute runnable or callable
handler.post(() -> {
// update the result to the UI thread
// or any operation you want to perform on UI thread. It is similar to onPostExecute() of AsyncTask
});
} catch (Exception e) {
e.printStackTrace();
handler.post(() -> {
// update error to UI thread or handle
});
}
});
You can use the above code in your app to run tasks asynchronously replacing the AsyncTask. However, you can also use the below class that contains the above Executor logic in a reusable way that would make the code cleaner:
package com.tedblob.rxjava;
import android.os.Handler;
import android.os.Looper;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class ExecutorRunner {
// Executor instance
private final Executor executor = Executors.newSingleThreadExecutor();
// UI thread handler
private final Handler handler = new Handler(Looper.getMainLooper());
// callback interface to communicate result or error
public interface Callback<R> {
void onComplete(R result);
void onError(Exception e);
}
public <R> void execute(Callable<R> callable, Callback<R> callback) {
// Executor's execute method to execute the task asynchronously
executor.execute(() -> {
final R result;
try {
result = callable.call();
handler.post(() -> {
callback.onComplete(result);
});
} catch (Exception e) {
e.printStackTrace();
handler.post(() -> {
callback.onError(e);
});
}
});
}
}
You can also execute Runnable or Callable using the Executor. We will execute the below Callable task by using the execute method of the Executor interface.
package com.tedblob.rxjava;
import java.util.concurrent.Callable;
class SampleCallable implements Callable<String> {
private final String input;
public SampleCallable(String input) {
this.input = input;
}
@Override
public String call() {
return input;
}
}
You can create an instance of the above ExecutorRunner and pass the above callable task to run asynchronously.
executorRunner.execute(new SampleCallable("Input for Sample Callable"), new ExecutorRunner.Callback<String>() {
@Override
public void onComplete(String result) {
// Result returned from the asynchronous task
}
@Override
public void onError(Exception e) {
// any error while running the task asynchronously
}
});
4. Conclusion
To sum up, we have learned the alternative to deprecated AsyncTask in Android (Java).