Android AsyncTask Using Kotlin

Filed Under: Android

In this tutorial, we’ll be discussing and implementing AsyncTasks using Kotlin in our Android Application.

AsyncTask

AsyncTask is an abstract class that’s used to perform long operations in the background.
You need to extend it to make use of it.
inner class SomeTask extends AsyncTask<Params,Progress,Result>

The three types used by an asynchronous task are the following:

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

Following are the four methods that are triggered at different times during an AsyncTask:

  • PreExecute : This is invoked in UI thread before the AsyncTask is executed. We can show a ProgressBar or do any UI Stuff here.
  • doInBackground : The background execution works here. We cannot call the Activity’s UI instances in here.
  • onProgressUpdate : This gets triggered when
  • onPostExecute : Gets triggered after doInBackground is over. The values returned from the doInBackground are received here. We can do the UI stuff here such as updating the views with the values returned.

How is an AsyncTask instance created?

val task = MyAsyncTask(this)
task.execute(10)

The execute method starts the AsyncTask.
In the constructor, we can pass anything. Typically a context is passed.

AsyncTasks are defined as inner classes.
To prevent memory leaks we need to define them as static.
In Kotlin, companion object is the equivalent of static classes. So AsyncTasks are defined in a companion object.

Why can AsyncTask cause memory leaks when non-static?
When non-static, they hold a reference to the Activity. So, if the AsyncTask exists till after the Activity’s lifecycle, it’ll keep a reference of the Activity thereby causing memory leaks.
Hence companion object is used in which we can store a weak reference of the Activity.

Project Structure

android-asynctask-kotlin-project-structure

Code

The code for the activity_main.xml layout file is given below:


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">


    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/btnDoAsync"
        android:gravity="center"
        android:text="Value if returned from the AsyncTask, will be displayed here" />

    <Button
        android:id="@+id/btnDoAsync"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_margin="16dp"
        android:text="START ASYNC TASK" />


    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btnDoAsync"
        android:visibility="gone"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

The MainActivity.kt Kotlin Activity class is given below:


package net.androidly.androidlyasynctask

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
import android.os.AsyncTask
import android.view.View
import android.widget.Toast
import java.lang.ref.WeakReference


class MainActivity : AppCompatActivity() {


    var myVariable = 10

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btnDoAsync.setOnClickListener {
            val task = MyAsyncTask(this)
            task.execute(10)
        }
    }

    companion object {
        class MyAsyncTask internal constructor(context: MainActivity) : AsyncTask<Int, String, String?>() {

            private var resp: String? = null
            private val activityReference: WeakReference<MainActivity> = WeakReference(context)

            override fun onPreExecute() {
                val activity = activityReference.get()
                if (activity == null || activity.isFinishing) return
                activity.progressBar.visibility = View.VISIBLE
            }

            override fun doInBackground(vararg params: Int?): String? {
                publishProgress("Sleeping Started") // Calls onProgressUpdate()
                try {
                    val time = params[0]?.times(1000)
                    time?.toLong()?.let { Thread.sleep(it / 2) }
                    publishProgress("Half Time") // Calls onProgressUpdate()
                    time?.toLong()?.let { Thread.sleep(it / 2) }
                    publishProgress("Sleeping Over") // Calls onProgressUpdate()
                    resp = "Android was sleeping for " + params[0] + " seconds"
                } catch (e: InterruptedException) {
                    e.printStackTrace()
                    resp = e.message
                } catch (e: Exception) {
                    e.printStackTrace()
                    resp = e.message
                }

                return resp
            }


            override fun onPostExecute(result: String?) {

                val activity = activityReference.get()
                if (activity == null || activity.isFinishing) return
                activity.progressBar.visibility = View.GONE
                activity.textView.text = result.let { it }
                activity.myVariable = 100
            }

            override fun onProgressUpdate(vararg text: String?) {

                val activity = activityReference.get()
                if (activity == null || activity.isFinishing) return

                Toast.makeText(activity, text.firstOrNull(), Toast.LENGTH_SHORT).show()

            }
        }
    }
}

In the MainActivity, on Button click the AsyncTask is launched.
We pass an Int value in the AsyncTask which represents the number of seconds.
In the doInBackground we put the thread to sleep for that number of seconds, in intervals.
We trigger the progressUpdate with a String which displays a Toast.
In the onPostExecute we hide the ProgressBar and set the TextView to the string returned by unwrapping the Kotlin Nullable Type.

The output of the above application in action is given below:
android-p-asynctask-output

This brings an end to this tutorial. You can download the project from the link below:

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages