使用Kotlin的Android AsyncTask

时间:2020-02-23 14:28:46  来源:igfitidea点击:

在本教程中,我们将在Android应用程序中使用Kotlin学习和实现AsyncTask。

什么是Android AsyncTask?

Android AsyncTask是一个抽象类,用于在后台执行较长的操作。
我们必须扩展此类并实现抽象方法以在我们的应用程序中使用异步任务。

inner class SomeTask extends AsyncTask<Params, Progress, Result>

异步任务的三个类型参数是:

  • 参数:发送到AsyncTask的参数的类型。

  • Progress:在后台计算过程中发布的进度单位的类型。

  • Result:后台计算结果的类型。

AsyncTask方法

AsyncTask具有四种方法,这些方法在异步任务执行的生命周期中的不同时间触发。

  • PreExecute:在执行AsyncTask之前在UI线程中调用。
    我们可以使用此方法显示一个ProgressBar或者执行任何与UI相关的任务。

  • doInBackground:后台执行代码采用这种方法。
    我们无法使用此方法调用"活动"的UI实例。

  • onProgressUpdate:在doInBackground方法中调用发布进度时,将触发此方法。
    如果您希望通知UI线程当前进度,则可以使用此方法。

  • onPostExecute:在doInBackground结束后被触发。
    从doInBackground返回的值在此处接收。
    我们可以在此处进行UI更改,例如使用返回的值更新视图。

如何在Kotlin中创建AsyncTask?

val task = MyAsyncTask(this)
task.execute(10)

execute方法启动AsyncTask。
我们可以在构造函数中传递任何内容,通常会传递上下文。

AsyncTask被定义为内部类。
我们必须将它们定义为静态,以防止内存泄漏。

在Kotlin中,伴随对象等效于静态类。
因此,AsyncTasks是在伴随对象中定义的。

为什么非静态AsyncTask会导致内存泄漏?

当为非静态时,它们保存对活动的引用。
因此,如果AsyncTask在Activity的生命周期之后才存在,它将保留对Activity的引用,从而导致内存泄漏。

因此,在我们可以存储活动的弱引用的地方使用"伴侣对象"。

Android AsyncTask Kotlin项目结构

1. XML布局代码

下面给出了activity_main.xml布局文件的代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".MainActivity">

  <TextView
      android:id="@+id/textView"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_above="@+id/btnDoAsync"
      android:gravity="center"
      android:text="Value if returned from the AsyncTask, will be displayed here" 

  <Button
      android:id="@+id/btnDoAsync"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:layout_margin="16dp"
      android:text="START ASYNC TASK" 

  <ProgressBar
      android:id="@+id/progressBar"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_below="@+id/btnDoAsync"
      android:visibility="gone"
      android:layout_centerHorizontal="true" 

</RelativeLayout>

2. Kotlin活动类代码

MainActivity.kt Kotlin活动类如下所示。

package net.androidly.androidlyasynctask

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
import android.os.AsyncTask
import android.view.View
import android.widget.Toast
import java.lang.ref.WeakReference

class MainActivity : AppCompatActivity() {

  var myVariable = 10

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

      btnDoAsync.setOnClickListener {
          val task = MyAsyncTask(this)
          task.execute(10)
      }
  }

  companion object {
      class MyAsyncTask internal constructor(context: MainActivity) : AsyncTask<Int, String, String?>() {

          private var resp: String? = null
          private val activityReference: WeakReference<MainActivity> = WeakReference(context)

          override fun onPreExecute() {
              val activity = activityReference.get()
              if (activity == null || activity.isFinishing) return
              activity.progressBar.visibility = View.VISIBLE
          }

          override fun doInBackground(vararg params: Int?): String? {
              publishProgress("Sleeping Started") //Calls onProgressUpdate()
              try {
                  val time = params[0]?.times(1000)
                  time?.toLong()?.let { Thread.sleep(it/2) }
                  publishProgress("Half Time") //Calls onProgressUpdate()
                  time?.toLong()?.let { Thread.sleep(it/2) }
                  publishProgress("Sleeping Over") //Calls onProgressUpdate()
                  resp = "Android was sleeping for " + params[0] + " seconds"
              } catch (e: InterruptedException) {
                  e.printStackTrace()
                  resp = e.message
              } catch (e: Exception) {
                  e.printStackTrace()
                  resp = e.message
              }

              return resp
          }

          override fun onPostExecute(result: String?) {

              val activity = activityReference.get()
              if (activity == null || activity.isFinishing) return
              activity.progressBar.visibility = View.GONE
              activity.textView.text = result.let { it }
              activity.myVariable = 100
          }

          override fun onProgressUpdate(vararg text: String?) {

              val activity = activityReference.get()
              if (activity == null || activity.isFinishing) return

              Toast.makeText(activity, text.firstOrNull(), Toast.LENGTH_SHORT).show()

          }
      }
  }
}

当我们单击按钮时,AsyncTask在后台启动。

我们在AsyncTask中传递一个Int值,该值表示秒数。

doInBackground方法中,我们将线程休眠指定的秒数。

我们正在使用在Toast中显示的String触发progressUpdate

在" onPostExecute"方法中,我们隐藏了ProgressBar,并将TextView设置为通过解包Kotlin可空类型返回的字符串。