Notes: 24. Implement an AsyncTask
The student materials have been reviewed and are updated as of SEPTEMBER 2022.
Even though the AlarmManager is the first API that came in Android, for scheduling work in some way, you’ll cover the AsyncTask first.
AsyncTasks have three functions. doInBackground(), onProgressUpdate() and onPostExecute(). The first is where you fetch or compute your values. The second is for displaying progress to the user, and the third is for consuming the value, once it’s ready.
The AsyncTask handles threading and posting to the main thread automatically, so you don’t have to worry about it! You’ll see how easy it is to implement it! So let’s get on it! :]
First create a new class called DownloadImageTask, and add the following starter code:
class DownloadImageTask(private val onImageLoaded: (Bitmap) -> Unit) : AsyncTask<String, String, Bitmap>() {
}
The task will extend the AsyncTask class, and it will take in a String variable arguments array as the input, it can provide a String as the progress output, but you won’t use it, and it will produce a Bitmap as the task output.
Next, override the doInbackground() function, and add the code like so:
class DownloadImageTask(private val onImageLoaded: (Bitmap) -> Unit) : AsyncTask<String, String, Bitmap>() {
override fun doInBackground(vararg params: String?): Bitmap {
val imagePath = params[0] ?: throw IllegalArgumentException("No url provided!")
val imageUrl = URL(imagePath)
val connection = imageUrl.openConnection() as HttpURLConnection
}
}
doInBackground() will take in that String array, and it will produce a Bitmap. You can get the first parameter here, and if there isn’t one, it means no image path was passed in.
Then you open an HTTP connection. Finally, add the rest of the code to download an image:
class DownloadImageTask(private val onImageLoaded: (Bitmap) -> Unit) : AsyncTask<String, String, Bitmap>() {
override fun doInBackground(vararg params: String?): Bitmap {
val imagePath = params[0] ?: throw IllegalArgumentException("No url provided!")
val imageUrl = URL(imagePath)
val connection = imageUrl.openConnection() as HttpURLConnection
connection.doInput = true
connection.connect()
val inputStream = connection.inputStream
try {
return BitmapFactory.decodeStream(inputStream)
} catch (error: Throwable) {
error.printStackTrace()
}
throw IllegalArgumentException("No image")
}
}
You could’ve returned null here, and made the return type nullable, but this might be better, as you expect to get an image to display.
After you’ve downloaded the image, and computed it, you need to consume it via the lambda property in the class constructor. To do that, override the onPostExecute() function, and add the rest of the code:
...
override fun onPostExecute(result: Bitmap?) {
super.onPostExecute(result)
if (result != null) {
onImageLoaded(result)
}
}
...
This will send the result back to the call site. That’s it from the AsyncTask side! Head over to the MainActivity.kt, and add the final piece of code, to start the AsyncTask:
val imagePath = "https://cdn.pixabay.com/photo/2017/11/30/11/57/barn-owl-2988291_960_720.jpg"
val task = DownloadImageTask { bitmap ->
image.setImageBitmap(bitmap)
}
task.execute(imagePath)
Now run the project, and the image should be displayed in the app! :]
The AsyncTask will take in the parameters from execute(), process them using doInBackground(), and then post them to the main thread using onPostExecute(), which is quite cool! :]