4

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

4
  • First of all let me know why are you not writing async task in the same class in which you want to use returned value? Commented May 2, 2018 at 16:18
  • It's my architecture , I want that my Provider do AsyncTask and sends datas to my Manager Commented May 2, 2018 at 16:25
  • Refer this. Commented May 2, 2018 at 16:42
  • Any reason why you are using HashMap<String, Any?> instead of something like a class? Commented May 2, 2018 at 21:44

2 Answers 2

2

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)
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

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"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.