android线程消息机制之Handler详解
android线程消息机制主要由handler,looper,message和messagequene四个部分组成。平常在开发中,我们常用来在子线程中通知主线程来更新,其实整个安卓生命周期的驱动都是通过handler(activitythread.h)来实现的。
首先我们先介绍这四个类的作用:
handler:消息的发送者。负责将message消息发送到messagequeue中。以及通过runnable,callback或者handlemessage()来实现消息的回调处理
looper:是消息的循环处理器,它负责从messagequeue中取出message对象进行处理。(looper含有messagequeue的引用)
message:是消息载体,通过target来指向handler的引用。通过object来包含业务逻辑数据。其中messagepool为消息池,用于回收空闲的message对象的。
messagequeue:消息队列,负责维护待处理的消息对象。
通过上面的图,我们可以比较清楚地知道他们的作用以及关系。接下来,我们从源码角度来分析这种关系是如何建立的。
public handler(looper looper, callback callback, boolean async) { mlooper = looper; mqueue = looper.mqueue; mcallback = callback; masynchronous = async; }
hander的其它构造方法可以自己去查看,通过这个构造方法,我们知道,handler持有messagequeue的引用。所以可以方便地将message加入到队列中去。
通过源码我们发现,sendmessage->sendmessagedelayed->sendmessageattime->enqueuemessage
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); }
都是通过enqueuemessage将message将加入到messagequeue中。
接下来,我们看message是如何构造的。通过message的构造方法。
public static message obtain() { synchronized (spoolsync) { if (spool != null) { message m = spool; spool = m.next; m.next = null; m.flags = 0; // clear in-use flag spoolsize--; return m; } } return new message(); }
我们看到,message是通过obtain的静态方法从消息池spool中拿到的。这样可以做到消息的复用。
public static message obtain(handler h) { message m = obtain(); m.target = h; return m; }
其中有一个重载方法中m.target = h;这段代码非常重要,便于后面找到消息的目标handler进行处理。
接下来,我们来看looper。我们知道looper通过过looper.loop来进入循环的,而循环是通过线程的run方法的驱动的。
首先我们知道,我们在创建handler的时候,都没有去创建looper,那么looper哪里来的呢?
public handler(callback callback, boolean async) { ... 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; }
再看看looper.mylooper()
public static @nullable looper mylooper() { return sthreadlocal.get(); }
threadlocal是线程创建线程局部变量的类。表示此变量只属于当前线程。
public t get() { thread t = thread.currentthread(); threadlocalmap map = getmap(t); if (map != null) { threadlocalmap.entry e = map.getentry(this); if (e != null) { @suppresswarnings("unchecked") t result = (t)e.value; return result; } } return setinitialvalue(); }
我们看到了sthreadlocal.get()的方法实际是取当前线程中的looper对象。
那么我们主线程的looper到底在哪里创建的呢?
而我们清楚地知道,如果在子线程中创建handler调用,则需要使用looper.prepare方法。
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)); }
我们看到此方法中,如果此线程中没有looper对象,则创建一个looper对象。接下来我们在源码中看到一个熟悉的方法。
public static void preparemainlooper() { prepare(false); synchronized (looper.class) { if (smainlooper != null) { throw new illegalstateexception("the main looper has already been prepared."); } smainlooper = mylooper(); } }
此方法单独的创建了一个smainlooper用于主线程的looper。这个preparemainlooper到底在哪里调用呢?
高过引用指向发现,我们在activitythread.main()方法中发现
public static void main(string[] args) { ... looper.preparemainlooper(); 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(); throw new runtimeexception("main thread loop unexpectedly exited"); }
而activitythread.main()是程序的入口方法。这样我们就非常清楚了,主线程的looper在程序的启动过程中就已经创建并循环。
那么如果在子线程中创建looper该如何正确调用呢?
class looperthread extends thread { public handler mhandler; public void run() { looper.prepare(); mhandler = new handler() { public void handlemessage(message msg) { // process incoming messages here } }; looper.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;//拿到当前looper的消息队列 // 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 (;;) {//死循环遍历消息体。如果为null,则休眠。 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 slowdispatchthresholdms = me.mslowdispatchthresholdms; final long tracetag = me.mtracetag; if (tracetag != 0 && trace.istagenabled(tracetag)) { trace.tracebegin(tracetag, msg.target.gettracename(msg)); } final long start = (slowdispatchthresholdms == 0) ? 0 : systemclock.uptimemillis(); final long end; try { msg.target.dispatchmessage(msg);//此处是真正的分发消息。此处的target即是handler对象 end = (slowdispatchthresholdms == 0) ? 0 : systemclock.uptimemillis(); } finally { if (tracetag != 0) { trace.traceend(tracetag); } } if (slowdispatchthresholdms > 0) { final long time = end - start; if (time > slowdispatchthresholdms) { slog.w(tag, "dispatch took " + time + "ms on " + thread.currentthread().getname() + ", h=" + msg.target + " cb=" + msg.callback + " msg=" + msg.what); } } 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(); } }
最后我们看下dispatchmessage的处理方法。
public void dispatchmessage(message msg) { if (msg.callback != null) { handlecallback(msg); } else { if (mcallback != null) { if (mcallback.handlemessage(msg)) { return; } } handlemessage(msg); } }
我们看到,dispatchmessage是优化处理msg.callback,然后就是实现的callback接口,最后才是handlemessage方法。
重点说明:
1、handler在实例化的时候,持有looper的引用。是通过threadlocal与handler进行关联的。
2、message在实例化的过程中,通过target 持有handler的引用。
3、通常一个线程对应一个looper.一个looper可以属于多个handler。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。