Handler的使用
在Android開發(fā)中,Handler機(jī)制是一個(gè)很重要的知識(shí)點(diǎn),主要用于消息通信。
Handler使用的三大步驟:
1、Loop.prepare()。
2、new一個(gè)Handler對象,并重寫handleMessage方法。
3、Loop.loop()。
先運(yùn)行實(shí)例代碼觀察現(xiàn)象,再深入分析內(nèi)部原理。
publicclassLooperThreadextendsThread{ privatestaticfinalString TAG = LooperThread.class.getSimpleName(); privateHandler handler; @Override publicvoidrun(){ Looper.prepare(); handler = newHandler(Looper.myLooper(), newHandler.Callback() { @Override publicbooleanhandleMessage(@NonNull Message msg){ Log.d(TAG, "what: "+ msg.what + ", msg: "+ msg.obj.toString()); returntrue; } }); Looper.loop(); } publicvoidsendMessage(intwhat, Object obj){ Message msg = handler.obtainMessage(what, obj); handler.sendMessage(msg); } }
publicclassFirstActivityextendsAppCompatActivity{ privatestaticfinalString TAG = FirstActivity.class.getSimpleName(); privateLooperThread looperThread; @Override protectedvoidonCreate(Bundle savedInstanceState){ looperThread = newLooperThread(); looperThread.start(); try{ Thread.sleep(1000); } catch(InterruptedException e) { e.printStackTrace(); } looperThread.sendMessage(1, "Hello android!"); }
編譯運(yùn)行程序,輸出如下:
2021-10-0623:15:24.32320107-20107/com.example.activitytest D/FirstActivity: Task id is73 2021-10-0623:15:25.32820107-20124/com.example.activitytest D/LooperThread: what:1, msg:Hello android! 2021-10-0623:15:25.39420107-20132/com.example.activitytest I/OpenGLRenderer: Initialized EGL, version1.4 2021-10-0623:15:25.39420107-20132/com.example.activitytest D/OpenGLRenderer: Swap behavior 1
Loop.prepare方法內(nèi)部實(shí)現(xiàn)原理
了解某個(gè)方法具體做了什么,最好的方法就是追蹤下去看源碼。我們跟隨IDE一步一步查看Loop.prepare到底做了什么。
/** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ publicstaticvoidprepare() { prepare(true); } privatestaticvoidprepare(boolean quitAllowed) { if(sThreadLocal.get() != null) { thrownewRuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(newLooper(quitAllowed)); }
sThreadLocal是一個(gè)ThreadLocal類型變量,且ThreadLocal是一個(gè)模板類。Loop.prepare最終創(chuàng)建一個(gè)新的Looper對象,且對象實(shí)例被變量sThreadLocal引用。繼續(xù)追蹤下去,查看Looper構(gòu)造方法做了什么操作。
privateLooper(booleanquitAllowed){ mQueue = newMessageQueue(quitAllowed); mThread = Thread.currentThread(); } ...... MessageQueue(booleanquitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit(); }到這里我們已經(jīng)很清楚,Looper構(gòu)造方法主要是創(chuàng)建一個(gè)MessageQueue,且MessageQueue構(gòu)造方法調(diào)用native方法獲取底層queue的指針,mQuitAllowed值為true表示允許退出loop,false表示無法退出loop。結(jié)合前面Looper.prepare方法內(nèi)部代碼,表示我們創(chuàng)建的Looper允許退出loop。 new一個(gè)Handler對象實(shí)例,到底做了什么?
/** * Use the provided {@linkLooper} instead of the default one and take a callback * interface in which to handle messages. * * @paramlooper The looper, must not be null. * @paramcallback The callback interface in which to handle messages, or null. */ publicHandler(@NonNull Looper looper, @Nullable Callback callback){ this(looper, callback, false); } ...... /** * Use the provided {@linkLooper} instead of the default one and take a callback * interface in which to handle messages. Also set whether the handler * should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by conditions such as display vsync. * * @paramlooper The looper, must not be null. * @paramcallback The callback interface in which to handle messages, or null. * @paramasync If true, the handler calls {@linkMessage#setAsynchronous(boolean)} for * each {@linkMessage} that is sent to it or {@linkRunnable} that is posted to it. * * @hide */ @UnsupportedAppUsage publicHandler(@NonNull Looper looper, @Nullable Callback callback, booleanasync){ mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }
Handler還有其他構(gòu)造方法,這里我們調(diào)用其中一種構(gòu)造方法創(chuàng)建一個(gè)Handler對象實(shí)例。該構(gòu)造方法要求傳入一個(gè)Looper對象實(shí)例和CallBack對象實(shí)例?;仡櫼幌伦铋_始的例子代碼,我們傳入的形參,一個(gè)是由Looper.myLooper方法獲取的Looper對象實(shí)例,另外一個(gè)則是Callback匿名類。我們先看看Looper.myLooper到底獲取到了什么。
/** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ publicstatic@Nullable Looper myLooper() { returnsThreadLocal.get(); }這里獲取到的就是前面Looper.prepare方法新創(chuàng)建的Looper對象實(shí)例,所以Looper.prepare方法必須在創(chuàng)建Handler對象實(shí)例之前調(diào)用。再回到Handler構(gòu)造方法里,有幾個(gè)地方很關(guān)鍵: 1、Handler內(nèi)部保存了Looper對象引用。 2、Handler內(nèi)部保存了Looper內(nèi)部的MessageQueue對象引用。 3、Handler內(nèi)部保存了Callback對象引用。 4、mAsyncchronous值為true表示handleMessage方法異步執(zhí)行,false表示同步執(zhí)行。
Looper.loop方法內(nèi)部實(shí)現(xiàn)原理
/** * Run the message queue in this thread. Be sure to call * {@link#quit()} to end the loop. */ publicstaticvoidloop(){ finalLooper me = myLooper(); if(me == null) { thrownewRuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } if(me.mInLoop) { Slog.w(TAG, "Loop again would have the queued messages be executed" + " before this one completed."); } me.mInLoop = true; finalMessageQueue 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(); finallongident = Binder.clearCallingIdentity(); // Allow overriding a threshold with a system prop. e.g. // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start' finalintthresholdOverride = SystemProperties.getInt("log.looper." + Process.myUid() + "." + Thread.currentThread().getName() + ".slow", 0); booleanslowDeliveryDetected = false; 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 finalPrinter logging = me.mLogging; if(logging != null) { logging.println(">>>>> Dispatching to "+ msg.target + " "+ msg.callback + ": "+ msg.what); } // Make sure the observer won't change while processing a transaction. finalObserver observer = sObserver; finallongtraceTag = me.mTraceTag; longslowDispatchThresholdMs = me.mSlowDispatchThresholdMs; longslowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs; if(thresholdOverride > 0) { slowDispatchThresholdMs = thresholdOverride; slowDeliveryThresholdMs = thresholdOverride; } finalbooleanlogSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0); finalbooleanlogSlowDispatch = (slowDispatchThresholdMs > 0); finalbooleanneedStartTime = logSlowDelivery || logSlowDispatch; finalbooleanneedEndTime = logSlowDispatch; if(traceTag != 0&& Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } finallongdispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0; finallongdispatchEnd; Object token = null; if(observer != null) { token = observer.messageDispatchStarting(); } longorigWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid); try{ msg.target.dispatchMessage(msg); if(observer != null) { observer.messageDispatched(token, msg); } dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } catch(Exception exception) { if(observer != null) { observer.dispatchingThrewException(token, msg, exception); } throwexception; } finally{ ThreadLocalWorkSource.restore(origWorkSource); if(traceTag != 0) { Trace.traceEnd(traceTag); } } if(logSlowDelivery) { if(slowDeliveryDetected) { if((dispatchStart - msg.when) <= 10) { ????????????????????????Slog.w(TAG, "Drained"); ????????????????????????slowDeliveryDetected = false; ????????????????????} ????????????????} else?{ ????????????????????if?(showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery", ????????????????????????????msg)) { ????????????????????????// Once we write a slow delivery log, suppress until the queue drains. ????????????????????????slowDeliveryDetected = true; ????????????????????} ????????????????} ????????????} ????????????if?(logSlowDispatch) { ????????????????showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg); ????????????} ????????????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(); ????????} ????}
代碼較長,我們只取關(guān)鍵代碼閱讀。通過myLooper獲取新創(chuàng)建的Looper對象實(shí)例,進(jìn)而獲取Looper內(nèi)部的MessageQueue對象實(shí)例。然后進(jìn)入死循環(huán)中不斷調(diào)用MessageQueue類的next方法獲取MessageQueue里的message,然后調(diào)用dispatchMessage進(jìn)行消息分發(fā),最后由handleMessage進(jìn)行消息處理。到這里L(fēng)ooper、MessageQueue和Handler之間的關(guān)系就建立起來了。介于篇幅,發(fā)送消息和消息處理原理,下篇文章詳細(xì)分析。
審核編輯:湯梓紅
-
Android
+關(guān)注
關(guān)注
12文章
3936瀏覽量
127417 -
通信
+關(guān)注
關(guān)注
18文章
6032瀏覽量
135999 -
代碼
+關(guān)注
關(guān)注
30文章
4788瀏覽量
68625 -
handler
+關(guān)注
關(guān)注
0文章
7瀏覽量
3035
原文標(biāo)題:詳解Android Handler機(jī)制和原理(一)
文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論