Home » AsyncTask deprecated alternative Android Kotlin

AsyncTask deprecated alternative Android Kotlin

  • by
AsyncTask deprecated alternative Android

1. Overview

In this article, we will learn the alternative solutions to the deprecated AsyncTask in Android using Kotlin.

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

  1. java.util.concurrent 
  2. Kotlin concurrency utilities.

Here, we will use the java.util.concurrent.

2. Why AsyncTask is deprecated in Android

AsyncTask could cause

  1. Context leaks
  2. Missed callbacks
  3. Crashes on configuration changes
  4. Inconsistent behavior on different versions of the platform
  5. 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. 
  6. 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 ExecutorThreadPoolExecutor and FutureTask.

3. AsyncTask deprecated alternative Android - Kotlin

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 val 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 val handler = 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 {
    val result: R
    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 (e: Exception) {
         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
class ExecutorRunner {
    // create a new instance of Executor using any factory methods
    private val executor: Executor = Executors.newSingleThreadExecutor()
    // handler of UI thread
    private val handler = Handler(Looper.getMainLooper())
    // callable to communicate the result back to UI
    interface Callback<R> {
        fun onComplete(result: R)
        fun onError(e: Exception?)
    }
    fun <R> execute(callable: Callable<R>, callback: Callback<R>) {
        executor.execute {
            val result: R
            try {
                // execute the callable or any tasks asynchronously
                result = callable.call()
                handler.post { 
                   // update the result back to UI
                   callback.onComplete(result) 
                }
            } catch (e: Exception) {
                e.printStackTrace()
                handler.post { // communicate error or handle 
                    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.

class SampleCallable(private val input: String) : Callable<String> {
    override fun call(): String {
        return input
    }
}

You can create an instance of the above ExecutorRunner and pass the above callable task to run asynchronously.

executorRunner?.execute(
            SampleCallable("Input for Sample Callable"),
            object : ExecutorRunner.Callback<String> {
                override fun onComplete(result: String) { // handle the result obtained from the asynchronous task 
                }
                override fun onError(e: Exception?) { // handle the result obtained from the asynchronous task 
                }
            })

4. Conclusion

To sum up, we have learned the alternative to deprecated AsyncTask in Android (Kotlin).

Leave a Reply

Your email address will not be published.