AsyncTask in Android with Kotlin



如何使用 Kotlin 在 Android 中进行 API 调用?

我听说过安科.但是我想使用 Kotlin 提供的方法,就像在 Android 中我们有 Asynctask 进行后台操作一样。

AsyncTask是一个 Android API,而不是 Java 或 Kotlin 提供的语言功能。如果需要,您可以像这样使用它们:

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 的doAsync并不是由 Kotlin 真正"提供"的,因为 Anko 是一个使用 Kotlin 的语言特性来简化长代码的库。在这里查看:

  • https://github.com/Kotlin/anko/blob/d5a526512b48c5cd2e3b8f6ff14b153c2337aa22/anko/library/static/commons/src/Async.kt

如果你使用Anko,你的代码将类似于这样:

doAsync {
    // ...
}

你可以得到一个与Anko类似的语法相当容易。如果您只是不想执行后台任务,则可以执行以下操作

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

并像使用它一样使用

doAsync {
    yourTask()
}.execute()

下面是一个示例,它还允许您更新向用户显示的任何 UI 或进度。

异步类

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

简单用法

doAsync {
    // do work here ...
    myView.post({
        // update UI of myView ...
    })
}

AsyncTask在 API 级别 30 中已弃用。为了实现类似的行为,我们可以使用 Kotlin 并发实用程序(协程(。

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)
}

现在它可以在任何CoroutineScope实例上使用,例如,在ViewModel

class MyViewModel : ViewModel() {
      fun someFun() {
          viewModelScope.executeAsyncTask(onPreExecute = {
              // ...
          }, doInBackground = {
              // ...
              "Result" // send data to "onPostExecute"
          }, onPostExecute = {
              // ... here "it" is a data returned from "doInBackground"
          })
      }
  }

Activity/Fragment

lifecycleScope.executeAsyncTask(onPreExecute = {
      // ...
  }, doInBackground = {
      // ...
      "Result" // send data to "onPostExecute"
  }, onPostExecute = {
      // ... here "it" is a data returned from "doInBackground"
  })

要使用viewModelScopelifecycleScope将下一行添加到应用的 build.gradle 文件的依赖项中,请执行以下操作:

implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$LIFECYCLE_VERSION" // for viewModelScope
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$LIFECYCLE_VERSION" // for lifecycleScope
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)
    }
}

链接 - Github Irontec

这是我

在项目中避免内存泄漏的方式:

我为异步加载创建了一个abstract base Async Task

import android.os.AsyncTask
abstract class BaseAsyncTask(private val listener: ProgressListener) : AsyncTask<Void, Void, String?>() {
    interface ProgressListener {
        // callback for start
        fun onStarted()
        // callback on success
        fun onCompleted()
        // callback on error
        fun onError(errorMessage: String?)
    }
    override fun onPreExecute() {
        listener.onStarted()
    }
    override fun onPostExecute(errorMessage: String?) {
        super.onPostExecute(errorMessage)
        if (null != errorMessage) {
            listener.onError(errorMessage)
        } else {
            listener.onCompleted()
        }
    }
}

用法:

现在,每次我必须在后台执行某些任务时,我都会创建一个新LoaderClass并使用我的BaseAsyncTask类对其进行扩展,如下所示:

class LoadMediaTask(listener: ProgressListener) : BaseAsyncTask(listener) {
    override fun doInBackground(vararg params: Void?): String? {
        return VideoMediaProvider().allVideos
    }
}

现在,您可以在应用中的任何位置使用新的AsyncLoader类。

下面是显示/隐藏进度条和处理错误/成功场景的示例:

   LoadMediaTask(object : BaseAsyncTask.ProgressListener {
            override fun onStarted() {
                //Show Progrss Bar
                loadingBar.visibility = View.VISIBLE
            }
            override fun onCompleted() {
                // hide progress bar
                loadingBar.visibility = View.GONE
                // update UI on SUCCESS
                setUpUI()
            }
            override fun onError(errorMessage: String?) {
                // hide progress bar
                loadingBar.visibility = View.GONE
                // Update UI on ERROR
                Toast.makeText(context, "No Videos Found", Toast.LENGTH_SHORT).show()
            }
        }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)

我总是使用这种形式:

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
    }
}

您可以通过以下方式调用它:

loadingProducts = object : LoadingProducts() {
        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)
            Log.e("Result", result)
        }
    }
