首页 > 行业资讯 > 正文

Handler的使用

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

Handler使用的三大步骤:

1、Loop.prepare()。

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

3、Loop.loop()。

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

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!”); }

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

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方法内部实现原理

了解某个方法具体做了什么,最好的方法就是追踪下去看源码。我们跟随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 */ @UnsupportedAppUsage publicHandler(@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() wasnt 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 wont 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 wasnt 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();         }     }

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

审核编辑:汤梓红

猜你喜欢