提到Android里的消息机制,便会提到Message、Handler、Looper、MessageQueue这四个类,我先简单介绍如下这4个类
之间的爱恨情仇。java
消息的封装类,里边存储了消息的详细信息,以及要传递的数据shell
主要用在消息的发送上,有即时消息,有延迟消息,内部还提供了享元模式封装了消息对象池,可以有效的减小重复对象的建立,留更多的内存作其余的事,app
这个类内部持有一个MessageQueue对象,当建立Looper的时候,同时也会建立一个MessageQueue,而后Looper的主要工做就不断的轮训MessageQueue,轮到天荒地老的那种less
内部持有一个Message对象,采用单项链表的形式来维护消息列队。而且提供了入队,出队的基础操做异步
举个现实中的栗子,Message就至关于包装好的快递盒子,Handler就至关于传送带,MessageQueue就至关于快递车,Looper就至关于快递员,联想一下,来个快递盒子,biu丢到传送带上,传送带很智能,直接传送到快递三轮车里,而后快递小哥送一波~,日夜交替,不分昼夜的工做,好家伙,007工做制async
好,咱们把这4个家伙从头到位分析一遍,要想使用Android的消息,首先要建立Looper对象,Android系统已经帮咱们在UI线程内建立好了一个,咱们能够看一下ide
public final class ActivityThread extends ClientTransactionHandler { /** * The main entry point from zygote. */ public static void main(String[] args) { Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } }
ActivityThread
这个类你们应该不陌生吧,没错,他就是咱们App的主线程管理类,咱们看到他调用了 prepareMainLooper
来初始化,而后 loop
,天荒地老的那种loop,这个loop
,咱们最后聊函数
咱们看一下Looper内部提供的 prepareMainLooper
实现oop
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); } private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
上边涉及到了3个方法,我都贴出来了,首先 quitAllowed
这个参数表明该Looper是否能够退出,咱们主线程内的Looper是不容许退出的,因此封装了 prepareMainLooper
方法和 prepare
方法已作区分,咱们项目中平时用的都是 prepare
方法,由于是子线程,因此容许退出Looper,你们在子线程内用完记得调用quit哦~
这里咱们看Looper内部是经过ThreadLocal维护的Looper对象,也就是说每一个线程都是相互独立的。并且Looper作了限制,每一个线程内部只能存在一个Looper对象,等同于每一个线程内只能有一个MessageQueue
最后在Looper的构造方法内,建立了一个MessageQueue对象,整个Looper的初始化就结束了ui
咱们准备好了Looper和MessageQueue后,就能够建立消息啦,接下来咱们建立一个消息吧
//直接new对象,不推荐的方式 Message msg = new Message(); //推荐:内部是一个复用对象池 Message message = handler.obtainMessage(); message.what = 1; message.obj = "hello world";
咱们发送消息的时候,都是会借助Handler的sendMessage就能够把消息发送到列队里了,咱们往下看是如何完成的入队操做吧,首先咱们平时都是建立一个Handler,而后调用sendMessage
就能够了
Handler handler = new Handler(); handler.sendMessage(message);
咱们先看一下Handler的构造方法
public Handler() { this(null, false); } public Handler(@Nullable Callback callback, boolean async) { //FIND_POTENTIAL_LEAKS一直都是false,因此不用关心这个逻辑 if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } //获得当前线程下的Looper对象 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()"); } //从Loopper内部获取一个列队 mQueue = mLooper.mQueue; // 回调对象,咱们平时写的时候,通常都是用类集成的方式重写 handleMessage 方法 mCallback = callback; //标示当前Handler是否支持异步消息 mAsynchronous = async; }
其实构造方法很简单呐,就是获取Looper对象,而后初始化列队和回调对象就完事了,咱们继续看sendMessage而后看消息的入队吧
public final boolean sendMessage(@NonNull Message msg) { return sendMessageDelayed(msg, 0); } public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } public boolean sendMessageAtTime(@NonNull 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); }
经过内部的重载方法,一直调用到sendMessageAtTime
方法,在这里获得Handler内部的MessageQueue
对象,而后调用了 enqueueMessage
方法准备入队
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) { msg.target = this; msg.workSourceUid = ThreadLocalWorkSource.getUid(); if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
这里调用了MessageQueue的enqueueMessage
方法真正入队,咱们继续看一下
boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } synchronized (this) { //若是当前退出状态,则回收消息,并返回消息入队失败 if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w(TAG, e.getMessage(), e); msg.recycle(); return false; } msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; //若是链表是空的,或者当前消息的when小于表头的when的时候,便会从新设置表头 //这里能够得知,消息的顺序是按照延迟时间,从小往大排序的 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 { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. 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放到链表最后 msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
经过这个方法,咱们了解到MessageQueue是经过Message的单链结构存储的,而后每次入队的时候,都会
经过这个enqueueMessage
方法向链表的最末尾添加数据。
最后咱们聊一下Looper下的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(); // Allow overriding a threshold with a system prop. e.g. // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start' final int thresholdOverride = SystemProperties.getInt("log.looper." + Process.myUid() + "." + Thread.currentThread().getName() + ".slow", 0); boolean slowDeliveryDetected = false; for (;;) { //queue的next会阻塞 Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. 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); } // Make sure the observer won't change while processing a transaction. final Observer observer = sObserver; final long traceTag = me.mTraceTag; long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs; if (thresholdOverride > 0) { slowDispatchThresholdMs = thresholdOverride; slowDeliveryThresholdMs = thresholdOverride; } final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0); final boolean logSlowDispatch = (slowDispatchThresholdMs > 0); final boolean needStartTime = logSlowDelivery || logSlowDispatch; final boolean needEndTime = logSlowDispatch; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0; final long dispatchEnd; Object token = null; if (observer != null) { token = observer.messageDispatchStarting(); } long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid); try { //派发消息,执行回调handleMessage msg.target.dispatchMessage(msg); if (observer != null) { observer.messageDispatched(token, msg); } dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } catch (Exception exception) { if (observer != null) { observer.dispatchingThrewException(token, msg, exception); } throw exception; } finally { ThreadLocalWorkSource.restore(origWorkSource); if (traceTag != 0) { Trace.traceEnd(traceTag); } } if (logSlowDelivery) { if (slowDeliveryDetected) { if ((dispatchStart - msg.when) <= 10) { Slog.w(TAG, "Drained"); slowDeliveryDetected = false; } } else { if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery", msg)) { // Once we write a slow delivery log, suppress until the queue drains. slowDeliveryDetected = true; } } } if (logSlowDispatch) { showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg); } if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycleUnchecked(); } }
Looper内的loop方法别看这么多,大多数都是日志相关的处理。其实他就两件事
第一件事就是从列队中经过next
取出Message对象
第二件事就是经过Message对象上绑定的target对象dispatchMessage
方法,来分发消息
咱们接下来看一下dispatchMessage
方法,而后在看MessageQueue的next
public void dispatchMessage(@NonNull Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
灰常简单,判断CallBack对象。而后调用handleMessage就完事了,咱们的Activity就收到数据了。
接下来咱们看看MessageQueue的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) { 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; } }
首先MessageQueue的消息是用单链表的形式存储,而后next函数作的事情就是死循环获取消息,
在获取消息的时候判断一下消息是否符合执行时间,若是不符合执行时间,就进入睡眠状态等待消息。
若是符合执行时间就直接返回Message给Looper进行分发,若是Message链表都为空。则睡眠时间是-1
表明无休止的睡眠。在无休止睡眠的状态下,enqueueMessage
的nativeWake
方法,会进行一次唤醒,唤醒后next
函数继续执行,判断返回消息给Looper执行消息分发