Async Task in Android is Deprecated: There are Better Ways

Async Task in Android is Deprecated: There are Better Ways

There were days when async task in Android was really very great. They allowed us to perform operations in a non thread blocking manner. They were great and not so great at the same time ( stares Schrödinger(ly) ). But now as of Android 11 ( API 30 ) they have been deprecated.

But fear not, we have really cool thing now. Yes, i’m talking about co-routines. For those of you who have never used an async task, see how it looks like below.

Deprecated means it is no longer deemed suitable because of performance, security or technological reasons.

What is Async Task

In Java an AsyncTask implementation looks something like below.

class AsyncTaskExample extends AsyncTask<Void, Void, Void> { @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected Void doInBackground(Void... voids) { return null; } @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); } }

The onPreExecute() block is executed before doInBackground(Void… voids) is triggered. And when the doInBackground(Void… voids) is complete onPostExecute(Void aVoid) block is invoked by the system. Which made it really easy to do asynchronous operations.

Now, we left out the onProgressUpdate(Void… values) block of code. This block was executed when there was some ongoing tasks such as downloading which required update more frequently. These all worked in to make sure you get proper async operation feeling. But they async tasks in android had a great problem that behaved in a weird manner sometimes. Making them really problematic as per the answers on SO.

But for Me I only had one problem with async tasks i.e. if the task was running for long period of time, U.I thread froze. Some of you might say that it’s very unlikely, but it happened. But then again in the documentation it is clearly mentioned that you should not use async task for operation that takes longer than couple of seconds.

Also Read: ZOOM SDK Android: Learn How to Create an Online Meeting

TECHENUM

Why is Async Task in Android deprecated ?

There were too many problems with Async Task in Android. There were context leaks, crashes on configuration changes. As the async task was not tied to Lifecycle of the Activity or Fragment.

If you were not careful with your decision on implementing the Async Task. You would end up with random crashes at unexpected places. Which is always a bad thing for the user and developer as a whole. Nobody likes inconsistent states right ?

Let us look at some of the alternatives of Async Task.

3 best approaches

Great that i’m making async task look like a villain, which was never my intention. And all i’m saying is that there are better ways to achieve these things. Here I will outline exactly three ways how one might accomplish asynchronous operation and more. This will get really very cool if you are already familiar with Kotlin. But even if you’re not it’ll be no problem.

Handler Thread

What is a HandlerThread ? The answer to the question is simple. The HandlerThread is a wrapper class for Thread which allows us to create new threads with more ease. It is because some boiler plate is handled by android system itself.

Let us look at the initialization and usage of the handler thread.

In the code below we have created a new instance of HandlerThread on LINE 1 by passing a name "MyHandlerThread” and on LINE 2 we have started this thread.

HandlerThread ht = new HandlerThread("MyHandlerThread"); ht.start();

After we have created a thread and initialized it we need to use a Handler and a Runnable class to utilize out new thread as under.

Handler handler = new Handler(ht.getLooper()); Runnable runnable = new Runnable() { @Override public void run() { // your async code goes here. } }; handler.post(runnable);

See the comment in LINE 5 ? Yes that’s where you put your code which will be executed in a separate thread. Let us improve it a little more with example.

In the code below you retrieve the result as Object in LINE 8. And you pass it from LINE 22. And we have invoked another method on LINE 9 passing the response variable. The doSomethingOnUi() method has necessary code to run things on UI.

public void doSomeTaskAsync() { HandlerThread ht = new HandlerThread("MyHandlerThread"); ht.start(); Handler asyncHandler = new Handler(ht.getLooper()) { @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); Object response = msg.obj; doSomethingOnUi(response); } }; Runnable runnable = new Runnable() { @Override public void run() { // your async code goes here. try { Thread.sleep(10_000); // create message and pass any object here doesn't matter // for a simple example I have used a simple string Message message = new Message(); message.obj = "My Message!"; asyncHandler.sendMessage(message); } catch (InterruptedException e) { e.printStackTrace(); } } }; asyncHandler.post(runnable); }

And now let us look at the method doSomethingOnUi(). After 10 milliseconds we will get the string "My Message!". In the code below cast the object to whatever you had passed in LINE 22 above. The code in the run() will be executed on main thread. That is where you must put your code for updating U.I elements.

private void doSomethingOnUi(Object response) { Handler uiThread = new Handler(Looper.getMainLooper()); uiThread.post(new Runnable() { @Override public void run() { // now update your UI here // cast response to whatever you specified earlier } }); }

That was all about HandlerThread let us move forward into Executors and see how same thing can be done using Executors below. We know one way to replace async task in Android now.

You should move this line

HandlerThread ht = new HandlerThread("MyHandlerThread");

Out of the method and create an instance only once like a singleton.

Also Read: Implement SMS Broadcast Receiver in Android

TECHENUM

Executors

Executors are way more structured service which manage multiple number ( pool ) of threads. We can specify how many threads are to be kept in the memory. If we supply more than the amount of acceptable pool of threads, they will be kept in a queue.

Everything is exactly same except the LINE 2 and the try {} catch {} block of code. And you may want to make sure you create only one instance of ExecutorService.

.public void doSomeTaskAsync() { ExecutorService executors = Executors.newFixedThreadPool(1); Runnable runnable = new Runnable() { @Override public void run() { // your async code goes here. try { Thread.sleep(10_000); // create message and pass any object here doesn't matter // for a simple example I have used a simple string String msg = "My Message!"; doSomethingOnUi(msg); } catch (InterruptedException e) { e.printStackTrace(); } } }; executors.submit(runnable); }

The other method is exactly same though it might be a better thing to use String instead of Object ( because we used String in our example ). The second block of code:

private void doSomethingOnUi(Object response) { Handler uiThread = new Handler(Looper.getMainLooper()); uiThread.post(new Runnable() { @Override public void run() { // now update your UI here // cast response to whatever you specified earlier } }); }

This is just a quick way on using ExecutorService, I have not really explained it in detail here. For that I might write a separate article later. Now that takes us to our final way of doing async operation i.e. co-routine.

Make sure to move the line out of the method as we should not create a new instance each time the method is invoked.

ExecutorService executors = Executors.newFixedThreadPool(1);

Coroutines

Do you want to learn more about coroutine basics ? Read more here : Kotlin Coroutine in Android : Understanding the Basics

co-routine cannot be used with Java it’s Kotlin specific feature. We can achieve something similar in Java with the help of Future. But I will not be discussing about future in the present. Let’s dive right into co-routine.

Let us quickly convert the above code into co-routines and see how Kotlin makes it really very easy for us.

In the code below we have used CoroutineExceptionHandler to handle any exceptions when executing co-routine. the code inside the withContext(Dispatchers.IO) { } is where the magic happens. You might notice Dispatchers.IO which is used by co-routine to identify the type of task. If you’re familiar with RxJava you might notice the similarity.

fun doSomeTaskAsync() { val errorHandler = CoroutineExceptionHandler { coroutineContext, throwable -> // here the exception is gracefully handled } GlobalScope.launch(errorHandler) { var result: String = "" withContext(Dispatchers.IO) { delay(10_000) result = "My Task!" doSomethingOnUi(result) } } }

Now for the U.I update part it’s really easy use the code below. If you’re not familiar to Kotlin the keyword suspend will make your heart pound a bit, read more.

suspend fun doSomethingOnUi(msg: String) { withContext(Dispatchers.Main) { // update your UI code here } }

Now that we have successfully understood how we might replace async task in android. There might be other ways to explore which I might have missed. But I play with co-routines and ExecutorService all the time in my work. If you find any problem with the code examples please feel free to leave a comment below.

Also Read: Interface in OOP: Guide to Polymorphism and Callbacks

TECHENUM

Naveen Niraula

I am an Android Developer. I really love to write tutorials and reviews about latest technologies.

This Post Has One Comment

  1. Hu Sen

    Thanks!

Leave a Reply