Handler,Looper,MessageQueue流程梳理
目的:handle的出现主要是为了解决线程间通讯。
举个例子,android是不允许在主线程中访问网络,因为这样会阻塞主线程,影响性能,所以访问网络都是放在子线程中执行,对于网络返回的结果则需要显示在主线程中,handler就是连接主线程和子线程的桥梁。
1.handler基本使用方法
看一下使用方法:
public static final int empty_msg = 0; @suppresslint("handlerleak") handler handler = new handler(){ @override public void handlemessage(message msg) { switch (msg.what){ case 0: toast.maketext(mainactivitys.this, "接受到消息", toast.length_short).show(); break; } } }; @override protected void oncreate(@nullable bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); new thread(new runnable() { @override public void run() { handler.sendemptymessage(0); } }).start(); }
通过上边代码就完成了子线程向主线程发送消息的功能。
2. handler,looper,messagequeue 解释
handler:负责发送和处理消息
looper:消息循环器,也可以理解为消息泵,主动地获取消息,并交给handler来处理
messagequeue:消息队列,用来存储消息
3.源码分析
程序的启动是在activitythread的main方法中
public static void main(){ looper.prepare(); //1 handler handler = new handler();//2 looper.loop(); //3 }
looper.prepare()会初始化当前线程的looper
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.set()方法,threadlocal是线程安全的,不同的线程获取到的值是不一样的,下面先分析一下threadlocal是如何做到线程安全。
public void set(t value) { thread t = thread.currentthread(); threadlocalmap map = getmap(t); if (map != null) map.set(this, value); else createmap(t, value); }
不同的线程会设置不同的looper,下面看一下threadlocalmap是如何存储数据的
threadlocalmap(threadlocal firstkey, object firstvalue) { table = new entry[initial_capacity]; int i = firstkey.threadlocalhashcode & (initial_capacity - 1); table[i] = new entry(firstkey, firstvalue); }
threadlocalmap会创建一个数组,key是通过特殊的算法来创建出来,一个线程中会有一个threadlocalmap,这个map中会存多个threadlocal和values。
下面看下threadlocalmap是如何set一个值的
private void set(threadlocal key, object value) { // we don't use a fast path as with get() because it is at // least as common to use set() to create new entries as // it is to replace existing ones, in which case, a fast // path would fail more often than not. entry[] tab = table; int len = tab.length; int i = key.threadlocalhashcode & (len-1); for (entry e = tab[i]; e != null; e = tab[i = nextindex(i, len)]) { threadlocal k = e.get(); if (k == key) { e.value = value; return; } if (k == null) { replacestaleentry(key, value, i); return; } } tab[i] = new entry(key, value); int sz = ++size; if (!cleansomeslots(i, sz) && sz >= threshold) rehash(); }
其实是遍历threadlocalmap中的table,如果当前table中存在threadlocal这个key就更新,不存在就新建。threadlocal的set方法到此结束。
下面看下handler handler = new handler()中执行了哪些操作:
public handler(callback callback, boolean async) { mlooper = looper.mylooper(); mqueue = mlooper.mqueue; }
重要的就是构造函数中这两个方法,在handler中初始化looper和messagequeue。这个就不展开讲了。
下面看一下looper.loop()这个步骤,我做了一些精简,把无关的代码去掉了。
public static void loop() { final looper me = mylooper(); final messagequeue queue = me.mqueue; for (;;) { message msg = queue.next(); // might block if (msg == null) { // no message indicates that the message queue is quitting. return; } msg.target.dispatchmessage(msg); msg.recycleunchecked(); } }
queue.next()是个无限for循环,其实也是个阻塞方法,其中比较重要的是下面这个方法,其作用是不会一直循环。底层采用的是pipe/epoll机制。
nativepollonce(ptr, nextpolltimeoutmillis);
message next() { // return here if the message loop has already quit and been disposed. // this can happen if the application tries to restart a looper after quit // which is not supported. final long ptr = mptr; if (ptr == 0) { return null; } int pendingidlehandlercount = -1; // -1 only during first iteration int nextpolltimeoutmillis = 0; for (;;) { if (nextpolltimeoutmillis != 0) { binder.flushpendingcommands(); } nativepollonce(ptr, nextpolltimeoutmillis); synchronized (this) { // try to retrieve the next message. return if found. final long now = systemclock.uptimemillis(); message prevmsg = null; message msg = mmessages; if (msg != null && msg.target == null) { // stalled by a barrier. find the next asynchronous message in the queue. do { prevmsg = msg; msg = msg.next; } while (msg != null && !msg.isasynchronous()); } if (msg != null) { if (now < msg.when) { // next message is not ready. set a timeout to wake up when it is ready. nextpolltimeoutmillis = (int) math.min(msg.when - now, integer.max_value); } else { // got a message. mblocked = false; if (prevmsg != null) { prevmsg.next = msg.next; } else { mmessages = msg.next; } msg.next = null; if (debug) log.v(tag, "returning message: " + msg); msg.markinuse(); return msg; } } else { // no more messages. nextpolltimeoutmillis = -1; } // process the quit message now that all pending messages have been handled. if (mquitting) { dispose(); return null; } // if first time idle, then get the number of idlers to run. // idle handles only run if the queue is empty or if the first message // in the queue (possibly a barrier) is due to be handled in the future. if (pendingidlehandlercount < 0 && (mmessages == null || now < mmessages.when)) { pendingidlehandlercount = midlehandlers.size(); } if (pendingidlehandlercount <= 0) { // no idle handlers to run. loop and wait some more. mblocked = true; continue; } if (mpendingidlehandlers == null) { mpendingidlehandlers = new idlehandler[math.max(pendingidlehandlercount, 4)]; } mpendingidlehandlers = midlehandlers.toarray(mpendingidlehandlers); } // run the idle handlers. // we only ever reach this code block during the first iteration. for (int i = 0; i < pendingidlehandlercount; i++) { final idlehandler idler = mpendingidlehandlers[i]; mpendingidlehandlers[i] = null; // release the reference to the handler boolean keep = false; try { keep = idler.queueidle(); } catch (throwable t) { log.wtf(tag, "idlehandler threw exception", t); } if (!keep) { synchronized (this) { midlehandlers.remove(idler); } } } // reset the idle handler count to 0 so we do not run them again. pendingidlehandlercount = 0; // while calling an idle handler, a new message could have been delivered // so go back and look again for a pending message without waiting. nextpolltimeoutmillis = 0; } }
message.next()返回消息之后会接着调用 msg.target.dispatchmessage(msg);在这个方法里边会进行判断,来决定执行哪一种回调。
public void dispatchmessage(message msg) { if (msg.callback != null) { handlecallback(msg); } else { if (mcallback != null) { if (mcallback.handlemessage(msg)) { return; } } handlemessage(msg); } }
到此整个handler的流程就结束了。最后附上一张handler的时序图。
上一篇: Vue-指令
推荐阅读
-
Handler,Looper,MessageQueue流程梳理
-
Android异步2:深入详解 Handler+Looper+MessageQueue
-
Android Handler 机制 - Looper,Message,MessageQueue
-
handler,message,looper,messagequeue
-
Handler,Looper,Thread,Message,MessageQueue
-
Handler、Looper、Message、MessageQueue
-
Looper,MessageQueue,Message,Handler
-
异步消息处理(Message, Handler, MessageQueue, Looper)
-
Android消息通信机制Handler详解,Handler,Looper,MessageQueue,源码解析,讲解这几个类怎么配合工作的
-
Android消息处理机制(Handler、Looper、MessageQueue与Message)