In the Android world, long-running operations such as heavy computations, database operations, or network operations, are not expected to be executed on the UI or main thread because these operations do not complete immediately, and tend to block the thread from which they were called.
It would be a total disaster for the UI if this operation was performed on the main thread. In modern applications, there is a huge reliance on long-running operations to provide rich content to users, and as we know, maintaining a great UI experience is very attractive and keeps users coming back. To avoid UI jank and freezes, work must be moved off the main thread and onto other threads to avoid losing users.
The Android framework has a strict policy regarding this; by default, it does not allow long-running operations such as database interactions or network requests to be performed on the main thread. Exceptions are thrown at runtime, if this policy is violated.
Android originally designed the AsyncTask API to help with asynchronous tasks without requiring third-party libraries. I won’t go into the inner workings of AsyncTask because, as of API level 30, AsyncTask is deprecated and replaced by alternatives, which we’ll discuss in this post.
Why is AsyncTask deprecated?
- There are three main parts of this API that you should understand before working with this API:
- AsyncTask must be subclassed before you can use it.
- It comes with three general types, namely Params, Progress, and Result.
- There are four execution steps: onPreExecute, doInBackground, onProgressUpdate, onPostExecute.
What are Kotlin coroutines?
Suspend functions
suspend fun invokeSuspendFunc (){ }
fun invokeRegularFunc (){ }
Coroutine builders
Coroutine context & dispatchers
Using Kotlin Coroutines for Asynchronous Tasks
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.3" implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.5.1"
Case study
private fun coDoWork (binding: ActivityMainBinding) { lifecycleScope.launch(Dispatchers.IO) { println( "running task on ${Thread.currentThread().name}" ) val result = factorial(input) val text = "Factorial of $result = $result" withContext(Dispatchers.Main) { println( "Accessing UI on ${Thread.currentThread().name}" ) binding.displayText.text = text } } println( "running end on ${Thread.currentThread().name}" ) }