Android的消息机制(源码篇)
2017-12-27 23:47
134 查看
大致流程
将当前线程转成Looper线程;Handler发送消息,插到MessageQueue(消息队列);looper进入循环,如果在消息队列中拿到Message就交给Handler,如果消息队列中没有消息则阻塞。线程的分类及通信
我们都比较明白线程可分为主线程和工作线程,还有线程之间的通信分为主线程与工作线程、工作线程与工作线程(比较少听到)。相关的对象
在上一篇基本都有提到,在这继续说一下Message:线程间通信的信息,是消息的载体;
MessageQueue:消息队列,用于存放Handler发送的消息,里面是一个链表结构,每个线程只有一个MessageQueue对象
Looper:每个线程通过发送Message保存在MessageQueue中,Looper用于去消息队列中拿取消息;有两个重要的方法:prepare()方法,创建Looper对象并将其设置到ThreadLocal中; loop()方法,产生无限循环,每当发现一个消息,就从队列中拿取出来,最后传到Handler的handleMessage方法中。
Handler:用于发送消息和处理消息;sendMessage方法、sendXXX等方法,最终是调用sendMessageAtTime方法;除了sendMessageAtFrontOfQueue方法;只要在Looper线程中构建Handler,那么这个Handler实例就会获取该Looper线程中的MessageQueue实例的引用,此后调用sendMessage方法就会通过此引用往消息队列插入消息。
附上自己画的一张图,有点丑,但可以将就将就
Handler的创建
1.在主线程中创建Handler handler=new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { return false; } });
2.在工作线程中创建
new Thread(new Runnable() { @Override public void run() { //创建Looper Looper.prepare(); Handler handler=new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { return false; } }); //开始循环 Looper.loop(); } });
问题:为什么子线程需要调用Looper.prepare()和Looper.loop()。这也是我刚开始不理解的地方。后来参考别的文章和阅读源码才知道。
Looper.prepare():
private static void prepare(boolean quitAllowed) { //防止此方法执行两次 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } //将Looper对象设置到ThreadLocal中 sThreadLocal.set(new Looper(quitAllowed)); }
其中的ThreadLocal在上一篇有讲过用法;主要是在不同线程中设置不同的值。
Looper的构造方法
private Looper(boolean quitAllowed) { //初始化消息队列和指定为当前线程 mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
loop方法
public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) {//在这里进入循环,一直查看队列有没有消息 Message msg = queue.next(); // might block if (msg == null) { //队列没有消息则跳出 return; } // This must be in a local variable, in case a UI event sets the logger final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { //msg.target为Handler,此方法为将消息分发 msg.target.dispatchMessage(msg); } finally { …… msg.recycleUnchecked(); } }
这个方法比较长,省略了其中一小部分的代码。
它的作用主要是进入死循环,从消息队列获取消息,如果消息队列没有消息则会停止循环。如果有找到就进行消息的分发
dispatchMessage方法
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) {//这里就回调了handleMessage方法 if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg);//查看源码是一个空实现 } }
进入此方法可知道如果创建Handler时有传进去Callback,则Callback回调了handleMessage方法。否则最后会回调Handler本身的handleMessage方法。
sendMessage方法:跟踪到最后是调用sendMessageAtTime方法
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } //调用自己的方法 return enqueueMessage(queue, msg, uptimeMillis); }
enqueueMessage方法:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } //这里就是将消息加入消息队列 return queue.enqueueMessage(msg, uptimeMillis); }
消息队列中的enqueueMessage方法
boolean enqueueMessage(Message msg, long when) { …… //同步,因为可能同时有多个消息加入(在不同线程中) synchronized (this) { …… Message p = mMessages; boolean needWake; //插入消息,分两种情况(消息队列为空/不为空) if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) {//排列消息 prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } if (needWake) {//唤醒线程(Looper循环) nativeWake(mPtr);//此方法是一个native的方法 } } return true; }
从上面代码可知,往消息队列插入消息时,会分两种情况去插入消息,如果消息队列本身是空的,在最后则会唤醒主线程去处理消息
Handler的创建:
public Handler(Callback callback, boolean async) { …… mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
这里顺便跟踪一下myLooper方法
public static @Nullable Looper myLooper() { //从ThreadLocal中拿到Looper对象 return sThreadLocal.get(); }
总结
通过以上源码的分析,我们可以得出两点可以知道为什么在创建Handler前要执行Looper.prepare方法。(因为没有先执行Looper.prepare()会抛异常)
Handler一创建便持有本线程的消息队列和Looper对象,所以它可以在其他线程中发送消息,最后还是会回到创建时的线程(调用HandleMessage方法)。
疑惑
不知你也会跟我一样又产生一个疑惑,在主线程中创建Handler对象不需要调用Looper.prepare和Looper.loop。
查看了文章才大概明白了是为什么。在Activity的创建过程,走到ActivityThread中的main方法public static void main(String[] args) { …… Looper.prepareMainLooper();//!!! ActivityThread thread = new ActivityThread(); thread.attach(false); …… Looper.loop();//!!! throw new RuntimeException("Main thread loop unexpectedly exited"); }
原来是在主线程中系统会执行:Looper.prepareMainLooper()和Looper.loop();
到此消息机制的源码分析也差不多啦,可能被我拆得比较碎,但希望我们都可以从中学习到东西。
相关文章推荐
- 源码篇——Handler消息机制
- Android:在子线程中更新UI,解析异步消息处理机制(Handler)
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- Android应用程序键盘(Keyboard)消息处理机制分析(9)
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android4.2.2 SurfaceFlinger的相关事件和消息处理机制
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- [看书日记20160106]Activity的Flags , IntentFilter ,Android的消息机制
- Android学习笔记(7)————Android中的消息机制
- Android消息机制底层原理
- Android基础的xml文件创建,解析,以及安卓下的消息机制
- Android消息机制源码解析(一)——消息的载体Message
- 聊一聊Android的消息机制
- Android消息机制 空闲消息处理器
- Android编程实现异步消息处理机制的几种方法总结
- Android Handler 异步消息处理机制的妙用 创建强大的图片加载类
- 个人学习_ Android异步消息处理机制
- Android:消息处理机制(Handler,Message,Looper)分析
- Android消息机制:Looper、Handler、MessageQueue分析
- Android---Handler消息处理机制