Background processing with AsyncTask
Updated in AndroidAndroid AsyncTask
is one the key elements of the whole platform. The class
provides easy to understand interface for background threads. Background
threads are important in Android since you cannot do anything CPU intensive on
the UI thread. If you do, you’ll make the UI very sluggish and at some point
the operating system intervenes and displays an Application Not Responding
(ANR) dialog to the user and stops the applications.
So in order to do any heavy lifting you need to use background threads and
AsyncTask
class gives you easy access to them. Google documentation gives
you a thorough explanation about the class but I’ll go over the main points
here and shown an example on AsyncTask
usage.
Basics
AsyncTask class consists of four main methods: onPreExecute()
,
doInBackground()
, onProgressUpdate()
and onPostExecute()
. Out of these
four methods doInBackground()
is the only one executed in the background
thread. What this means is that you cannot change UI directly from
doInBackground and you need to use publishProgress method which calls
onProgressUpdate()
behind the scenes. So in normal case the AsyncTask program
flow goes something like this:
- onPreExecute()
- doInBackground(Params…)
- onProgressUpdate(Progress…)
- Do some more work and update UI
- onPostExecute(Result)
Example
The following example shows AsyncTask usage in more detail.
Resources
res/values/strings.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">AsyncTask Tutorial</string>
<string name="start_button">Start AsyncTask</string>
<string name="ok_button">OK</string>
</resources>
res/layout/activity_asynctask.xml:
<?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=".AsyncTaskActivity">
<Button
android:id="@+id/startAsyncTask"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onStartButtonClick"
android:text="@string/start_button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Code
src/com/caphal/android/asynctask/AsyncTaskActivity.java:
package com.tanelikorri.android.asynctask;
import android.app.AlertDialog.Builder;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
public class AsyncTaskActivity extends AppCompatActivity {
private static final String TAG = "AsyncTaskActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_asynctask);
}
/**
* Start button click handler
*
* @param view
*/
public void onStartButtonClick(View view) {
// Start new AsyncTask with a parameter
new PrimeTask().execute(5000);
}
/**
* Calculates given parameter amount of prime numbers starting from 0 and
* returns the calculation time.
*/
private class PrimeTask extends AsyncTask<Integer, Integer, Long> {
private int primeCount;
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.d(TAG, "UI thread onPreExecute");
}
@Override
protected Long doInBackground(Integer... params) {
primeCount = params[0];
long startTime = System.currentTimeMillis();
int primesFound = 0;
for (int i = 2; primesFound < primeCount; i++) {
if (isPrime(i)) {
primesFound++;
// Publish progress, calls onProgressUpdate behind the scenes
publishProgress(i, (int) (((float) primesFound / (float) primeCount) * 100f));
}
}
long endTime = System.currentTimeMillis();
return endTime - startTime;
}
/**
* Checks if the given parameter is a prime number. Return true or false
*
* @param number Number to test
* @return True if the parameter is prime number, false otherwise
*/
private boolean isPrime(int number) {
for (int i = number - 1; i > 1; i--) {
if (number % i == 0) {
return false;
}
}
return true;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// Print progress to the log
Log.d(TAG, values[0] + " is prime " + values[1] + " % ready");
}
@Override
protected void onPostExecute(Long result) {
super.onPostExecute(result);
Log.d(TAG, "onPostExecute");
// Show AlertDialog to user
Builder builder = new Builder(AsyncTaskActivity.this);
builder.setMessage(primeCount + " prime(s) found in " + result
/ 1000 + " second(s).");
builder.setPositiveButton(R.string.ok_button, null);
builder.create().show();
}
}
}
Screenshots
Source code
Source code for this example project is available here