handler的使用
在android开发中,handler机制是一个很重要的知识点,主要用于消息通信。
handler使用的三大步骤:
1、loop.prepare()。
2、new一个handler对象,并重写handlemessage方法。
3、loop.loop()。
先运行实例代码观察现象,再深入分析内部原理。
public class looperthread extends thread{ private static final string tag = looperthread.class.getsimplename(); private handler handler; @override public void run() { looper.prepare(); handler = new handler(looper.mylooper(), new handler.callback() { @override public boolean handlemessage(@nonnull message msg) { log.d(tag, what: + msg.what + , msg: + msg.obj.tostring()); return true; } }); looper.loop(); } public void sendmessage(int what, object obj){ message msg = handler.obtainmessage(what, obj); handler.sendmessage(msg); }}
public class firstactivity extends appcompatactivity { private static final string tag = firstactivity.class.getsimplename(); private looperthread looperthread; @override protected void oncreate(bundle savedinstancestate) { looperthread = new looperthread(); looperthread.start(); try { thread.sleep(1000); } catch (interruptedexception e) { e.printstacktrace(); } looperthread.sendmessage(1, hello android!); }
编译运行程序,输出如下:
2021-10-06 23:15:24.323 20107-20107/com.example.activitytest d/firstactivity: task id is 732021-10-06 23:15:25.328 20107-20124/com.example.activitytest d/looperthread: what: 1, msg: hello android!2021-10-06 23:15:25.394 20107-20132/com.example.activitytest i/openglrenderer: initialized egl, version 1.42021-10-06 23:15:25.394 20107-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()}. */ 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)); }
sthreadlocal是一个threadlocal类型变量,且threadlocal是一个模板类。loop.prepare最终创建一个新的looper对象,且对象实例被变量sthreadlocal引用。继续追踪下去,查看looper构造方法做了什么操作。
private looper(boolean quitallowed) { mqueue = new messagequeue(quitallowed); mthread = thread.currentthread(); }......messagequeue(boolean quitallowed) { mquitallowed = quitallowed; mptr = nativeinit();}到这里我们已经很清楚,looper构造方法主要是创建一个messagequeue,且messagequeue构造方法调用native方法获取底层queue的指针,mquitallowed值为true表示允许退出loop,false表示无法退出loop。结合前面looper.prepare方法内部代码,表示我们创建的looper允许退出loop。 new一个handler对象实例,到底做了什么?/** * use the provided {@link looper} instead of the default one and take a callback * interface in which to handle messages. * * @param looper the looper, must not be null. * @param callback the callback interface in which to handle messages, or null. */ public handler(@nonnull looper looper, @nullable callback callback) { this(looper, callback, false); }...... /** * use the provided {@link looper} 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. * * @param looper the looper, must not be null. * @param callback the callback interface in which to handle messages, or null. * @param async if true, the handler calls {@link message#setasynchronous(boolean)} for * each {@link message} that is sent to it or {@link runnable} that is posted to it. * * @hide */ @unsupportedappusage public handler(@nonnull looper looper, @nullable callback callback, boolean async) { 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. */ public static @nullable looper mylooper() { return sthreadlocal.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. */ public static void loop() { final looper me = mylooper(); if (me == null) { throw new runtimeexception(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; 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(); // allow overriding a threshold with a system prop. e.g. // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start' final int thresholdoverride = systemproperties.getint(log.looper. + process.myuid() + . + thread.currentthread().getname() + .slow, 0); boolean slowdeliverydetected = 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 final printer 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. final observer observer = sobserver; final long tracetag = me.mtracetag; long slowdispatchthresholdms = me.mslowdispatchthresholdms; long slowdeliverythresholdms = me.mslowdeliverythresholdms; if (thresholdoverride > 0) { slowdispatchthresholdms = thresholdoverride; slowdeliverythresholdms = thresholdoverride; } final boolean logslowdelivery = (slowdeliverythresholdms > 0) && (msg.when > 0); final boolean logslowdispatch = (slowdispatchthresholdms > 0); final boolean needstarttime = logslowdelivery || logslowdispatch; final boolean needendtime = logslowdispatch; if (tracetag != 0 && trace.istagenabled(tracetag)) { trace.tracebegin(tracetag, msg.target.gettracename(msg)); } final long dispatchstart = needstarttime ? systemclock.uptimemillis() : 0; final long dispatchend; object token = null; if (observer != null) { token = observer.messagedispatchstarting(); } long origworksource = 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); } throw exception; } 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(); } }
代码较长,我们只取关键代码阅读。通过mylooper获取新创建的looper对象实例,进而获取looper内部的messagequeue对象实例。然后进入死循环中不断调用messagequeue类的next方法获取messagequeue里的message,然后调用dispatchmessage进行消息分发,最后由handlemessage进行消息处理。到这里looper、messagequeue和handler之间的关系就建立起来了。介于篇幅,发送消息和消息处理原理,下篇文章详细分析。
!销售/收购/维修 HP83711B HP 83711B A
2011年通信展今日开幕
RC桥式振荡器,RC桥式振荡器工作原理是什么?
微雪电子IC120-0324-009 PLCC32测试座简介
汇川技术预计上半年实现营收超25.96 亿
详解Android Handler机制和原理
Choosing the Right RS-232 Tran
Versal系列芯片三个产品的基础知识
普通车床的组成和传动系统
可穿戴技术在医疗健康领域中的应用趋势
OpenHarmony视频录制流程介绍
S7-200 PLC的数据区
北工大校友Cheng Zhang获SIGGRAPH最佳博士论文奖!
Club Vivado 的用户们, 你在哪里?
华为nova8系列、畅享20SE部分参数曝光
动态充电:电动汽车在行驶中充电
科达猎鹰人像大数据平台 以熟稔身法游刃在技战前沿
迎接“无尾”时代 无线供电高层研讨会即将召开
光控开关与光电开关的区别
浅谈高压SiC MOSFET发展历程与研究现状