源码分析Android Handler是如何实现线程间通信的
?
源碼分析Android Handler是如何實(shí)現(xiàn)線程間通信的
Handler作為Android消息通信的基礎(chǔ),它的使用是每一個(gè)開發(fā)者都必須掌握的。開發(fā)者從一開始就被告知必須在主線程中進(jìn)行UI操作。但Handler是如何實(shí)現(xiàn)線程間通信的呢?本文將從源碼中分析Handler的消息通信機(jī)制。
0x00 Handler使用
首先看看我們平時(shí)是如何使用的Handler的。先看看以下代碼
//定義Handler Handler mHandler = new Handler(){public void handleMessage(Message msg){switch(msg.what){case UPDATE_UI:updateUI(msg);break;}} }; class MyThread extends Thread{public void run(){//do same work!...//send messageMessage msg = mHandler.obtainMessage(UPDATE_UI);mHandler.sendMessage(msg);} }private void updateUI(Message msg){//update UI }在子線程中sendMessage(Message)發(fā)送消息,然后在Handler的handleMessage(Message)接收消息,執(zhí)行更新UI操作。那么Handler是如何把消息從MyThread傳遞到MainThread中來呢?我們從sendMessage()開始慢慢揭開它的面紗。
0x01 sendMessage(Message)
public final boolean sendMessage(Message msg){return sendMessageDelayed(msg, 0); } ... public final boolean sendMessageDelayed(Message msg, long delayMillis){if (delayMillis < 0) {delayMillis = 0;}return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } ... 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); } ... private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis); }我們發(fā)現(xiàn)調(diào)用sendMessage()方法最后都走到enqueueMessage()這個(gè)方法,一開始就把當(dāng)前Handler實(shí)例賦給了Message.target的屬性里面,后面可以知道這個(gè)target是用來執(zhí)行處理函數(shù)回調(diào)的。
enqueueMessage方法是把Message信息放入到一個(gè)MessageQueue的隊(duì)列中。顧名思義MessageQueue就是消息隊(duì)列。從sendMessageAtTime()方法知道這個(gè)MessageQueue是Handler中的一個(gè)成員。它是在Handler的構(gòu)造函數(shù)中通過Loopger對(duì)象來初始化的。
0x02 Handler構(gòu)造函數(shù)
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; }這時(shí)候我們腦海知道創(chuàng)建Handler的時(shí)候,同時(shí)也創(chuàng)建了Looper實(shí)例和MessageQueue引用(MessageQueue對(duì)象其實(shí)是在Looper中構(gòu)造的)。Looper是何物呢?簡(jiǎn)單地說就是消息循環(huán),這個(gè)我們稍后會(huì)分析。
0x03 enqueueMessage(MessageQueue)
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;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;//這里把消息插入到隊(duì)列中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.nextprev.next = msg;}// We can assume mPtr != 0 because mQuitting is false.if (needWake) {nativeWake(mPtr);}}return true; }在MessageQueue中可以看到這個(gè)入列方法中有一個(gè)for循環(huán)就是把當(dāng)前的需要處理Message放到隊(duì)列的合適位置。因?yàn)樾枰幚淼腗essage對(duì)象都有一個(gè)開始處理的時(shí)間when,這個(gè)隊(duì)列是按照when排序的。
至此,Handler調(diào)用sendMessage()方法后就把Message消息通過enqueueMessage()插入MessageQueue隊(duì)列中。
而這個(gè)MessageQueue是在Looper中維護(hù)的。
0x04 prepare()創(chuàng)建Looper
在0x02中我們知道創(chuàng)建Handler時(shí)就使用靜態(tài)方法Looper.myLooper()得到當(dāng)前線程的Looper對(duì)象。
/*** Return the Looper object associated with the current thread. Returns* null if the calling thread is not associated with a Looper.*/ public static @Nullable Looper myLooper() {return sThreadLocal.get(); }sThreadLocal是一個(gè)ThreadLocal類型的靜態(tài)變量。什么時(shí)候會(huì)把Looper對(duì)象放在sThreadLocal中呢?通過prepare()方法。
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)); }繼續(xù)翻閱源碼知道Looper在構(gòu)造函數(shù)中創(chuàng)建MessageQueue對(duì)象
private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread(); }調(diào)用prepare()方法將一個(gè)Looper對(duì)象放在了靜態(tài)的ThreadLocal對(duì)象中。這個(gè)是一個(gè)與線程綁定的對(duì)象,且在內(nèi)存中僅保存了一份引用。
使用ThreadLocal對(duì)象這一點(diǎn)非常巧妙,也非常重要,這是線程間通信的基礎(chǔ)。即在線程中調(diào)用prepare()時(shí)就在該線程中綁定了Looper對(duì)象,而Looper對(duì)象中擁有MessageQueue引用。所以每個(gè)線程都有一個(gè)消息隊(duì)列。
這樣Handler、Looper、MessageQueue這幾個(gè)類關(guān)系大概就可以畫出來了。
0x05 啟動(dòng)循環(huán)loop()
/*** Run the message queue in this thread. Be sure to call* {@link #quit()} to end the 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();//這里執(zhí)行消息隊(duì)列循環(huán)for (;;) {Message msg = queue.next(); // might blockif (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 loggerfinal 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));}//執(zhí)行處理消息的回調(diào)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();} }loop()方法中有一個(gè)無限循環(huán),不停地讀取調(diào)用MessageQueue的next()方法。當(dāng)next()沒有返回時(shí)就阻塞在這里。當(dāng)獲取到MessageQueue中的消息時(shí),就執(zhí)行了處理消息的回調(diào)函數(shù)msg.target.dispatchMessage(msg)。
前面0x01分析我們知道m(xù)sg.target是在Handler中的enqueueMessage()進(jìn)行賦值,即它指向當(dāng)前的Handler實(shí)例。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis); }執(zhí)行msg.target.dispatchMessage(msg)后便走到了以下流程
/*** 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);} }這里就是回調(diào)handleMessage(msg)函數(shù)處理消息的地方。Handler負(fù)責(zé)將Message入列,Looper則負(fù)責(zé)循環(huán)從MessageQueue中取出需要處理的Message并交由Handler來處理。
0x06 啟動(dòng)主線程的消息循環(huán)
我們知道通過靜態(tài)方法Looper.prepare()創(chuàng)建了綁定當(dāng)前線程的Looper對(duì)象,而通過loop()啟動(dòng)一個(gè)循環(huán)不停地讀取隊(duì)列中Message。但是Android系統(tǒng)是什么時(shí)候啟動(dòng)了主線程的消息循環(huán)呢?
要理解這一點(diǎn)就必須進(jìn)入Android應(yīng)用程序的入口ActivityThread的main方法。
public static void main(String[] args) {...Looper.prepareMainLooper();...Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited"); }可以看出main方法中先后執(zhí)行了Looper.prepareMainLooper()方法和Looper.loop()方法。正常情況下main方法不會(huì)退出,只有l(wèi)oop()方法發(fā)生異常后將會(huì)拋出RuntimeException。
0x07 Looper.prepareMainLooper()
/*** Initialize the current thread as a looper, marking it as an* application's main looper. The main looper for your application* is created by the Android environment, so you should never need* to call this function yourself. See also: {@link #prepare()}*/ public static void prepareMainLooper() {prepare(false);synchronized (Looper.class) {if (sMainLooper != null) {throw new IllegalStateException("The main Looper has already been prepared.");}sMainLooper = myLooper();} }prepareMainLooper()方法其實(shí)是調(diào)用了prepare()方法。
當(dāng)我們啟動(dòng)應(yīng)用時(shí)系統(tǒng)就調(diào)用了prepareMainLooper()并在主線程中綁定了一個(gè)Looper對(duì)象。
這時(shí)候我們回過來看看一開始的Handler使用方式。在主線程中我們創(chuàng)建了Handler對(duì)象,在Handler構(gòu)造函數(shù)中初始化了Looper(即獲取到了綁定在主線程中的Looper對(duì)象)。當(dāng)在子線程MyThread中通過mHandler.sendMessage(msg)方法發(fā)送一個(gè)消息時(shí)就把Message放在與主線程綁定的MessageQueue中。這樣在子線程中使用Handler就實(shí)現(xiàn)了消息的通信。
可以簡(jiǎn)單的使用以下類圖表示,每個(gè)線程都由一個(gè)Handler,每個(gè)Handler都是與當(dāng)前所在線程的Looper綁定。
0x08 主線程是否會(huì)阻塞
在0x06中知道在ActivityThead的main方法中啟動(dòng)了一個(gè)死循環(huán)。那主線程是不是就一直阻塞在這里呢?其實(shí)不然。可以看到ActivityThread類里面有一個(gè)自定義的Handler對(duì)象mH,在這里對(duì)象中handleMessage()回調(diào)中定義了Activity的各種交互如管理Activity生命周期,啟動(dòng)service,顯示window等,都是通過Handler進(jìn)行處理的。同時(shí)可以看出只有當(dāng)應(yīng)用退出EXIT_APPLICATION之后才回調(diào)用Looper.quit()停止消息循環(huán)。
public void handleMessage(Message msg) {...switch (msg.what) {case LAUNCH_ACTIVITY: {...handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);} break;...case PAUSE_ACTIVITY: {...handlePauseActivity((IBinder) args.arg1, false,(args.argi1 & USER_LEAVING) != 0, args.argi2,(args.argi1 & DONT_REPORT) != 0, args.argi3);...} break;...case SHOW_WINDOW:...handleWindowVisibility((IBinder)msg.obj, true);...break;...case EXIT_APPLICATION:if (mInitialApplication != null) {mInitialApplication.onTerminate();}Looper.myLooper().quit();break;...}... }0x09 總結(jié)
當(dāng)創(chuàng)建Handler時(shí)將通過ThreadLocal在當(dāng)前線程綁定一個(gè)Looper對(duì)象,而Looper持有MessageQueue對(duì)象。執(zhí)行Handler.sendMessage(Message)方法將一個(gè)待處理的Message插入到MessageQueue中,這時(shí)候通過Looper.loop()方法獲取到隊(duì)列中Message,然后再交由Handler.handleMessage(Message)來處理。
微信關(guān)注我們,可以獲取更多?
?
轉(zhuǎn)載于:https://www.cnblogs.com/angrycode/p/6576905.html
總結(jié)
以上是生活随笔為你收集整理的源码分析Android Handler是如何实现线程间通信的的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 添加引导滚动页
- 下一篇: Android开发 ---如何操作资源目