基本的两种方式:
Android 的多线程使用方式 与 Java多线程类似
- 继承Thread类 重写 run() 方法,实例化后调用start()开启线程
kotlin
// 1. 定义继承 Thread 的子类
class MyThread : Thread() {
override fun run() {
// 线程要执行的任务
println("线程运行中: ${Thread.currentThread().name}")
}
}
// 2. 使用示例
fun main() {
val thread = MyThread() // 创建线程实例
thread.start() // 启动线程
}
- 实现 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) 一步完成创建和发送
}
}
}
}