Creating an AsyncTask in Android
An AsyncTask has three generic parameter types:
AsyncTask<Params, Progress, Result>
- params: the type of the parameters sent to the task upon execution
- progress: the type of the progress units published during the background computation
- result: the type of the result of the background computation
We can actually think about implementing our Async tasks in the order these parameter types are defined!
Step 1:
We must analyze if any runtime parameters need to be sent for execution of the task. In our example to generate a new fact, we only need to invoke the function. Hence, the param type is Void
.
Step 2:
Do we need to know about the progress percentage of this task?
In our async task, there is no concept of progress hence the progress type is also Void
. One example where this is crucial will be downloading a big file.
Step 3:
What is the result of task? The type we designate here also tells us how will we can update our UI with the result. In particular, we want to show the user new fact which is of type String
.
All these steps gives us our signature
AsyncTask<Void, Void, String>() {
Step 4:
Start by extending the abstract class and implementing minimum
override fun doInBackground(vararg params: Void?): String {
Step 5:
Any ui update if need will need.
Shortcut tip: ctrl + o (override method shortcut in android studio) will help do method setup
override fun onPostExecute(result: String?) {
Here we need to set result string as Textview’s text value. We have method in activity that will update it for us. So to call it we need to pass that to task so it can call it. Changing class to have
private class NewAvocadoFactTask(val activity: MainActivity)
Okay! Now just call is left
Step 6:
In onClick method call
moarButton.setOnClickListener {
NewAvocadoFactTask(this).execute();
}
Now for the MOST important step: you are leaking your activity!
How?? What??
AsyncTask is a threading construct. AsyncTask started a new thread and it doesn’t know your app may or may not have been killed by the time we have our response. In other words, AsyncTask runs independent of the main app in the background thread. So if the app is closed first without first ending the task, that task could still be running. After the response is returned, AsyncTask is responsible for returning the result to the main thread itself as a callback.
Is passing the actual activity val activity: MainActivity
really safe? Should we try to call something that could be garbage collected?? Maybe we should use a wrapper called WeakReference
.
var reference: WeakReference<MainActivity> = WeakReference(activity)
What is WeakReference? Glad you asked. It is a wrapper type that would be ok if the object it was keeping track of was garbage collected. Incase that happens it will indicate you the object you wanted reference for is no longer present.
reference.get()
will yield a null
. So we make our UI update call with elvis operator
reference.get()?.updateAvocadoFact(it)