Android AsyncTask Example

Hi Folks! Today I’d like to describe about Android AsyncTask and implement AsyncTask in our android application example.

Let’s Start

AsyncTask(Asynchronous Task):

A common task in Android is to perform some background operations in the background thread, meanwhile updating the main UI thread such as downloading files, playing media, making database queries, or computing complex analytics. This type of heavy task can block the main UI thread and the app doesn’t respond to user input or draw on the screen. So we can use Android AsyncTask to execute some background operations that need to update the UI.

What is AsyncTask ?

AsyncTask is a helper class which helps us to use the UI thread properly. AsyncTask allows us to perform long-run/background operations and show its result on the UI thread without blocking threads. AsyncTasks should ideally be used for short operations (a few seconds at the most.) that will not affect our main thread.

AsyncTasks gives us an easy way to do work on a separate thread while displaying the results of that work on the main thread. It handles all the threading behind the scenes means that the UI thread can stay responsive.

The primary goal of AsyncTask is to make it easy to run a Thread in the background that can later interact with the UI thread. Hence the use of AsyncTask in android applications keeps the UI thread responsive and fast at all times.

Note: AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor, and FutureTask.

How to use AsyncTask

To use the AsyncTask Helper class, we have to first execute the asynctask using the execute() method, then the task will be handled by the AsyncTask helper class.

AsyncTask’s generic types:

When we create an AsyncTask subclass, we can configure it using these three parameters used by an asynchronous task are the following:
AsyncTask<Params, Progress, Result> :

  • Params: The type of parameters sent to the task upon execution.
  • Progress: The type of progress units published during the background computation.
  • Result: The type of the result of the background computation.

Not all types/parameters are always used by an asynchronous task. To mark a type as unused, simply we use the type Void:
private class MyTask extends AsyncTask<Params, Progress, Result> { … }

Methods of AsyncTask :

When an asynchronous task is executed, the task will go through the following 4 stages:

  • onPreExecute(): It invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
  • doInBackground(Params…): It invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress…) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress…) step.
  • onProgressUpdate(Progress…): It invoked on the UI thread after a call to publishProgress(Progress…). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
  • onPostExecute(Result): It invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.

Cancel Task :

A task can be cancelled at any time by invoking cancel(boolean). Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute() will be invoked after doInBackground() returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(), if possible (inside a loop for instance.)

Android AsyncTask Example :

This example demonstrate about how to use AsyncTask in android.

1. Create a New Project –

Create a new project in Android Studio from File ⇒ New Project and select Empty Activity from templates to implement Download image using AsyncTask in android .

2. Implement Dependency –

After creating a new project, specify the following dependency in your build.gradle.

dependencies {
   //Dexter run time permission library
    implementation "com.karumi:dexter:6.1.2"
}

Try to add the latest version of the Dexter run time permission library or Dependency to ask for read and write external storage permission. Once that’s done, save the file and perform a Gradle sync.

3. Add Permissions to AndroidManifest.xml –

AsyncTask is going to perform a network request to load images via the internet and store into external storage, we need to include the permission INTERNET, READ_EXTERNAL_STORAGE, and WRITE_EXTERNAL_STORAGE in our AndroidManifest.xml.

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

or just implement the following xml code to your AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.technxt.androidasynctask">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:hardwareAccelerated="false"
        android:requestLegacyExternalStorage="true"
        android:usesCleartextTraffic="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

4. Designing Layout –

Now open res -> layout -> activity_main.xml  file and just implement the following xml code .

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="180dp"
        android:layout_height="180dp"
        tools:srcCompat="@tools:sample/avatars"
        android:layout_marginTop="28dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="200dp"
        android:layout_height="20dp"
        android:visibility="gone"
        android:progressTint="@color/colorAccent"
        android:minHeight="50dp"
        android:minWidth="250dp"
        android:max="100"
        android:indeterminate="false"
        android:progress="0"
        android:layout_marginHorizontal="20dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

    <TextView
        android:id="@+id/txt"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="0/100"
        android:visibility="gone"
        app:layout_constraintTop_toBottomOf="@id/progressBar"
        app:layout_constraintLeft_toLeftOf="@id/progressBar"
        app:layout_constraintRight_toRightOf="@id/progressBar"/>

    <Button
        android:id="@+id/download"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start Download"
        android:layout_marginBottom="24dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toTopOf="@id/cancel"/>

    <Button
        android:id="@+id/cancel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Cancel Download"
        android:layout_marginBottom="42dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

5. Implement AsyncTask

Creating an AsyncTask is as similar to defining a class that extends from AsyncTask 

public class MyDownLoadTask extends AsyncTask<URL, Integer, String> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            // Good for toggling visibility of a progress indicator
            progressBar.setVisibility(ProgressBar.VISIBLE);
            progressPercent.setVisibility(View.VISIBLE);
        }

        @Override
        protected String doInBackground(URL... urls) {
            // Start long-running task of downloading an image in background thread
            String download = downloadImageFromUrl(urls[0]);
            return download;
        }

        private String downloadImageFromUrl(URL url) {
            int lenghtOfFile = 0;
            try {
                URLConnection conection = url.openConnection();
                conection.connect();
                // getting file length
                lenghtOfFile = conection.getContentLength();

                File folder = new File(Environment
                        .getExternalStorageDirectory().getAbsolutePath() + "/" +"MyImages");
                if (!folder.exists()){
                    folder.mkdir();
                }
                File imgFile = new File(folder,"myimage.jpg");
                // input stream to read file - with 8k buffer
                InputStream input = new BufferedInputStream(url.openStream(), 8192);
                byte data[] = new byte[1024];
                int total = 0;
                int count = 0;
                OutputStream outputStream = new FileOutputStream(imgFile);
                while ((count = input.read(data)) != -1 && !isCancelled()) {
                    total += count;
                    outputStream.write(data,0,count);
                    // publishing the progress....
                    int  progress = (int)(total*100)/lenghtOfFile;
                    publishProgress(progress);
                    Log.d("Progress:", String.valueOf(progress));
                }
                input.close();
                outputStream.close();
            }catch (IOException ex){
                ex.printStackTrace();
            }

            return "Download Completed !";
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            progressPercent.setText("Download "+values[0]+"/"+progressBar.getMax());
            progressBar.setProgress(values[0]);
        }

        @Override
        protected void onPostExecute(String str) {
            super.onPostExecute(str);
            // Hide the progress bar
            progressBar.setVisibility(ProgressBar.INVISIBLE);
            progressPercent.setVisibility(View.INVISIBLE);
            Toast.makeText(getApplicationContext(),str,Toast.LENGTH_LONG).show();
            // Set the result of the long running task to imageview
            String path = Environment
                    .getExternalStorageDirectory().getAbsolutePath() + "/"+"MyImages/myimage.jpg";
            img.setImageDrawable(Drawable.createFromPath(path));

        }

        @Override
        protected void onCancelled() {
            super.onCancelled();
            progressBar.setVisibility(ProgressBar.INVISIBLE);
            progressPercent.setVisibility(View.INVISIBLE);
            Toast.makeText(MainActivity.this, "Download Task Cancelled !", Toast.LENGTH_LONG).show();
        }
    }

7. Execute AsyncTask –

MyDownLoadTask myDownLoadTask = new MyDownLoadTask();
myDownLoadTask.execute(url);

8. Defining MainActivity.java –

Now open your MainActivity.java and add following code –

package net.technxt.androidasynctask;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.app.DownloadManager;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Objects;

import static java.lang.Double.SIZE;

public class MainActivity extends AppCompatActivity {

    ImageView img;
    Button startDownload, cancelDownload;
    ProgressBar progressBar;
    TextView progressPercent;
    //Create an Instance of AsyncTask Subclass
    MyDownLoadTask myDownLoadTask = null;
    String downloadUrl = "http://technxt.net/img/paris.jpg";
    URL url = null;
    private Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        img = findViewById(R.id.imageView);
        progressBar = findViewById(R.id.progressBar);
        progressPercent = findViewById(R.id.txt);
        startDownload = findViewById(R.id.download);
        cancelDownload = findViewById(R.id.cancel);
        myDownLoadTask = new MyDownLoadTask();
        try {
            url = new URL(downloadUrl);
        }catch (MalformedURLException ex){
            ex.printStackTrace();
        }

        Dexter.withActivity(this)
                .withPermissions(
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE)
                .withListener(new MultiplePermissionsListener() {
                    @Override
                    public void onPermissionsChecked(MultiplePermissionsReport report) {
                        // check if all permissions are granted
                        if (report.areAllPermissionsGranted()) {
                            // do you work now
                            Log.d("Permission", "OK");
                        }

                        // check for permanent denial of any permission
                        if (report.isAnyPermissionPermanentlyDenied()) {
                            // permission is denied permenantly, navigate user to app settings
                            // show alert dialog navigating to Settings
                            showSettingsDialog();
                        }
                    }

                    @Override
                    public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
                        token.continuePermissionRequest();
                    }
                })
                .onSameThread()
                .check();

        startDownload.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (myDownLoadTask != null) {
                    myDownLoadTask.execute(url);
                }
            }
        });

        cancelDownload.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (myDownLoadTask != null) {
                    myDownLoadTask.cancel(true);
                }
            }
        });

    }

    private void showSettingsDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
        builder.setTitle("Need Permissions");
        builder.setMessage("This app needs permission to use this feature. You can grant them in app settings.");
        builder.setPositiveButton("GOTO SETTINGS", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
                openSettings();
            }
        });
        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });
        builder.show();

    }

    // navigating user to app settings
    private void openSettings() {
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package", getPackageName(), null);
        intent.setData(uri);
        startActivityForResult(intent, 101);
    }

    public class MyDownLoadTask extends AsyncTask<URL, Integer, String> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            // Good for toggling visibility of a progress indicator
            progressBar.setVisibility(ProgressBar.VISIBLE);
            progressPercent.setVisibility(View.VISIBLE);
        }

        @Override
        protected String doInBackground(URL... urls) {
            // Start long-running task of downloading an image in background thread
            String download = downloadImageFromUrl(urls[0]);
            return download;
        }

        private String downloadImageFromUrl(URL url) {
            int lenghtOfFile = 0;
            try {
                URLConnection conection = url.openConnection();
                conection.connect();
                // getting file length
                lenghtOfFile = conection.getContentLength();

                File folder = new File(Environment
                        .getExternalStorageDirectory().getAbsolutePath() + "/" +"MyImages");
                if (!folder.exists()){
                    folder.mkdir();
                }
                File imgFile = new File(folder,"myimage.jpg");
                // input stream to read file - with 8k buffer
                InputStream input = new BufferedInputStream(url.openStream(), 8192);
                byte data[] = new byte[1024];
                int total = 0;
                int count = 0;
                OutputStream outputStream = new FileOutputStream(imgFile);
                while ((count = input.read(data)) != -1 && !isCancelled()) {
                    total += count;
                    outputStream.write(data,0,count);
                    // publishing the progress....
                    int  progress = (int)(total*100)/lenghtOfFile;
                    publishProgress(progress);
                    Log.d("Progress:", String.valueOf(progress));
                }
                input.close();
                outputStream.close();
            }catch (IOException ex){
                ex.printStackTrace();
            }

            return "Download Completed !";
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            progressPercent.setText("Download "+values[0]+"/"+progressBar.getMax());
            progressBar.setProgress(values[0]);
        }

        @Override
        protected void onPostExecute(String str) {
            super.onPostExecute(str);
            // Hide the progress bar
            progressBar.setVisibility(ProgressBar.INVISIBLE);
            progressPercent.setVisibility(View.INVISIBLE);
            Toast.makeText(getApplicationContext(),str,Toast.LENGTH_LONG).show();
            // Set the result of the long running task to imageview
            String path = Environment
                    .getExternalStorageDirectory().getAbsolutePath() + "/"+"MyImages/myimage.jpg";
            img.setImageDrawable(Drawable.createFromPath(path));

        }

        @Override
        protected void onCancelled() {
            super.onCancelled();
            progressBar.setVisibility(ProgressBar.INVISIBLE);
            progressPercent.setVisibility(View.INVISIBLE);
            Toast.makeText(MainActivity.this, "Download Task Cancelled !", Toast.LENGTH_LONG).show();
        }
    }

}

Finally run your application.

9.Output –

The output of our Android AsyncTask example application is shown below

Android AsyncTask
Android AsyncTask

You can download the project Android AsyncTask from the below link.

Thanks for reading! If you enjoyed this article, please click the 👍 Like button and share it to help others find it! Feel free to leave a comment 💬 below.
Have feedback? Let’s connect on Facebook.

%d bloggers like this: