Android9/26/2020

How to Use AsyncTask in Android for Background Operations

Android applications should never perform heavy operations on the main UI thread.

Tasks such as:

  • Network requests
  • File downloads
  • Database processing
  • Large calculations

can block the UI and make applications unresponsive.

In this tutorial, we will learn how to use AsyncTask in Android to perform background operations while updating the UI safely.


What Is AsyncTask?

AsyncTask is an Android class used to perform background operations and publish results on the UI thread.

It helps developers avoid manually managing:

  • Threads
  • Handlers
  • Runnable objects

Although AsyncTask is deprecated in modern Android development, understanding it is still useful for maintaining older Android projects.


How AsyncTask Works

An AsyncTask typically contains four important methods:

Method Purpose
onPreExecute() Runs before background task starts
doInBackground() Performs heavy background work
onProgressUpdate() Updates progress on UI thread
onPostExecute() Returns result to UI thread

What We Will Build

In this example:

  • User clicks a button
  • Background task starts
  • ProgressBar updates gradually
  • Toast message appears after completion

Step 1 — Create Layout File

Create the UI inside activity_main.xml.


<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <ProgressBar
        android:id="@+id/progress_bar"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:visibility="invisible"/>

    <Button
        android:id="@+id/button_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start"/>

</LinearLayout>

Step 2 — Implement MainActivity.java

Open MainActivity.java and add the following code:


package com.example.asynctaskexample;

import androidx.appcompat.app.AppCompatActivity;

import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;

import java.lang.ref.WeakReference;

public class MainActivity extends AppCompatActivity {

    private ProgressBar progressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        progressBar = findViewById(R.id.progress_bar);

        Button buttonStart =
                findViewById(R.id.button_start);

        buttonStart.setOnClickListener(
                new View.OnClickListener() {

                    @Override
                    public void onClick(View view) {

                        ExampleAsyncTask task =
                                new ExampleAsyncTask(
                                        MainActivity.this
                                );

                        task.execute(10);
                    }
                });
    }

    private static class ExampleAsyncTask
            extends AsyncTask<Integer, Integer, String> {

        private WeakReference<MainActivity>
                activityWeakReference;

        ExampleAsyncTask(MainActivity activity) {

            activityWeakReference =
                    new WeakReference<>(activity);
        }

        @Override
        protected void onPreExecute() {

            super.onPreExecute();

            MainActivity activity =
                    activityWeakReference.get();

            if (activity == null
                    || activity.isFinishing()) {

                return;
            }

            activity.progressBar
                    .setVisibility(View.VISIBLE);
        }

        @Override
        protected String doInBackground(
                Integer... integers
        ) {

            for (int i = 0;
                 i < integers[0];
                 i++) {

                publishProgress(
                        (i * 100) / integers[0]
                );

                try {

                    Thread.sleep(1000);

                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            }

            return "Finished!";
        }

        @Override
        protected void onProgressUpdate(
                Integer... values
        ) {

            super.onProgressUpdate(values);

            MainActivity activity =
                    activityWeakReference.get();

            if (activity == null
                    || activity.isFinishing()) {

                return;
            }

            activity.progressBar
                    .setProgress(values[0]);
        }

        @Override
        protected void onPostExecute(String s) {

            super.onPostExecute(s);

            MainActivity activity =
                    activityWeakReference.get();

            if (activity == null
                    || activity.isFinishing()) {

                return;
            }

            Toast.makeText(
                    activity,
                    s,
                    Toast.LENGTH_SHORT
            ).show();

            activity.progressBar.setProgress(0);

            activity.progressBar
                    .setVisibility(View.INVISIBLE);
        }
    }
}

Why WeakReference Is Important

AsyncTask can continue running even after the Activity is destroyed.

If developers keep a strong Activity reference, memory leaks can happen.

Using:


WeakReference<MainActivity>

helps prevent memory leaks by allowing Android to clean destroyed Activities properly.


How This Example Works

The workflow is:

  1. User clicks Start button
  2. AsyncTask starts in background
  3. Progress updates every second
  4. ProgressBar updates on UI thread
  5. Toast appears after completion

Understanding AsyncTask Generic Types


AsyncTask<Params, Progress, Result>
Type Purpose
Params Input parameters
Progress Progress updates
Result Final task result

Common Mistakes Developers Make

1. Updating UI Inside doInBackground()

UI updates should only happen on the main thread.


2. Creating Memory Leaks

Holding strong Activity references can leak destroyed Activities.


3. Running Heavy Infinite Tasks

Long-running operations should use WorkManager or background services instead.


Why AsyncTask Is Deprecated

Google deprecated AsyncTask because:

  • Lifecycle handling is difficult
  • Memory leaks are common
  • Limited threading flexibility
  • Poor scalability

Modern Alternatives to AsyncTask

Modern Android applications should use:

  • Coroutines
  • WorkManager
  • RxJava
  • Executors
  • LiveData + ViewModel

AsyncTask vs Coroutines

AsyncTask Coroutines
Deprecated Modern solution
Complex lifecycle handling Lifecycle-aware support
More boilerplate Cleaner asynchronous code

FAQ

Is AsyncTask still useful in 2026?

Mainly for maintaining older Android projects and interview preparation.

Why should heavy work avoid the UI thread?

Heavy operations can freeze the UI and cause ANR (Application Not Responding) errors.

What is the best replacement for AsyncTask?

Kotlin Coroutines and WorkManager are modern recommended solutions.


Conclusion

AsyncTask helped Android developers perform background operations more easily in older Android applications.

Although deprecated today, understanding AsyncTask is still useful for maintaining legacy projects and understanding Android threading concepts.

Modern Android applications should prefer lifecycle-aware asynchronous solutions such as Coroutines and WorkManager.


About the Author

Salil Jha is a Full Stack and Mobile Developer with experience in Android, React Native, scalable SaaS platforms, fintech systems, and developer tooling applications.

CodeChain Dev — Build Modern Products. Solve Real Problems.

Deep Structural Diagnostics.

Mastering JSON is only the first step. Use our industrial-grade workbench to format, validate, and synthesize models for your production APIs.