基本的两种方式:
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) 一步完成创建和发送
}
}
}
}