Kotlin 中 AsyncTask 的使用教程

AsyncTask 用于将耗时操作放到后台线程执行,同时在任务开始和结束时在主线程更新 UI。本文将逐步讲解其基本概念、生命周期方法,并提供一个简单的示例代码。

值得注意的是, 从 Android 11 开始,AsyncTask 已被弃用,建议在新项目中使用 Kotlin 协程、WorkManager 或其他异步方案,本文仅做学习记录使用,而且第一行代码P396 10.2.4讲的更详细更好。


1. AsyncTask 的基本概念

AsyncTask 使用三个泛型参数来确定任务的输入、进度和结果类型:

  • Params:传递给任务的参数类型。
  • Progress:任务执行中更新进度时使用的数据类型。
  • Result:任务执行完毕后返回的结果类型。

例如:

plaintext

1
class MyTask : AsyncTask<Void, Int, String>() { ... }

表示该任务不需要输入参数(Void)、进度为 Int 类型、最终结果为 String。


2. AsyncTask 的生命周期方法

AsyncTask 定义了多个回调方法,每个方法在任务执行的不同阶段被调用:

  • onPreExecute()
    在任务开始前调用,通常用于初始化 UI(例如显示进度条)。
  • doInBackground(vararg params: Params)
    在后台线程中执行耗时操作。此方法不能直接更新 UI,但可以调用 publishProgress() 触发进度更新。
  • onProgressUpdate(vararg values: Progress)
    当调用 publishProgress() 时在主线程中执行,用于更新 UI 中的进度显示。
  • onPostExecute(result: Result)
    在后台任务执行完毕后调用,运行在主线程中,可以使用任务返回的结果更新 UI。
  • onCancelled()
    当任务被取消时调用,可用于清理操作。

3. Kotlin 示例代码

下面的示例展示了如何使用 AsyncTask 在后台模拟一个耗时任务(例如计数操作),并在 UI 上更新进度和显示结果。

plaintext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import android.os.AsyncTask
import android.os.Bundle
import android.widget.ProgressBar
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    private lateinit var progressBar: ProgressBar
    private lateinit var textView: TextView

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

        progressBar = findViewById(R.id.progressBar)
        textView = findViewById(R.id.textView)

        // 传入一个整数参数,这个参数会被传递到doInBackground()方法当中,例如:10
        MyTask().execute(10)
    }

    // MyTask 类继承自 AsyncTask<Int, Int, String>
    private inner class MyTask : AsyncTask<Int, Int, String>() {

        // 在任务开始前调用,通常用于初始化界面,比如显示进度条
        override fun onPreExecute() {
            super.onPreExecute()
            progressBar.progress = 0
            textView.text = "任务开始..."
        }

        // 在后台线程中执行耗时操作
        // params 数组中包含 execute() 方法传入的参数,这里我们只传入一个 Int 类型的参数
        override fun doInBackground(vararg params: Int?): String {
            // 获取传入的参数值,假设它表示任务总步数
            val totalSteps = params.firstOrNull() ?: 0
            for (i in 1..totalSteps) {
                try {
                    // 模拟耗时操作,例如睡眠 1 秒
                    Thread.sleep(1000)
                } catch (e: InterruptedException) {
                    e.printStackTrace()
                }
                // 调用 publishProgress() 更新进度,触发 onProgressUpdate()
                publishProgress(i)
            }
            // 返回任务完成后的结果
            return "任务完成,共计 $totalSteps 秒"
        }

        // 在主线程中接收并更新任务进度
        override fun onProgressUpdate(vararg values: Int?) {
            super.onProgressUpdate(*values)
            // 更新 ProgressBar 和 TextView 显示当前进度
            values.firstOrNull()?.let { progress ->
                progressBar.progress = progress * 100 / (intent.getIntExtra("TOTAL_STEPS", 10))
                textView.text = "当前进度: $progress/${intent.getIntExtra("TOTAL_STEPS", 10)}"
            }
        }

        // 在任务执行完毕后调用,传入 doInBackground() 返回的结果
        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)
            textView.text = result
        }

        // 可选:任务取消时调用
        override fun onCancelled() {
            super.onCancelled()
            textView.text = "任务取消"
        }
    }
}

代码说明

  • onPreExecute()
    初始化 ProgressBar 和 TextView 的显示状态。
  • doInBackground()
    在后台执行一个简单的循环操作,每次循环暂停 50 毫秒,并调用 publishProgress() 更新 UI 的进度。
  • onProgressUpdate()
    接收到进度后,在主线程更新 ProgressBar 和 TextView。
  • onPostExecute()
    当任务执行完毕后,显示完成消息。

4. 注意事项与最佳实践

  • 内存泄漏问题
    如果 AsyncTask 是作为 Activity 的内部类存在,当 Activity 被销毁时可能导致内存泄漏。建议将 AsyncTask 定义为静态内部类,并通过 WeakReference 持有 Activity 的引用。
  • 执行策略
    在 API 11(Android 3.0)及以上版本,AsyncTask 默认串行执行。如果需要并行执行,可以使用 executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
  • 已弃用提醒
    从 Android 11 开始,AsyncTask 已被弃用,建议在新项目中使用 Kotlin 协程、WorkManager 或其他异步方案。

5. 为什么推荐 Kotlin 协程?

  • 代码简洁
    Kotlin 协程可以让异步代码写得像同步代码,减少回调层级和代码冗余。
  • 更好的错误处理与取消机制
    协程内置了结构化并发,便于管理任务生命周期和异常处理。
  • 官方支持
    谷歌和 JetBrains 都推荐在 Android 项目中使用 Kotlin 协程来处理异步任务。

6. 总结

本文详细介绍了在 Kotlin 中使用 AsyncTask 的方法,包括各个生命周期回调的作用和示例代码。虽然 AsyncTask 曾经为 Android 异步处理提供了简化方案,但随着技术的发展,Kotlin 协程已成为更推荐的选择。在学习 AsyncTask 的同时,建议大家尽快熟悉并尝试使用 Kotlin 协程以提升代码的简洁性和可维护性。

Author: GoshenC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值