[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()
相关推荐
Mr数据杨7 小时前
【Codex】用学生入学评估模块建立新生能力画像
android·java·javascript·django·codex·项目开发
●VON7 小时前
谁小时候不想要一个游戏修改器?我把电脑 Skill 做成了 Android 小助手
android·游戏·电脑
加农炮手Jinx7 小时前
Flutter for OpenHarmony 实战:flutter_animate 声明式动画让 UI 灵动如原生
flutter·ui·华为·harmonyos·鸿蒙
刃神太酷啦8 小时前
Linux 系统 MySQL 完整安装配置教程:从卸载 MariaDB 到优化 my.cnf----《Hello MySQL!》(1)
android·linux·c语言·c++·mysql·leetcode·mariadb
里欧跑得慢8 小时前
Flutter 三方库 function_tree — 鸿蒙应用开发中的动态数学公式解析与计算神器,实现鸿蒙深度适配下的复杂函数逻辑运行时求值实战(适配鸿蒙 HarmonyOS Next ohos)
android·前端·安全·flutter·华为·harmonyos
IT毕设实战小研8 小时前
基于安卓的空气质量查询系统
android·大数据·vue.js·爬虫·python·django·课程设计
界面开发小八哥9 小时前
界面控件DevExpress WinForms中文帮助文档 - 将基于DevExpress的.NET Framework应用迁移至最新版.NET
ui·.net·界面控件·winform·devexpress·ui开发
雨声不在10 小时前
docker-android Android 16 支持与编译修改
android
天空之城--16 小时前
【无标题】
android
兰亭妙微UI设计公司16 小时前
兰亭妙微UI设计公司:移动端列表页设计的3个要素与2种布局
ui