Manu13k
Manu13k

Reputation: 366

AsyncTask use in Kotlin

I have a problem with AsyncTask in Kotlin , I'm actually new so please be cool :)

So the problem here , is that I would like to use the result value which is in onPostExecute(), in another class

Let me show you my code, Here is ProviderAsync() class in my Provider.kt file ( I just create an array of Hashmap which I want to use) :

class ProviderAsync() : AsyncTask<HashMap<String, Any>, Void, ArrayList<HashMap<String, Any>>>() {

var allThings: ArrayList<HashMap<String, Any>> = arrayListOf()
override fun doInBackground(vararg params: HashMap<String, Any>): ArrayList<HashMap<String, Any>>? {
    for (i in 0..2000) {
        val thing = hashMapOf("Loc" to "fr", "name" to "class", "Id" to "23", "tuto" to "fr", "price" to 44)
        allThings.add(thing )
    }
    return null
}

override fun onPreExecute() {
    super.onPreExecute()
    // ...
}

override fun onPostExecute(result: ArrayList<HashMap<String, Any>>?) {
    super.onPostExecute(result)
    // what can I do Here
}

And now here is my getThings() method in another file where i want to use the result value to get all elements of my Arraylist :

fun getThings(context: Context) {
        ProviderAsync().execute()
        var values = // Here i want the RESULT send from my AsyncTask
         for (i in 0..values.size) {

                        var myObject = convertToMyObject(values[i])
                        allTickets.add(myObject)
                    }
        }

Thanks and sorry for my English

Upvotes: 4

Views: 6250

Answers (2)

Sergio
Sergio

Reputation: 30595

As of June 2020 AsyncTask is DEPRECATED. It doesn't mean that the class will be removed any time soon, it means that Google is recommending that you move to something else. The docs recommend to use the standard java.util.concurrent or Kotlin concurrency utilities instead.

Using the last one we can implement it as the following:

  1. Create generic extension function on CoroutineScope:

     fun <R> CoroutineScope.executeAsyncTask(
             onPreExecute: () -> Unit,
             doInBackground: () -> R,
             onPostExecute: (R) -> Unit
     ) = launch {
         onPreExecute()
         val result = withContext(Dispatchers.IO) { // runs in background thread without blocking the Main Thread
             doInBackground()
         }
         onPostExecute(result)
     } 
    
  2. Use the function with any CoroutineScope:

    • In ViewModel:

      class MyViewModel : ViewModel() {
      
          fun someFun() {
              viewModelScope.executeAsyncTask(onPreExecute = {
                  // ... runs in Main Thread
              }, doInBackground = {
                  // ... runs in Worker(Background) Thread
                  "Result" // send data to "onPostExecute"
              }, onPostExecute = {
                  // runs in Main Thread
                  // ... here "it" is the data returned from "doInBackground"
              })
          }
      }
      
    • In Activity or Fragment:

      lifecycleScope.executeAsyncTask(onPreExecute = {
          // ... runs in Main Thread
      }, doInBackground = {
          // ... runs in Worker(Background) Thread
          "Result" // send data to "onPostExecute"
      }, onPostExecute = {
          // runs in Main Thread
          // ... here "it" is the data returned from "doInBackground"
      })
      

    To use viewModelScope or lifecycleScope add next line(s) to dependencies of the app's build.gradle file:

    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$LIFECYCLE_VERSION" // for viewModelScope
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:$LIFECYCLE_VERSION" // for lifecycleScope
    

    At the time of writing final LIFECYCLE_VERSION = "2.3.0-alpha05"

Upvotes: 1

y.allam
y.allam

Reputation: 1516

You can take advantage of Kotlin's functional nature:

class ProviderAsync(private val callback: (things: ArrayList<HashMap<String, Any>>) -> Unit) : AsyncTask<HashMap<String, Any>, Void, ArrayList<HashMap<String, Any>>>() {

    var allThings: ArrayList<HashMap<String, Any>> = arrayListOf()
    override fun doInBackground(vararg params: HashMap<String, Any>): ArrayList<HashMap<String, Any>>? {
        for (i in 0..2000) {
            val thing = hashMapOf("Loc" to "fr", "name" to "class", "Id" to "23", "tuto" to "fr", "price" to 44)
            allThings.add(thing)
        }
        return null
    }

    override fun onPreExecute() {
        super.onPreExecute()
        // ...
    }

    override fun onPostExecute(result: ArrayList<HashMap<String, Any>>) {
        super.onPostExecute(result)

        //callback function to be executed after getting the result
        callback(result)
    }
}

then split the the callback logic in a separate function to pass it to ProviderAsync constructor:

fun getThings(context: Context) {
        ProviderAsync(::asyncTaskCallback).execute()
}

fun asyncTaskCallback(values: ArrayList<HashMap<String, Any>>) {
    for (i in 0..values.size) {

        var myObject = convertToMyObject(values[i])
        allTickets.add(myObject)
    }
}

Upvotes: 2

Related Questions