Android消息机制是Android系统中处理线程间通信的核心部分。它通过消息队列(MessageQueue)和处理器(Handler)来实现异步处理任务,从而避免在主线程中进行耗时操作,保证应用的流畅性和响应性。
消息机制模型
Android消息机制模型就像一个持续运行的邮递系统,快递员(Handler)从仓库(MessageQueue)中取出信件(Message)并处理。
- 消息队列(MessageQueue):这是仓库,用于存储所有待处理的快递包裹(消息)。消息队列按照消息的发送顺序或预定时间进行排序,确保消息能够及时处理。
- 处理器(Handler):快递小哥,负责从信箱中取出信件并处理。每个Handler都关联着一个Looper,它负责管理消息循环。
- 消息(Message):快递包裹,包含要传递的信息和处理的操作。Message对象不仅携带数据,还包含了处理方法的引用,确保消息能够被正确处理。
- 消息循环(Looper):仓库的分拣人员,负责不断地检查信箱,并安排快递小哥取件和送件。每个线程在默认情况下没有Looper,需要调用Looper.prepare()来初始化。
消息机制架构
Handler、Looper和MessageQueue是Android消息处理机制的核心组成部分,它们之间的关系紧密相连。首先,每个线程可以拥有多个Handler,但每个线程只能有一个Looper,这个Looper是线程特有的,存储在ThreadLocal中。在Android的主线程(UI线程)中,系统已经为我们创建了一个Looper,因此我们无需再次创建。然而,在其他线程中,我们需要手动创建Looper。
Looper的作用是不断循环检查其MessageQueue,MessageQueue是Looper用来存储消息队列的容器。这些消息可以来自同一个线程中的不同Handler。简而言之,一个Looper可以处理多个Handler发送的消息,而这些消息都通过Looper所关联的MessageQueue进行管理。
消息机制的组件协同
Looper
Looper
是消息循环的核心。通过Looper.prepare()
方法为当前线程创建一个Looper对象,并初始化消息队列。每个线程可以有一个Looper,它通过不断循环来检查消息队列。
class MessageQueue {
// 假设MessageQueue类已经实现了必要的方法和属性
fun next(): Message? {
// 实现获取下一个消息的逻辑
}
}
class Message {
// 假设Message类已经实现了必要的方法和属性
var target: Handler? = null
fun dispatchMessage(message: Message) {
// 实现消息分发的逻辑
}
}
class Handler {
// 假设Handler类已经实现了必要的方法和属性
}
class Looper {
private val queue: MessageQueue = MessageQueue()
constructor() {
// 在构造函数中初始化Looper
}
companion object {
private val threadLocal: ThreadLocal<Looper> = ThreadLocal()
fun prepare() {
if (threadLocal.get() != null) {
throw RuntimeException("Only one Looper may be created per thread")
}
threadLocal.set(Looper())
}
fun loop() {
val looper = myLooper() ?: throw RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.")
val queue = looper.queue
while (true) {
try {
val message = queue.next() ?: break
message?.target?.dispatchMessage(message)
} catch (e: Exception) {
// 处理异常情况
}
}
}
fun myLooper(): Looper? = threadLocal.get()
}
}
在这段代码中:
prepare()
方法为当前线程创建并设置一个Looper对象。loop()
方法启动消息循环,从消息队列中不断地取出消息并分发给目标Handler进行处理。myLooper()
方法返回当前线程的Looper对象。
MessageQueue
MessageQueue
负责存储和管理消息。消息以链表形式存储,当有新消息加入时,会根据消息的处理时间排序。
class Message {
var when: Long = 0
var next: Message? = null
// 其他必要的属性和方法
}
class MessageQueue {
private var head: Message? = null
fun enqueueMessage(msg: Message, when: Long): Boolean = synchronized(this) {
msg.when = when
var p = head
if (p == null || msg.when < p.when) {
msg.next = p
head = msg
} else {
var prev: Message? = null
while (p != null && msg.when >= p.when) {
prev = p
p = p.next
}
msg.next = prev?.next
prev?.next = msg
}
notifyAll()
true
}
fun next(): Message? = synchronized(this) {
var p = head
while (p == null || p.when > System.currentTimeMillis()) {
wait()
p = head
}
head = p?.next
p?.next = null
p
}
}
在这段代码中:
enqueueMessage()
方法将消息按时间排序加入消息队列。next()
方法从消息队列中取出即将处理的消息,并在队列为空时等待。
Handler
Handler
负责将消息加入队列,并在消息到达时进行处理。通过sendMessage()
方法将消息发送到消息队列,并通过handleMessage()
方法处理消息。
class Handler(looper: Looper) {
private val looper: Looper = looper
private val queue: MessageQueue = looper.queue
fun sendMessage(msg: Message) {
queue.enqueueMessage(msg, System.currentTimeMillis())
}
fun handleMessage(msg: Message) {
}
fun dispatchMessage(msg: Message) {
if (msg.callback != null) {
msg.callback.run()
} else {
handleMessage(msg)
}
}
}
在这段代码中:
sendMessage()
方法将消息发送到消息队列。dispatchMessage()
方法处理消息,优先执行消息的回调方法(Runnable),否则调用handleMessage()
。
这里给出一段简化的Android消息机制源码,用于演示这些组件是如何协同工作的
class Message {
Runnable action;
long when;
// 其他必要的属性和方法
}
class MessageQueue {
private Message mMessages; // 用于模拟消息链表的头
public Message next() {
// 模拟获取下一个消息的逻辑
synchronized (this) {
// 这里只是示例,实际的实现会更复杂
return mMessages; // 返回消息并从队列中移除
}
}
public void enqueueMessage(Message msg, long when) {
// 消息入队的逻辑
}
}
class Handler {
private MessageQueue mQueue;
public Handler(MessageQueue queue) {
mQueue = queue;
}
public void sendMessage(Message msg) {
// 将消息发送到消息队列
mQueue.enqueueMessage(msg, System.currentTimeMillis());
}
public void handleMessage(Message msg) {
if (msg.action != null) {
msg.action.run();
}
}
}
class Looper {
private MessageQueue mQueue;
private boolean mRunning;
public Looper(MessageQueue queue) {
mQueue = queue;
}
public void loop() {
mRunning = true;
while (mRunning) {
Message msg = mQueue.next();
if (msg != null) {
Handler target = msg.getTarget();
if (target != null) {
target.handleMessage(msg);
}
}
}
}
public void quit() {
mRunning = false;
}
}
// 使用示例
MessageQueue queue = new MessageQueue();
Looper looper = new Looper(queue);
new Thread(new Runnable() {
public void run() {
looper.loop();
}
}).start();
消息机制的典型使用
更新UI
使用Handler
在后台线程完成一个耗时操作,然后在主线程更新UI。
import android.os.Handler
import android.os.Looper
import android.widget.TextView
class MainActivity : AppCompatActivity() {
private lateinit var textView: TextView
private val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
// 这里执行UI更新操作
textView.text = msg.obj as String
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView = findViewById(R.id.text_view)
// 模拟后台线程耗时操作
Thread {
// 假设这里进行了一些耗时操作
Thread.sleep(2000)
// 当操作完成时,通过Handler发送消息回主线程
val message = Message()
message.obj = "操作完成,UI已更新"
handler.sendMessage(message)
}.start()
}
}
在这个示例中:
- 定义一个MainActivity类,它继承自AppCompatActivity。
- 在onCreate方法中,设置了布局并获取了布局文件中的TextView控件引用,该控件用于展示文本信息。
- 创建了一个Handler的匿名内部类实例,它与主线程的Looper关联。
- 重写了handleMessage方法,以便在消息到达时执行UI更新操作。具体来说,将TextView的文本内容设置为消息对象中携带的字符串。
- 启动了一个新的线程来模拟一个耗时操作。在这个示例中,使用Thread.sleep方法来模拟耗时过程。
- 当耗时操作完成时,创建了一个Message对象,将操作结果封装为字符串,并设置为消息的对象,然后通过Handler将这个消息发送回主线程。
流程图
总结
以上便是消息机制的原理及组件解析,消息机制的运行过程,可以简单地用下图来理解。