1.消息机制概述html
a.做用:跨线程通讯。android
b.经常使用场景:当子线程中进行耗时操做后须要更新UI时,经过Handler将有关UI的操做切换到主线程中执行。安全
系统不建议在子线程访问UI的缘由:UI控件非线程安全,在多线程中并发访问可能会致使UI控件处于不可预期的状态。而不对UI控件的访问加上锁机制的缘由有:bash
- 上锁会让UI控件变得复杂和低效
- 上锁后会阻塞某些进程的执行
c.四要素:数据结构
Thread(线程):负责调度整个消息循环,即消息循环的执行场所。多线程
存在关系:并发
- 一个Thread只能有一个Looper,能够有多个Handler;
- Looper有一个MessageQueue,能够处理来自多个Handler的Message;
- MessageQueue有一组待处理的Message,这些Message可来自不一样的Handler;
- Message中记录了负责发送和处理消息的Handler;
- Handler中有Looper和MessageQueue;
图片来源:android的消息处理机制之Looper,Handler,Message异步
d.实现方法:ide
实例:Service篇--异步消息处理机制函数
2.消息机制分析
a.工做流程:
Handler.sendMessage()
发送消息时,会经过MessageQueue.enqueueMessage()
向MessageQueue中添加一条消息;Looper.loop()
开启循环后,不断轮询调用MessageQueue.next()
;Handler.dispatchMessage()
去传递消息,目标Handler收到消息后调用Handler.handlerMessage()
处理消息。简单来看,即
Handler
将Message
发送到Looper
的成员变量MessageQueue
中,以后Looper
不断循环遍历MessageQueue
从中读取Message
,最终回调给Handler
处理。如图:
b.工做原理:
ActivityThread.main()
看起,在这里(主线程)系统自动建立了Looper,主要方法://主线程中不须要本身建立Looper
public static void main(String[] args) {
......
Looper.prepareMainLooper();//为主线程建立Looper,该方法内部又调用 Looper.prepare()
......
Looper.loop();//开启消息轮询
......
}
复制代码
注意:
- 子线程的Looper须要手动去建立,标准写法是:
//子线程中须要本身建立一个Looper
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();//为子线程建立Looper
Looper.loop(); //开启消息轮询
}
}).start();
复制代码
- 不管是主线程仍是子线程,Looper只能被建立一次,即一个Thread只有一个Looper。
- 所建立的Looper会保存在ThreadLocal(线程本地存储区)中,它不是线程,做用是帮助Handler得到当前线程的Looper。更多讲解见ThreadLocal详解
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
复制代码
Looper.loop()
开启消息轮询:public static void loop() {
......
for (;;) {//死循环
Message msg = queue.next(); //用于提取下一条信息,该方法里一样有个for(;;)死循环,当没有可处理该Message的Handler时,会一直阻塞
if (msg == null) {
return;
}
......
try {
msg.target.dispatchMessage(msg);//若是从MessageQueue中拿到Message,由和它绑定的Handler(msg.target)将它发送到MessageQueue
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
......
}
复制代码
//第一种:send方式的Handler建立
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
//如UI操做
}
};
//第二种:post方式的Handler建立
Handler handler = new Handler();
复制代码
注意:建立Handler实例以前必须先建立Looper实例,不然会抛RuntimeException。
对于send方式的Handler:建立好一个Message后,调用Handler的如下几种常见的方法来发送消息:
sendEmptyMessage(); //发送空消息
sendEmptyMessageAtTime(); //发送按照指定时间处理的空消息
sendEmptyMessageDelayed(); //发送延迟指定时间处理的空消息
sendMessage(); //发送一条消息
sendMessageAtTime(); //发送按照指定时间处理的消息
sendMessageDelayed(); //发送延迟指定时间处理的消息
sendMessageAtFrontOfQueue(); //将消息发送到消息队头
复制代码
对于post方式的Handler,可在子线程直接调用Handler的如下几种常见方法,使得切换到主线程:
post(Runnable r)
postAtFrontOfQueue(Runnable r)
postAtTime(Runnable r, Object token, long uptimeMillis)
postAtTime(Runnable r, long uptimeMillis)
postDelayed(Runnable r, long delayMillis)
//例如,postDelayed()方法
handler.postDelayed(new Runnable() {
@Override
public void run() {
//如UI操做
}
},300);
复制代码
经过以上各类Handler的发送方法,都会依次调用 Handler.sendMessageDelayed
->Handler.sendMessageAtTime()
->Handler.enqueueMessage()
最终将Message发送到MessageQueue。
至此从源码已走过一遍流程。
推荐阅读:深刻了解Android的消息机制(源码)
最后,将Handler机制汇总到一张图:
如今,这里有一些有关消息机制的Questions,考考本身吧!
但愿这篇文章对你有帮助~