Handler主要用于線程切換,一個(gè)典型的應(yīng)用場(chǎng)景是:子線程通過(guò)Handler更新主線程UI 本文將從源碼上來(lái)介紹Handler的實(shí)現(xiàn)原理 簡(jiǎn)書地址:http://www.jianshu.com/p/bb078eac0190
先看一張圖:

主要流程如下: * 構(gòu)造Message對(duì)象 * 通過(guò)Handler將Message發(fā)送到MessageQueue * Looper從MessageQueue里取出Message對(duì)象 * Looper調(diào)用Message對(duì)象里保存的Handler對(duì)象的dispatchMessage方法將Message的處理移交給Handler
那么Looper和MessageQueue是哪來(lái)的呢?看一下Handler的構(gòu)造方法:
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();//獲取Handler所在線程的Looper。 if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.如果mLooper為空則直接拋異常了,所以如果不是在主線程創(chuàng)建Handler之前一定要在子線程里調(diào)用Looper.prepare()準(zhǔn)備好一個(gè)Looper。Looper.prepare()會(huì)調(diào)用Looper的構(gòu)造方法創(chuàng)建一個(gè)Looper,在Looper的構(gòu)造方法中又創(chuàng)建了一個(gè)MessageQueue。下面通過(guò)源碼來(lái)看這幾個(gè)步驟是如何實(shí)現(xiàn)的


或者,直接
Message message = new Message();各種方式在使用效果上最后的差別不大,任選其一即可。
左右的發(fā)送消息的方法最終都調(diào)用到了這個(gè)方法,顧名思義,這個(gè)方法將Message對(duì)象添加到MessageQueue隊(duì)列,在入隊(duì)之前,將message的target對(duì)象賦值為當(dāng)前handler對(duì)象,最后會(huì)通過(guò)這個(gè)target對(duì)象來(lái)處理這個(gè)message。
//MessageQueueboolean 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; 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.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其實(shí)是一個(gè)單鏈表,所以很多操作都是單鏈表的操作。如果p==null(當(dāng)前隊(duì)列為空)或者when==0(通過(guò)sendMessageAtFrontOfQueue方法發(fā)送的消息)或者when
//Handlerpublic final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }當(dāng)創(chuàng)建好Looper后,會(huì)調(diào)用Looper.loop()方法不斷的從MessageQueue里讀取Message,如果是主線程,那么Looper.loop()方法在系統(tǒng)創(chuàng)建進(jìn)程的時(shí)候就已經(jīng)調(diào)用過(guò)了,如果在子線程則需要自己調(diào)用。
//Looperpublic 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; ...省略 for (;;) { //從隊(duì)列里取出消息 Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } ...省略 try { //將msg的處理移交給Handler msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } ...省略 } } Message msg = queue.next(); // might block 通過(guò)一個(gè)無(wú)限的for循環(huán)中通過(guò)MessageQueue.next()讀消息,如果隊(duì)列沒(méi)有消息則阻塞。在next方法中,如果隊(duì)首的消息執(zhí)行時(shí)間還沒(méi)到,就設(shè)置一個(gè)等待時(shí)間,如果到了就從鏈表里取出來(lái),然后返回。
在Loopermsg.target.dispatchMessage(msg)讓Handler去處理,這里的target就是在調(diào)用Handler.的enqueueMessage方法時(shí)賦值得,忘記了可以去步驟2里再看一下。
至此,處理流程又回到了Handler的dispatchMessage方法里,邏輯很簡(jiǎn)單,一個(gè)細(xì)節(jié)要注意,如果mCallback不為空,是不會(huì)調(diào)用handleMessage,這里mCallback是在創(chuàng)建Handler的時(shí)候就傳進(jìn)來(lái)的,所以使用Handler處理消息,要么在創(chuàng)建Handler的時(shí)候傳入一個(gè)Callback,要么重寫handleMessage方法。
//Handler /** * 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); } } private static void handleCallback(Message message) { message.callback.run(); } /** * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { }新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注