Open In App

Alternatives for the Deprecated AsyncTask in Android

Improve
Improve
Like Article
Like
Save
Share
Report

AsyncTask (Asynchronous Task) in Android is an abstract class, or rather a helper class that lets the application perform tedious tasks in the background and parallelly perform UI changes in the front-end. This is quite similar to Threading but does not constitute any threading framework. Background tasks such as loading images, downloading music, pictures, files, etc can be performed using AsyncTask. However, AsyncTask is now deprecated and developers might sooner or later need an alternative for this.

How AsyncTask now appears in IDE

Through this article, we will show you 2 methods through which you can perform background tasks and simultaneously update the UI elements. The two alternatives are:

  1. Using a combination of an Executor and a Handler
  2. Using a Thread

But first, let us look at how AsyncTask works.

AsyncTask General Code Structure

The below code implements an AsyncTask to an inner class MyCustomClass. AsyncTask requires three arguments:

  1. Params: Can be of type Int, String, any object given as Input for executing the supposed task, Void when there is no input.
  2. Progress: Units published while executing the task, Void when not needed.
  3. Result: Can be of type Int, String, any object when the task is finished. Void when no output variable is needed.

Associated member functions are:

  1. onPreExecute() Optional
  2. doInBackground(Params…) Required
  3. onProgressUpdate(Progress…) Optional
  4. onPostExecute(Result) Optional

Below is the basic code structure for implementing AsyncTask.

Kotlin




import android.os.AsyncTask
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
  
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
  
    // AsyncTask <Params: Any!, Progress: Any!, Result: Any!>()
    inner class MyCustomClass: AsyncTask<String, Void, String>(){
  
        override fun doInBackground(vararg params: String?): String {
            TODO()
        }
  
        override fun onPostExecute(result: String?) {
            TODO()
        }
  
    }
}


Example:

Now in this example, we shall pass an Integer value (Input) to the Task. In the background, the input is converted into a String, and after the conversion, it will be displayed in a TextView.

Kotlin




import android.annotation.SuppressLint
import android.os.AsyncTask
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
  
class MainActivity : AppCompatActivity() {
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
  
        val myTextView = findViewById<TextView>(R.id.textView)
  
        val myInput = 100
        MyCustomClass(myTextView).execute(myInput)
    }
  
    // Input type is Int and Result is a String
    @SuppressLint("StaticFieldLeak")
    inner class MyCustomClass(var textView: TextView): AsyncTask<Int, Void, String>(){
  
        override fun doInBackground(vararg params: Int?): String {
            // Convert the input Params:Int
            // to String and return the Result:String
            return params[0].toString()
        }
  
        // Result:String is set as text in the passed TextView
        override fun onPostExecute(result: String?) {
            textView.text = result
        }
    }
}


XML




<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
  
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"/>
  
</RelativeLayout>


Output:

So basically, the code works perfectly fine. However, we have used AsyncTask to perform our task, which is deprecated and sooner or later requires a replacement.

Output when AsyncTask is implemented

Alternative 1: Using Executor and Handler

There is a sample code below. If you see, there is an executor and a handler declared. The executor will help in performing any task in the background and the handler will help to make UI changes.

Kotlin




import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import java.util.concurrent.Executors
  
class MainActivity : AppCompatActivity() {
      
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
  
        val myExecutor = Executors.newSingleThreadExecutor()
        val myHandler = Handler(Looper.getMainLooper())
          
        myExecutor.execute { 
        // Do something in background (back-end process)
        }
          
        myHandler.post { 
        // Do something in UI (front-end process)
        }
    }
}


Example:

We used the same example as we used for AsyncTask. Here the executor will execute the task and as soon as the desired results are available, UI changes are made using a handler.

Kotlin




import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.widget.TextView
import java.util.concurrent.Executors
  
class MainActivity : AppCompatActivity() {
  
    private val myExecutor = Executors.newSingleThreadExecutor()
    private val myHandler = Handler(Looper.getMainLooper())
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
  
        val myTextView = findViewById<TextView>(R.id.textView)
        val myInput = 55
  
        doMyTask(myTextView, myInput)
    }
  
    private fun doMyTask(textView: TextView, input: Int){
        myExecutor.execute {
            val result = input.toString()
            myHandler.post {
                textView.text = result
            }
        }
    }
}


XML




<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
  
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"/>
  
</RelativeLayout>


Output:

The code runs perfectly fine. We have got the desired results.

Output when we used Executor & Handler

Alternative 2: Using  a Thread

The below code runs a Thread. The marked comments show where the codes for background and UI changes are to be made. When using a Thread, any UI changes must run inside a UI Thread, and any background process must run outside the UI Thread.

Kotlin




import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
  
class MainActivity : AppCompatActivity() {
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
          
        Thread(Runnable {
            // Do something in Background (Back-end)
            runOnUiThread {
            // Do something in UI (Front-end)
            }
        }).start()
    }
}


Example:

Now let us look at an example where we shall pass an Integer for converting it into a String and pass it to the TextView.

Kotlin




import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
  
class MainActivity : AppCompatActivity() {
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
          
        val myTextView = findViewById<TextView>(R.id.textView)
        val myInput = 26
  
        doMyTask(myTextView, myInput)
    }
  
    private fun doMyTask(textView: TextView, input: Int){
        Thread(Runnable {
            val result = input.toString()
            runOnUiThread {
                textView.text = result
            }
        }).start()
    }
}


XML




<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
  
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"/>
  
</RelativeLayout>


Output:

The code runs perfectly fine. We have our desired results.

Output when Thread is used



Last Updated : 05 Aug, 2021
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads