註:本文源碼基於android7.0
先大概概括一下消息機制:
這裏有三個角色,Handler、looper、messageQueue。Handler負責發消息和處理消息,Looper負責從MessageQueue中取出消息給Handler處理,MessageQueue則負責存儲Handler發過來的消息。
這個機制主要是將一個任務切換到指定線程中執行,就像我們在子線程中更新UI界面,就可以用Handler。多說一句,特殊情況下子線程中也是可以更新UI的,具體可以看這篇文章,大概意思就是在ViewRootImpl未完全初始化之前更新Android 中子線程真的不能更新 UI 嗎?。
我們從Handler的sendMessage方法入手開始分析:
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }再看sendMessageDelayed方法
public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, systemClock.uptimeMillis() + delayMillis); }
再看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); }從最後一行我們可以看出,Handler的sendMessage方法最終就是往MessageQueue裏插入一條消息。
Looper我們就從Looper.prepare方法來分析
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)); }prepare方法是為當前線程創建一個looper,從那個if語句中我們也知道了為什麽一個線程中只能有一個Looper。sThreadlocal是Threadlocal類型,是一個線程內部的數據存儲類,在該線程存儲的數據只能在該線程中獲取。
接下來我們看Looper.loop方法
public static void loop() { //獲取到當前的Looper final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } //從Looper中得到MessageQueue 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(); //不斷的從MessageQueue取消息,當沒有消息時,next方法會阻塞,直到消息隊列被標記為退出 //這樣next方法會返回null for (;;) { 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); } final long traceTag = me.mTraceTag; if (traceTag != 0) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } //從這裏看到了Handler的消息最終交給它的dispatchMessage方法來處理了 try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } 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(); } }
Tags: Android public return called null
文章來源: