主页 > 互联网 > 内容页

世界微动态丨详解Android Handler机制和原理

2023-03-26 18:06:04 来源:Android编程精选

Handler的使用

Android开发中,Handler机制是一个很重要的知识点,主要用于消息通信


【资料图】

Handler使用的三大步骤:

1、Loop.prepare()。

2、new一个Handler对象,并重写handleMessage方法。

3、Loop.loop()。

先运行实例代码观察现象,再深入分析内部原理。

publicclassLooperThreadextendsThread{privatestaticfinalString TAG = LooperThread.class.getSimpleName();privateHandler handler;@Overridepublicvoidrun(){Looper.prepare();handler = newHandler(Looper.myLooper(), newHandler.Callback() {@OverridepublicbooleanhandleMessage(@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;@OverrideprotectedvoidonCreate(Bundle savedInstanceState){looperThread = newLooperThread();looperThread.start();try{Thread.sleep(1000);} catch(InterruptedException e) {e.printStackTrace();}looperThread.sendMessage(1, "Hello android!");}

编译运行程序,输出如下:

2021-10-0623:15:24.32320107-20107/com.example.activitytest D/FirstActivity: Task id is732021-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.42021-10-0623:15:25.39420107-20132/com.example.activitytest D/OpenGLRenderer: Swap behavior 1

Loop.prepare方法内部实现原理

了解某个方法具体做了什么,最好的方法就是追踪下去看源码。我们跟随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是一个ThreadLocal类型变量,且ThreadLocal是一个模板类。Loop.prepare最终创建一个新的Looper对象,且对象实例被变量sThreadLocal引用。继续追踪下去,查看Looper构造方法做了什么操作。

privateLooper(booleanquitAllowed){mQueue = newMessageQueue(quitAllowed);mThread = Thread.currentThread();}......MessageQueue(booleanquitAllowed) {mQuitAllowed = quitAllowed;mPtr = nativeInit();}
到这里我们已经很清楚,Looper构造方法主要是创建一个MessageQueue,且MessageQueue构造方法调用native方法获取底层queue的指针,mQuitAllowed值为true表示允许退出loop,false表示无法退出loop。结合前面Looper.prepare方法内部代码,表示我们创建的Looper允许退出loop。 new一个Handler对象实例,到底做了什么?
/*** 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*/@UnsupportedAppUsagepublicHandler(@NonNull Looper looper, @Nullable Callback callback, booleanasync){mLooper = looper;mQueue = looper.mQueue;mCallback = callback;mAsynchronous = async;}

Handler还有其他构造方法,这里我们调用其中一种构造方法创建一个Handler对象实例。该构造方法要求传入一个Looper对象实例和CallBack对象实例。回顾一下最开始的例子代码,我们传入的形参,一个是由Looper.myLooper方法获取的Looper对象实例,另外一个则是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方法新创建的Looper对象实例,所以Looper.prepare方法必须在创建Handler对象实例之前调用。再回到Handler构造方法里,有几个地方很关键: 1、Handler内部保存了Looper对象引用。 2、Handler内部保存了Looper内部的MessageQueue对象引用。 3、Handler内部保存了Callback对象引用。 4、mAsyncchronous值为true表示handleMessage方法异步执行,false表示同步执行。

Looper.loop方法内部实现原理

/*** 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 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 loggerfinalPrinter 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.finallongnewIdent = 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();}}

代码较长,我们只取关键代码阅读。通过myLooper获取新创建的Looper对象实例,进而获取Looper内部的MessageQueue对象实例。然后进入死循环中不断调用MessageQueue类的next方法获取MessageQueue里的message,然后调用dispatchMessage进行消息分发,最后由handleMessage进行消息处理。到这里Looper、MessageQueue和Handler之间的关系就建立起来了。介于篇幅,发送消息和消息处理原理,下篇文章详细分析。

审核编辑:汤梓红

标签:

上一篇:
下一篇: