本篇文章為大家展示了如何進(jìn)行Handler、Looper與MessageQueue源碼分析,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。
我們一直強(qiáng)調(diào)網(wǎng)站設(shè)計、網(wǎng)站制作對于企業(yè)的重要性,如果您也覺得重要,那么就需要我們慎重對待,選擇一個安全靠譜的網(wǎng)站建設(shè)公司,企業(yè)網(wǎng)站我們建議是要么不做,要么就做好,讓網(wǎng)站能真正成為企業(yè)發(fā)展過程中的有力推手。專業(yè)網(wǎng)絡(luò)公司不一定是大公司,創(chuàng)新互聯(lián)建站作為專業(yè)的網(wǎng)絡(luò)公司選擇我們就是放心。
在Android中可以通過Handler來更新主線程中UI的變化,更新UI只能在主線程中進(jìn)行更新,而為了讓其他線程也能控制UI的變化,Android提供了一種機(jī)制Handler、Looper與MessageQueue一同協(xié)作來達(dá)到其他線程更新UI的目的。
一般我們會在主線程中通過如下方法定義一個Handler
private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { tv.setText("mHandler change UI"); super.handleMessage(msg); } };
一般都見不到Looper與MessageQueue的,那么它們都是在哪里調(diào)用與如何協(xié)作的呢?在主線程不會顯式的調(diào)用Looper而是會在ActivityThread.main方法中默認(rèn)調(diào)用。
public static void main(String[] args) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Environment.initForCurrentUser(); // Set the reporter for event logging in libcore EventLogger.setReporter(new EventLoggingReporter()); // Make sure TrustedCertificateStore looks in the right place for CA certificates final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); Process.setArgV0(""); Looper.prepareMainLooper();//創(chuàng)建Looper ActivityThread thread = new ActivityThread(); thread.attach(false); 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();//開啟Looper循環(huán) throw new RuntimeException("Main thread loop unexpectedly exited"); }
如上代碼,調(diào)用了Looper.prepareMainLooper()方法,在主線程中創(chuàng)建了一個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));//創(chuàng)建Looper并賦給sThreadLocal } /** * 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(); } } public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
在prepareMainLooper方法中調(diào)用了prepare而通過prepare會發(fā)現(xiàn)它其實就是創(chuàng)建了一個Looper,并把它賦給了sThreadLocal。同時可以通過myLooper方法獲取當(dāng)前線程中的Looper。再來看下new Looper(quitAllowed)初始化了什么
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
在這里我們終于看到了MessageQueue了,它創(chuàng)建了一個MessageQueue。該消息隊列就是用來保存后續(xù)的Message。再回到ActivityThread.main方法中,發(fā)現(xiàn)它調(diào)用了Looper.loop()是用來開啟Looper循環(huán)的,監(jiān)聽消息隊列MessageQueue中的消息。
loop
我們來看下Looper.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;//獲取消息隊列 // 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 (;;) { 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)); } try { msg.target.dispatchMessage(msg);//通過Handler分發(fā)消息 } 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中首先獲取了當(dāng)前所在線程的Looper,同時也獲取到了Looper中的MessageQueue,說明Looper已經(jīng)與當(dāng)前的線程進(jìn)行了綁定。在后面開啟了一個for的死循環(huán),發(fā)現(xiàn)它做的事件是不斷的從消息隊列中取出消息,***都交給msg.target調(diào)用它的dispatchMessage方法,那么target又是什么呢?我們進(jìn)入Message
Message
/*package*/ int flags; /*package*/ long when; /*package*/ Bundle data; /*package*/ Handler target; /*package*/ Runnable callback; // sometimes we store linked lists of these things /*package*/ Message next;
發(fā)現(xiàn)它就是我們熟悉的Handler,說明***調(diào)用的就是Handler中的dispatchMessage方法,對消息的分發(fā)處理。這樣一來Handler就通過Looper聯(lián)系上了Looper所綁定的線程,即為主線程。
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; }
通過Handler的初始化,它獲取了它所處線程的Looper,同時也獲取了Looper中的消息隊列。當(dāng)然如果所處線程的Looper為空的話就會拋出異常,這就解釋了為什么在非主線程中創(chuàng)建Handler要分別調(diào)用Looper.prepare與Looper.loop而主線程則不需要,因為它默認(rèn)已經(jīng)調(diào)用了。
dispatchMessage
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(); }
回到前面,對于dispatchMessage的處理,首先判斷msg.callback是否為空,這里callback通過上面的Message應(yīng)該能知道他就是一個Runnable,如果不為空則直接調(diào)用Runnable的run方法。否則調(diào)用Handler的handleMessage方法.而這個方法相信大家已經(jīng)很熟悉了,對事件的處理都是在這個方法中執(zhí)行的。因為通過前面我們已經(jīng)知道了Handler已經(jīng)聯(lián)系上了主線程,所以handleMessage中的處理自然相對于在主線程中進(jìn)行,自然也能更新UI了。通過這里我們能把Looper比作是一個橋梁,來連接Looper所在的線程與Handler之間的通信,同時管理消息隊列MessageQueue中的消息。那么前面的Runnable又是如何不為空的呢?我們使用Handler有兩種方法,一種是直接創(chuàng)建一個Handler并且重寫它的handleMessage方法,而另一種可以通過Handler.post(Runnable)來使用,這樣事件的處理自然就在run方法中實現(xiàn)。
上面介紹了Handler是如何聯(lián)系上了需要操作的線程與對消息是如何取出與處理的。下面來談?wù)勏⑹侨绾畏湃氲絃ooper中的MessageQueue中的。
sendMessageAtTime
通過Handler發(fā)送消息的方式很多,例如:sendMessage、sendEmptyMessage與sendMessageDelayed等,其實到***他們調(diào)用的都是sendMessageAtTime方法。所以還是來看下sendMessageAtTime方法中的實現(xiàn)。
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); }
而sendMessageAtTime則就是調(diào)用了enqueueMessage操作,看這方法名就知道是入隊列操作了。
enqueueMessage
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
果不其然直接調(diào)用了MessageQueue中的queue.enqueueMessage(msg, uptimeMillis)將消息加入消息隊列,同時這段代碼msg.target = this 將當(dāng)前的Handler賦給了msg.target,這就是前面所說的Looper.loop方法中調(diào)用的Handler。這樣就把消息放到了MessageQueue中,進(jìn)而通過前面所講的loop來取出消息進(jìn)行相應(yīng)的處理,這樣就構(gòu)成了整個對消息進(jìn)行處理的系統(tǒng)。這也是使用Handler內(nèi)部所發(fā)生的原理。好了Handler、Looper與MessageQueue它們之間的聯(lián)系基本就是這些了。我也簡單畫了張圖希望有所幫助
上述內(nèi)容就是如何進(jìn)行Handler、Looper與MessageQueue源碼分析,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。