Android:多线程

基本的两种方式:

Android 的多线程使用方式 与 Java多线程类似

  1. 继承Thread类 重写 run() 方法,实例化后调用start()开启线程
kotlin 复制代码
// 1. 定义继承 Thread 的子类
class MyThread : Thread() {
    override fun run() {
        // 线程要执行的任务
        println("线程运行中: ${Thread.currentThread().name}")
    }
}

// 2. 使用示例
fun main() {
    val thread = MyThread()   // 创建线程实例
    thread.start()            // 启动线程
}
  1. 实现 Runnable接口 实现 run() 方法
kotlin 复制代码
// 1. 定义实现 Runnable 接口的类
class MyRunnable : Runnable {
    override fun run() {
        // 线程要执行的任务
        println("Runnable 线程运行中: ${Thread.currentThread().name}")
    }
}

// 2. 使用示例
fun main() {
    val runnable = MyRunnable()   // 创建 Runnable 实例
    val thread = Thread(runnable) // 将 Runnable 传给 Thread, 这是一种向上转型
    thread.start()                // 启动线程
}

Kotlin 你内置一个更为简单的顶层函数 thread{ 线程逻辑 }

kotlin 复制代码
import kotlin.concurrent.thread

fun main() {
    thread {
        // 线程逻辑
        println("线程运行中: ${Thread.currentThread().name}")
    }
}

子线程中 UI 的更新

Android 的UI是线程不安全的 (修改一个UI是多步骤的,多线程会错乱)。

如果 想要更新程序里的UI元素,必须在主线程中进行,否则 会出现异常。

Android提供了一套 异步消息处理机制 ,解决了子线程中进行UI操作的问题。(另外一种简单的方式 runOnUiThread 可以在子线程切换为主线程进行UI更新,底层就是异步消息处理机制)

异步消息处理机制

四个部分组成:

  • Message:
    在不同线程之间传递的数据(少量信息)。有what、arg1、arg2(携带整型)、 obj(携带Object对象)字段
  • Handler:
    用于发送和处理消息的。
    发送消息 对应Handler的 sendMessage()方法、post()方法等;
    发送的消息经过一些列处理后会传递到Haandler的 handleMessage() 方法中
  • MessageQueue:
    消息队列。存放所有通过Handler发送的消息。这些消息一直存于消息队列中,等待被处理。
    每个线程只有一个MessageQueue对象
  • Looper:
    每个线程中的MessageQueue的管家,调用Looper的 loop() 方法后,就会进入无限循环,然后每当发现 MessageQueue 中存在一条消息时,就会将他取出,并传递到Handler的 handleMessage() 方法中。
    每个线程一个Looper对象

异步消息处理机制的流程:

流程1:
UI线程(主线程) Looper MessageQueue Handler 子线程 UI线程(主线程) Looper MessageQueue Handler 子线程 Handler持有主线程Looper的引用 安全更新UI loop 无限循环 1. 创建Message对象并调用 sendMessage(msg) 2. 将消息放入主线程的消息队列 3. 通知有新消息 4. 不断取出下一条消息 5. 返回消息 6. 通过消息的target回调 Handler.dispatchMessage() 7. 执行 handleMessage() (主线程运行)

流程2:
主线程
子线程
消息入队
创建Message
调用Handler.sendMessage
MessageQueue
Looper.loop
从队列取消息
通过target找到Handler
Handler.handleMessage
安全更新UI

代码示例,子线程点击按钮changeTextBtn更新textView的文本:

kotlin 复制代码
class MainActivity : AppCompatActivity() {

    // 自定义消息标识(what),用于在 handleMessage 中区分不同类型的消息
    val updateText = 1

    /**
     * 创建 Handler 对象,并显式绑定到主线程的 Looper。
     * 
     * 异步消息处理机制的核心角色:
     * - Looper:消息循环器,每个线程只能有一个 Looper,负责不断从 MessageQueue 中取出消息并分发给 Handler。
     * - MessageQueue:消息队列,遵循 FIFO 原则,存放待处理的消息。
     * - Handler:消息的发送者与处理器。我们重写其 handleMessage 方法定义如何处理收到的消息。
     * 
     * 传入 Looper.getMainLooper() 后,该 Handler 会关联主线程的消息队列。
     * 因此,handleMessage 中的代码将在主线程中执行,可以安全地更新 UI。
     */
    val handler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            // 此方法运行在【主线程】,Android 允许在此直接操作 UI 组件
            when (msg.what) {
                updateText -> textView.text = "Nice to meet you"   // 更新 TextView 文本
                // 可添加更多消息类型的分支处理
            }
        }
    }

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

        // 为按钮设置点击监听器
        changeTextBtn.setOnClickListener {
            /**
             * 启动一个【子线程】(非 UI 线程)。
             * 注意:子线程中绝对不能直接操作 UI,否则会抛出 CalledFromWrongThreadException。
             */
            thread {
                // 模拟耗时操作(如网络请求、数据库查询等)
                // Thread.sleep(1000)   // 可在此添加延迟,模拟任务执行

                // 1. 创建消息对象(推荐使用 Message.obtain() 重用对象,节省内存)
                val msg = Message()
                // 2. 设置消息标识,告诉 Handler 要执行哪个操作
                msg.what = updateText
                // 可选:可以通过 msg.obj 携带任意数据,例如 msg.obj = "some data"

                // 3. 通过 Handler 将消息发送到主线程的消息队列
                //    handler 内部会把消息放入【主线程的 MessageQueue】中,
                //    主线程的 Looper 不断轮询队列,一旦取到该消息,就会回调 handler 的 handleMessage 方法。
                handler.sendMessage(msg)

                // 也可以使用 handler.sendEmptyMessage(updateText) 一步完成创建和发送
            }
        }
    }
}
相关推荐
Kapaseker几秒前
Boolean 变量到底该怎么命名?
android·kotlin
雾屿_Mistisle13 分钟前
文件包含漏洞(File Inclusion)
android
小孔龙1 小时前
Android 图形系统全景
android·计算机图形学
2501_915921431 小时前
详细解析,iOS 应用上架 App Store 的完整流程与指南
android·ios·小程序·https·uni-app·iphone·webview
qq_425516181 小时前
录音转文字工具免费下载:免费额度与功能限制对比
android·人工智能·智能手机·powerpoint
plainGeekDev1 小时前
Robolectric → 分层测试:测试策略重构
android·java·kotlin
plainGeekDev1 小时前
Instrumentation → Compose Testing
android·java·kotlin
sz_denny2 小时前
android aab导出apk
android
码上有光2 小时前
make和makefile(自动化构建)
android·运维·自动化
艾莉丝努力练剑2 小时前
【MYSQL】MYSQL学习的一大重点:视图
android·服务器·数据库·学习·mysql·面试·视图