Android中的AsyncTask与Kotlin

Rak*_*ari 38 android kotlin

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

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

shi*_*psh 51

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)
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

Anko doAsync并不是由Kotlin"提供",因为Anko是一个使用Kotlin语言功能来简化长码的库.点击这里:

如果您使用Anko,您的代码将类似于:

doAsync {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

  • 我们如何防止此警告"可能发生泄漏使异步任务静态"? (3认同)

Alg*_*gar 28

您可以很容易地获得与Anko类似的语法.如果你只是做背景任务,你可以做类似的事情

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

并使用它

doAsync {
    yourTask()
}.execute()
Run Code Online (Sandbox Code Playgroud)

  • @Mohanakrrishna这是一个古老的答案,我永远也不会使用。.例如使用LiveData,您的所有烦恼都消除了。而且由于它是Kotlin-使用协程,您的所有烦恼都消除了。 (2认同)

que*_*ful 12

这是一个示例,它还允许您更新显示给用户的任何UI或进度.

异步类

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

    override fun doInBackground(vararg params: Void?): Void? {
        handler()
        return null
    }
}
Run Code Online (Sandbox Code Playgroud)

简单用法

doAsync {
    // do work here ...

    myView.post({
        // update UI of myView ...
    })
}
Run Code Online (Sandbox Code Playgroud)


Gop*_*.cs 6

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

链接-Github Irontec


Ser*_*gey 6

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)
}
Run Code Online (Sandbox Code Playgroud)

现在它可以用于任何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"
          })
      }
  }
Run Code Online (Sandbox Code Playgroud)

或在Activity/ Fragment

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

要在应用程序的build.gradle文件的依赖项中使用viewModelScopelifecycleScope添加下一行:

implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$LIFECYCLE_VERSION" // for viewModelScope
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$LIFECYCLE_VERSION" // for lifecycleScope
Run Code Online (Sandbox Code Playgroud)


Hit*_*ahu 5

这就是我在项目中避免内存泄漏的做法:

我创建了一个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()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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

class LoadMediaTask(listener: ProgressListener) : BaseAsyncTask(listener) {

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

        return VideoMediaProvider().allVideos
    }
}
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)