Android Handle原理(Looper,Handler和Message三者關系案例詳解
介紹
前面的內容對Handler做瞭介紹,也講解瞭如何使用handler,但是我們並不知道他的實現原理。本文從源碼的角度來分析如何實現的。
首先我們得知道Handler,Looper,Message Queue三者之間的關系
– Handler封裝瞭消息的發送,也負責接收消。內部會跟Looper關聯。
– Looper 消息封裝的載,內部包含瞭MessageQueue,負責從MessageQueue取出消息,然後交給Handler處理
– MessageQueue 就是一個消息隊列,負責存儲消息,有消息過來就存儲起來,Looper會循環的從MessageQueue讀取消息。
源碼分析
當我們new一個Handler對象的時候,看看他的構造方法裡面做瞭什麼.
public Handler(Callback callback, boolean async) { 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()); } } 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; }
從源碼中我們看到他會調用Looper.myLooper方法獲取一個Looper對象,然後從Looper對象獲取到MessageQueue對象。
Looper myLooper()
跟進去看看Looper.myLooper()方法做瞭什麼。這是一個靜態方法,可以類名.方法名直接調用。
public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
這個方法裡面就一行代碼,從sThreadLocal中獲取一個Looper對象,sThreadLocal是一個ThreadLocal對象,可以在一個線程中存儲變量。底層是ThreadLocalMap,既然是Map類型那肯定得先set一個Looper對象,然後我們才能從sThreadLocal對象裡面get一個Looper對象。
ActivityThread main()
說到這裡得給大傢介紹一個新的類ActivityThread,ActivityThread類是Android APP進程的初始類,它的main函數是這個APP進程的入口。我們看看這個main函數幹瞭什麼事情。
public static final void main(String[] args) { ------ Looper.prepareMainLooper(); if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } ActivityThread thread = new ActivityThread(); thread.attach(false); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); ----- }
在第二行代碼調用Looper.prepareMainLooper()方法,第13行調用瞭Looper.loop()方法。
Looper prepareMainLooper()
繼續跟進Looper.prepareMainLooper()方法,在這個方法中第一行代碼調用瞭內部的prepare方法。prepareMainLooper有點像單例模式中的getInstance方法,隻不過getInstance會當時返回一個對象,而prepareMainLooper會新建一個Looper對象,存儲在sThreadLocal中。
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
Looper prepare()
繼續跟進prepare方法,看第5行代碼,新建瞭一個Looper對象,調用sThreadLocal.set方法把Looper對象保存起來。看到這裡我想聰明的你們肯定明白瞭為什麼new Handler對象的時候調用Looper.myLooper()方法能從sThreadLocal對象中取到Looper對象。
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)); }
Looper 構造方法
文章開頭我們就講到Looper內部包含瞭MessageQueue,其實就是在new Looper對象的時候就new瞭一個MessageQueue對象。
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
Looper loop()
ActivityThread類main方法中調用瞭Looper的兩個方法,前面我們解釋瞭prepareMainLooper(),現在來看第二個方法loop()。
public static void loop() { final Looper me = myLooper();//獲取Looper對象 if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue;//從Looper對象獲取MessageQueue對象 // 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 (;;) {//死循環 一直從MessageQueue中遍歷消息 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 { //調用handler的dispatchMessage方法,把消息交給handler處理 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(); } }
這個方法的代碼呢比較多。我都給代碼加上瞭註釋。其實就是一個死循環,一直會從MessageQueue中取消息,如果取到瞭消息呢,會執行msg.target.dispatchMessage(msg)這行代碼,msg.target就是handler,其實就是調用handler的dispatchMessage方法,然後把從MessageQueue中取到的message傳入進去。
Handler dispatchMessage()
public void dispatchMessage(Message msg) { //如果callback不為空,說明發送消息的時候是post一個Runnable對象 if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) {//這個是用來攔截消息的 if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg);//最終調用我們重寫的handleMessage方法 } }
這個方法對消息做最後處理,如果是post類型調用handleCallback方法處理,如果是sendMessage發送的消息。看我們有沒有攔截消息,如果沒有最終調用handleMessage方法處理。
Handler handleCallback()
看到這裡我們知道為什麼post一個Runnable對象,run方法執行的代碼在主線程瞭吧,因為底層根本就沒有開啟線程,就隻是調用瞭run方法而已。
private static void handleCallback(Message message) { message.callback.run(); }
前面我們從創建handler對象開始,以及創建Looper,創建MessageQueue的整個流程,現在來分析下,當我們調用post以及sendMessage方法時,怎麼把Message添加到MessageQueue。
Handler post()
調用瞭getPostMessage方法,把Runnable傳遞進去。
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
Handler getPostMessage()
首先調用Message.obtain()方法,取出一個Message對象,這個方法之前有講過,然後把Runnable對象賦值瞭Message對象的callback屬性。看到這裡我們也明白瞭dispatchMessage方法為什麼要先判斷callback是否為空瞭吧。
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
Handler enqueueMessage()
在post方法裡面調用瞭sendMessageDelayed方法,其實最終調用的是enqueueMessage方法,所以我這裡就直接看enqueueMessage方法源碼。第一行代碼就把handler自己賦值給messgae對象的target屬性。然後調用MessageQueue的enqueueMessage方法把當前的Messgae添加進去。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
總結
總結:handler負責發送消息,Looper負責接收Handler發送的消息,並直接把消息回傳給Handler自己。MessageQueue就是一個存儲消息的容器。
到此這篇關於Android Handle原理(Looper,Handler和Message三者關系案例詳解的文章就介紹到這瞭,更多相關Android Handle原理(Looper,Handler和Message三者關系內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Android Handler,Message,MessageQueue,Loper源碼解析詳解
- Android消息機制Handler深入理解
- 詳解Android Handler機制和Looper Handler Message關系
- Android Handler源碼深入探究
- Android handle-message的發送與處理案例詳解