[Android]在后台线程执行耗时操作,然后在主线程更新UI

1.Coroutines(官方推荐)

Coroutines 提供了一种轻量级的线程管理方式,使得在后台线程执行任务和在主线程更新 UI 变得简单。以下是如何在 Kotlin 中使用 Coroutines 来处理耗时逻辑并更新 UI 的步骤:

添加 Coroutines 依赖:

首先,确保你的 Android 项目中包含了 Coroutines 的依赖。在你的 build.gradle 文件中添加:

Kotlin 复制代码
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")

版本查询:Maven Central

使用 CoroutineScope 启动协程:

你可以在 Activity 或 Fragment 中通过定义一个 CoroutineScope 来启动协程。通常,在 Android 中,我们使用 lifecycleScope (对于 Activities 和 Fragments)或 viewModelScope (在 ViewModel 中)来自动管理协程的生命周期。

Kotlin 复制代码
import kotlinx.coroutines.*

class MyActivity : AppCompatActivity() {

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

        lifecycleScope.launch {
            performLongRunningTask()
        }
    }

    private suspend fun performLongRunningTask() {
        // 运行在后台线程
        withContext(Dispatchers.IO) {
            // 模拟耗时操作
            Thread.sleep(2000)
            // 计算或数据处理
        }
        
        // 更新 UI 必须在主线程执行
        withContext(Dispatchers.Main) {
            // 更新 UI 组件
            findViewById<TextView>(R.id.textView).text = "Update completed"
        }
    }
}

在这个例子中,performLongRunningTask 函数使用 withContext(Dispatchers.IO) 来指定代码块应该在 IO 调度器(通常用于磁盘和网络操作的线程池)上运行。耗时操作完成后,使用 withContext(Dispatchers.Main) 切换回主线程来更新 UI。

2.runOnUiThread

runOnUiThread 是 Activity 类中的一个方法,它被用来确保一段代码块在主线程(也称为 UI 线程)上执行。这是处理 UI 更新的一种常见方法,特别是当你在后台线程中完成一些处理,并需要将结果安全地更新到 UI 上时。

使用示例:

Kotlin 复制代码
class MyActivity : AppCompatActivity() {

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

        Thread {
            // 执行一些耗时的任务
            val result = performLongRunningTask()

            // 现在需要更新UI
            runOnUiThread {
                // 这部分代码在主线程执行,可以安全地更新UI
                findViewById<TextView>(R.id.textView).text = result
            }
        }.start()
    }

    private fun performLongRunningTask(): String {
        // 模拟耗时操作
        Thread.sleep(2000)
        return "Operation Completed"
    }
}

工作机制:

  • 当你从非 UI 线程调用 runOnUiThread 方法时,它将传入的 Runnable 对象排队到主线程的消息队列中。主线程将在处理其他 UI 任务时,按顺序处理这些消息。

  • 如果 runOnUiThread 是在主线程本身调用的,那么 Runnable 将被立即执行。

使用场景和注意事项:

使用场景:

当你在后台线程中完成任务后需要在 UI 上显示结果时,可以使用 runOnUiThread。例如,在网络请求完成后更新界面。

注意事项:

保证只在需要修改 UI 的时候使用 runOnUiThread,避免在主线程上执行耗时的操作,这样可以避免界面卡顿。

虽然 runOnUiThread 是一个方便的工具,但在处理复杂的异步逻辑时,使用 Kotlin Coroutines 或 RxJava 可能是更好的选择,因为它们提供了更好的控制机制和错误处理能力。

3.RxJava

RxJava 是一个在 Java VM 上使用可观测序列来组成异步和基于事件的程序的库,它非常适合用于复杂的线程操作和数据流处理。

Kotlin 复制代码
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.schedulers.Schedulers

Observable.fromCallable {
    // 在后台线程执行耗时操作
    Thread.sleep(2000)
    "Operation Completed"
}
.subscribeOn(Schedulers.io())  // 指定上游操作在 IO 线程
.observeOn(AndroidSchedulers.mainThread())  // 指定下游操作在主线程
.subscribe { result ->
    textView.text = result  // 更新 UI
}

4.Handler

Handler 是 Android 中处理线程间通信的一种方式,尤其适用于从后台线程发送数据到主线程。

Kotlin 复制代码
val handler = Handler(Looper.getMainLooper())

Thread {
    // 执行耗时操作
    Thread.sleep(2000)  // 模拟耗时操作
    val message = "Operation Completed"

    // 使用 Handler 切回主线程
    handler.post {
        textView.text = message
    }
}.start()

5.AsyncTask(deprecated)

AsyncTask 是 Android 提供的一个抽象类,用于处理后台任务并在主线程上发布结果。不过,需要注意的是,从 Android API level 30 开始,AsyncTask 已被标记为过时(deprecated),因为它不推荐用于现代 Android 开发。尽管如此,了解它的使用仍然对理解 Android 异步编程模型有帮助。

Kotlin 复制代码
class MyAsyncTask(private val textView: TextView) : AsyncTask<Void, Void, String>() {
    override fun doInBackground(vararg params: Void?): String {
        // 在后台线程执行耗时操作
        Thread.sleep(2000)  // 模拟耗时操作
        return "Operation Completed"
    }

    override fun onPostExecute(result: String) {
        // 在主线程更新 UI
        textView.text = result
    }
}

// 在 Activity 或 Fragment 中使用
MyAsyncTask(textView).execute()
相关推荐
三少爷的鞋1 小时前
Kotlin 协程,重点就在「协」这个字上
android·kotlin
好的佩奇1 小时前
Dart 之模式
android·flutter·dart
淡淡的香烟3 小时前
Flutter实现多语言切换
android·flutter·1024程序员节
xy34534 小时前
Axure 9.0 列表框 介绍
ui·axure·原型·产品设计
xy34534 小时前
Axure 9.0 内联框架加载方式
前端·ui·html·axure·原型·产品设计
AIsoft_86895 小时前
手机视频转文字工具清单:哪些APP支持录屏识别
android·音视频
_祝你今天愉快8 小时前
Paint Cavans高级绘制:[一]Paint画笔高级应用
android
特立独行的猫a8 小时前
仓颉语言cj-tauri 跨端开发框架实战:给鸿蒙侧加一个「读设备电量」的原生能力
ui·harmonyos·tauri·1024程序员节·仓颉·鸿蒙pc
@zulnger8 小时前
安卓进行稳定性测试
android·appium·1024程序员节
不吃凉粉9 小时前
android 副屏连接
android