先举个子线程中使用Handler的例子:
package com.haoran.myhandler; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { Looper looper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new Thread(){ @Override public void run() { System.out.println("子线程中打印线程名:"+Thread.currentThread().getName()); Looper.prepare(); looper = Looper.myLooper(); looper.loop(); } }.start(); Handler handler = new Handler(looper){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); System.out.println("主线程中打印线程名:"+Thread.currentThread().getName()); } }; Message message = Message.obtain(); handler.sendMessage(message); } }大家看了这段代码估计会有疑惑,子线程中怎么没有new Looper()? Handler(looper)的构造做了什么操作?
那好,我们debug运行下
其实 从 FrameWork层 MainActivity.class –> Activity.class –> ActivityThread.class –> ActivityThread.class中的内部类(H.class) 和main方法。 Handler消息机制起了很大的作用,从四大组件的启动,模板模式进行生命周期方法的回调,都是消息机制在默默的进行着。从源码层看,安卓主线程在创建过程中,在ActivityManager的main入口,通过自动初始化了一个Looper和Handler以及handleMessage方法进行消息机制 再通过H.class中进行四大组件的消息机制的判断 消息类型定义: 消息处理方法: 我们说了半天的Handler消息机制的重要性好像和Handler消息机制原理没有半毛钱关系,最开始代码引发我们思考的问题依然无法回答。
下面我们从Handler消息机制的UML图,及相关类源码进一步进行分析,先上图:
这张架构图我们可以花时间分型一下,分析他们之间互相持有的关系。哈哈,这里我就简单概述一下,再走一下源码。。。
首先 作为一个合格的助手,Handler里有mQueue和mLooper对象;于是就有了消息队列MessageQueue和轮询器Looper,再将消息Message放在消息队列里面。Message记录着相对应的Handler,MessageQueue里持有Message对象,Looper通过持有的MessageQueue对象,对消息进行轮询读写
图解:
上图的代码大家应该看着不舒服,我把源码截取一点,一起走一遍,不过我们要带着问题走: 1. 消息怎么被发送到消息队列中的? 2. 消息怎么被Handler/Looper处理的? 3. Handler 对象是怎么创建出来的? 4. loop 这个方法什么时候执行? 5. Message 、Handler 、 Looper、 MessageQueue 、 Thread、 ThreadLocal直接的关系是什么呢?
我们知道, handler.sendMessage(Messagemessage)或handler.postRunnable(Runnable runnable);
都是可以发送消息的,其实post底层也是封装了sendMessage方法的,所以我们从handler.sendMessage(Message msg)开始吧 –>go
Mainactivity中 handler.sendMessage(message)
Message message = Message.obtain(); handler.sendMessage(message);点进去 –>Handle.class的sendMessage方法
继续 –> sendMessageDelayed方法 继续 –> sendMessageAtTime方法
这里发现mQueue,按谷歌工程师开发习惯mQueue是Handler.class类里面的成员变量。那么,mQueue是在什么时候被赋值的呢? 我们找一找 –> 发现Handler(Callback callback, boolean async)构造 Handler的其他构造里,同样赋值操作是Looper给的,那么mLooper是如何赋值的呢?
可以通过handler构造外界传递一个,通常我们用无参构造。哈哈,我们的例子里传递了一个looper哦,大家还记得吗? 上图里 mLooper = Looper.myLooper();
那么Looper里的myLooper()方法做了什么操作呢?点点点! –>
??sThreadLocal 又是什么啊?这里留个坑,一会儿填,咱们先刻舟求剑
好了,先回到 sendMessageAtTime方法发现,走了自己的enqueueMessage();方法,–>Handler.class 的enqueueMessage()
发现 –>
走到了MessageQueue.class 的enqueueMessage(Message msg, long when) 方法
这个方法有点长用伪代码解释一下吧
if (p == null || when == 0 || when < p.when) { // 当前发送的message需要马上被处理调,needWake唤醒状态置true } else { // 当前发送的message被排队到其他message的后面,needWake唤醒状态置false } ..... // 是否唤醒主线程 if (needWake) { nativeWake(mPtr); }MessageQueue.enqueueMessage()执行,会往消息队列里添加Message。消息队列MessageQueue按照时间对所有的Message进行排序。 往消息队里里添加Message分为两种情况 1.当前发送的Message位于队列头部。需要马上处理消息。就会把当前的唤醒状态needWake唤醒状态置为true,唤醒主线程,让轮循器取消息。 2.当前发送的Message被排队排到了其他Message的后面。就不需要唤醒主线程了。就会把当前的唤醒状态needWake置为false。不唤醒主线程。
等等,哈哈,我们的Handler.class中enqueueMessage方法还没有分析完毕,细心的同学会发现 – > msg.target = this; 这做了什么操作? //1. Message的target标记为当前发送的Handler //2. Looper取到message根据target把message分发给相应的Handler
至此,我们把Handler的发送,MessageQueue的给消息排队解释完毕了,接下来就是Looper中如何轮询获取消息,并交给Handler处理的
看Looper.class –> 核心Looper.loop()轮循
while (true) {//死循环,轮循取消息 // 取消息,如果没有消息,就阻塞 Message msg = queue.next(); // might block //有可能会阻塞。 ... //取消息。取到消息就发送给Handler msg.target.dispatchMessage(msg); ... }queue.next()方法
Message next() { // Return here if the message loop has already quit and been disposed. // This can happen if the application tries to restart a looper after quit // which is not supported. final long ptr = mPtr; if (ptr == 0) { return null; } int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; if (msg != null && msg.target == null) { // Stalled by a barrier. Find the next asynchronous message in the queue. do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { // Next message is not ready. Set a timeout to wake up when it is ready. nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { // Got a message. mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); return msg; } } else { // No more messages. nextPollTimeoutMillis = -1; } // Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); return null; } // If first time idle, then get the number of idlers to run. // Idle handles only run if the queue is empty or if the first message // in the queue (possibly a barrier) is due to be handled in the future. if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } // Run the idle handlers. // We only ever reach this code block during the first iteration. for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf(TAG, "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } // Reset the idle handler count to 0 so we do not run them again. pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered // so go back and look again for a pending message without waiting. nextPollTimeoutMillis = 0; } }msg.target.dispatchMessage(msg)也就是Handler.dispatchMessage方法
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } dispatchMessage: 先判断 Message 对象上的 callback 是否为空, 如果不为空,执行 callback 上的 run 方法(联想到了handler.postRunnable方法了吗?) 如果为空,让 handler 去处理消息,判断 handler 上的 mCallback 是否为空 ①如果 mCallback 不为空,让 mCallback.handleMessage 方法来处理消息 ②如果 mCallback 为空,才会调用 handler.handleMessage 方法来处理消息哈哈,差不多了,还记得我们留的一个坑吗ThreadLocal看源码吧:)
很像一个map集合啊,就当是一个hashmap集合吧,我们android中把 K设置为thread名,V设置为looper吧
get方法 :
public T get() { // Optimized for the fast path. Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values != null) { Object[] table = values.table; int index = hash & values.mask; if (this.reference == table[index]) { return (T) table[index + 1]; } } else { values = initializeValues(currentThread); } return (T) values.getAfterMiss(this); }set方法 :
public void set(T value) { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values == null) { values = initializeValues(currentThread); } values.put(this, value); }哈哈,再见了,不足的地方咱们一起学习吧
