51 votes

AsyncTask dans Android avec Kotlin

Comment faire un appel d'API dans Android avec Kotlin ?

J'ai entendu parler de Anko . Mais je veux utiliser les méthodes fournies par Kotlin comme dans Android, nous avons Asynctask pour les opérations en arrière-plan.

2 votes

Vous pouvez également utiliser AsyncTask avec Kotlin

77voto

shiftpsh Points 1294

AsyncTask est un Android API et non un caractéristique linguistique qui est fournie par Java ou Kotlin. Vous pouvez les utiliser comme ça si vous le souhaitez :

class someTask() : AsyncTask<Void, Void, String>() {
    override fun doInBackground(vararg params: Void?): String? {
        // ...
    }

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

    override fun onPostExecute(result: String?) {
        super.onPostExecute(result)
        // ...
    }
}

Anko's doAsync n'est pas vraiment "fournie" par Kotlin, puisque Anko est une bibliothèque qui utilise les caractéristiques du langage de Kotlin pour simplifier les longs codes. Vérifiez ici :

Si vous utilisez Anko, votre code sera similaire à celui-ci :

doAsync {
    // ...
}

4 votes

Comment éviter cet avertissement "une fuite peut se produire si la tâche asynchrone est statique" ?

0 votes

@Killer Ne le mettez pas dans les classes qui peuvent rester trop longtemps à cause de l'AsyncTask (comme Activity), à moins que vous ne les gardiez sous contrôle, et que vous annuliez toutes les instances de l'AsyncTask lorsque votre classe devrait être détruite.

36voto

Algar Points 1126

Vous pouvez obtenir une syntaxe similaire à celle d'Anko assez facilement. Si vous ne voulez que la tâche de fond, vous pouvez faire quelque chose comme

class doAsync(val handler: () -> Unit) : AsyncTask<Void, Void, Void>() {
    override fun doInBackground(vararg params: Void?): Void? {
        handler()
        return null
    }
}

Et l'utiliser comme

doAsync {
    yourTask()
}.execute()

1 votes

J'ai récemment migré vers Kotlin. J'ai donc quelques doutes.. Comment pouvez-vous être sûr que des fuites de mémoire ne se produiront pas lorsque vous appelez ce doAsync depuis une activité ou un fragment. Où obtiendrez-vous le résultat ? Le doAsync d'Anko est conscient du cycle de vie, n'est-ce pas ? Comment pouvons-nous l'intégrer dans notre doAsync ?

4 votes

@Mohanakrrishna C'est une vieille réponse et je ne l'utiliserais jamais Utilisez par exemple LiveData et tous vos soucis disparaissent. Et comme il s'agit de Kotlin, utilisez des coroutines et tous vos soucis disparaîtront.

26voto

quemeful Points 134

Voici un exemple qui vous permettra également de mettre à jour toute interface utilisateur ou progression affichée à l'utilisateur.

Classe asynchrone

class doAsync(val handler: () -> Unit) : AsyncTask<Void, Void, Void>() {
    init {
        execute()
    }

    override fun doInBackground(vararg params: Void?): Void? {
        handler()
        return null
    }
}

Utilisation simple

doAsync {
    // do work here ...

    myView.post({
        // update UI of myView ...
    })
}

1 votes

Merci mon pote. Cela fonctionne comme un charme pour les personnes utilisant Kotlin. J'ai sauvé ma journée.

9voto

Gopi.cs Points 600
package com.irontec.kotlintest

import android.os.AsyncTask
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
import android.widget.TextView
import kotlinx.android.synthetic.main.activity_main.*
import org.json.JSONObject
import java.io.BufferedInputStream
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL

class MainActivity : AppCompatActivity() {

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

        GetWeatherTask(this.text).execute()
    }

    class GetWeatherTask(textView: TextView) : AsyncTask<Unit, Unit, String>() {

        val innerTextView: TextView? = textView

        override fun doInBackground(vararg params: Unit?): String? {
            val url = URL("https://raw.githubusercontent.com/irontec/android-kotlin-samples/master/common-data/bilbao.json")
            val httpClient = url.openConnection() as HttpURLConnection
            if (httpClient.responseCode == HttpURLConnection.HTTP_OK) {
                try {
                    val stream = BufferedInputStream(httpClient.inputStream)
                    val data: String = readStream(inputStream = stream)
                    return data
                } catch (e: Exception) {
                    e.printStackTrace()
                } finally {
                    httpClient.disconnect()
                }
            } else {
                println("ERROR ${httpClient.responseCode}")
            }
            return null
        }

        fun readStream(inputStream: BufferedInputStream): String {
            val bufferedReader = BufferedReader(InputStreamReader(inputStream))
            val stringBuilder = StringBuilder()
            bufferedReader.forEachLine { stringBuilder.append(it) }
            return stringBuilder.toString()
        }

        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)

            innerTextView?.text = JSONObject(result).toString()

            /**
             * ... Work with the weather data
             */

        }
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.menu_main, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        val id = item.itemId
        if (id == R.id.action_settings) {
            return true
        }
        return super.onOptionsItemSelected(item)
    }
}

lien - Github Irontec

1 votes

Cela semble très mauvais. Même si l'asynctask est une classe interne... Je ne vois pas où vous vérifiez l'état de l'activité dans onPostExecute ? Aussi, arrêtez d'utiliser Asynctask tous ensemble.

3voto

J'utilise toujours ce formulaire :

open class LoadingProducts : AsyncTask<Void, Void, String>() {

private var name = ""

    override fun doInBackground(vararg p0: Void?): String {

        for (i in 1..100000000) {
            if (i == 100000000) {
                name = "Hello World"
            }
        }
        return name
    }
}

Vous l'invoquez de la manière suivante :

loadingProducts = object : LoadingProducts() {
        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)

            Log.e("Result", result)
        }
    }

loadingProducts.execute()

J'utilise l'ouverture afin de pouvoir appeler le onPostExecute pour le résultat.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X