loadingProducts.execute()

我使用 open,以便我可以调用结果的 onPostExecute 方法。

我花了一整天的时间试图弄清楚如何取回异步任务产生的结果:协程是我的解决方案!!

首先,创建您的异步任务对象...不要忘记使用更正参数类型代替所有任何

@SuppressLint("StaticFieldLeak")
class AsyncTaskExample(private var activity: MainActivity?) : AsyncTask<Any, Int, Any?>() {
    override fun onPreExecute() {
        super.onPreExecute()
        // do pre stuff such show progress bar
    }
    override fun doInBackground(vararg req: Any?): Any? {
        // here comes your code that will produce the desired result
        return result 
    }
    // it will update your progressbar
    override fun onProgressUpdate(vararg values: Int?) {
        super.onProgressUpdate(*values)
    }

    override fun onPostExecute(result: Any?) {
        super.onPostExecute(result)
        // do what needed on pos execute, like to hide progress bar
        return
    }
}

然后,调用它(在本例中,从主活动(

var task = AsyncTaskExample(this)
var req = { "some data object or whatever" }
GlobalScope.launch( context = Dispatchers.Main){
   task?.execute(req)
}
GlobalScope.launch( context = Dispatchers.Main){
   println( "Thats the result produced by doInBackgorund: " +  task?.get().toString() )
}
<</div> div class="one_answers">

如果您想在不使用 Anko 的情况下执行此操作,正确的方法是使用以下方式

open class PromotionAsyncTask : AsyncTask<JsonArray, Void, MutableList<String>>() {
private lateinit var out: FileOutputStream
private lateinit var bitmap: Bitmap
private lateinit var directory: File
private var listPromotion: MutableList<String> = mutableListOf()
override fun doInBackground(vararg params: JsonArray?): MutableList<String> {
    directory = Environment.getExternalStoragePublicDirectory("Tambo")
    if (!directory.exists()) {
        directory.mkdirs()
    }
    for (x in listFilesPromotion(params[0]!!)) {
        bitmap = BitmapFactory.decodeStream(URL(x.url).content as InputStream)
        out = FileOutputStream(File(directory, "${x.name}"))
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
        out.flush()
        out.close()
        listPromotion.add(File(directory, "${x.name}").toString())
    }
    return listPromotion
}
private fun listFilesPromotion(jsonArray: JsonArray): MutableList<Promotion> {
    var listString = mutableListOf<Promotion>()
    for (x in jsonArray) {
        listString.add(Promotion(x.asJsonObject.get("photo")
                .asString.replace("files/promos/", "")
                , "https://tambomas.pe/${x.asJsonObject.get("photo").asString}"))
    }
    return listString}
}

执行方式如下

promotionAsyncTask = object : PromotionAsyncTask() {
                    override fun onPostExecute(result: MutableList<String>?) {
                        super.onPostExecute(result)
                        listFile = result!!
                        contentLayout.visibility = View.VISIBLE
                        progressLottie.visibility = View.GONE
                    }
                }
                promotionAsyncTask.execute(response!!.body()!!.asJsonObject.get("promos").asJsonArray)

我在可组合中使用LaunchedEffect

LaunchedEffect ("http_get") {
    withContext (Dispatchers.IO) {
        http_get() }}

并在回调中rememberCoroutineScope

val scope = rememberCoroutineScope()
Button (
    onClick = {
        scope.launch {
            withContext (Dispatchers.IO) {
                http_get() }}})

它似乎有效,但我不知道为什么。

  private fun updateUI(account: GoogleSignInAccount?) {
    if (account != null) {
        try {
            AsyncTaskExample().execute()
        } catch (e: Exception) {
        }
    }
}
inner class AsyncTaskExample : AsyncTask<String, String, String>() {
            override fun onPreExecute() {
                super.onPreExecute()
            }
            override fun doInBackground(vararg p0: String?): String {
                var Result: String = "";
                try {
                    googleToken = GoogleAuthUtil.getToken(activity, accountVal, "oauth2:https://www.googleapis.com/auth/userinfo.profile")
                    signOut()
                } catch (e: Exception) {
                    signOut()
                }

                signOut()
                return Result
            }
            override fun onPostExecute(result: String?) {
                super.onPostExecute(result)
                socialPrsenter.setDataToHitApiGoogleLogin(googleToken ?: "")
            }
        }

最新更新