一个Handler消息的发送过程个人总结:
1、在一个新的线程中需要先用Looper.prepare()创建一个消息循环Looper对象,底层会把Looper对象存在了一个ThreadLocal中,在创建Looper对象的时候同时也会创建一个MessageQueue对象,保存在Looper对象的属性mQueue中。
2、在线程中创建Handler的时候,会去检测当前ThreadLocal是否存有Looper对象,如果没有存,那么就报错。
如果存了,那么就把Looper下的消息队列mQueue赋值给当前Handler的消息队列mQueue 即:mQueue = mLooper.mQueue
3、在Handler发送消息的时候就会调用Handle中的方法enqueueMessage,enqueueMessage方法中又会调用queue.enqueueMessage(msg, uptimeMillis);然后把消息插入消息队列中,(这个队列是在Looper中创建的)这个消息队列并不是一个真正的队列,仅仅是一个单链表而已,在存消息的时候会带有一个when,when为SystemClock.uptimeMillis() + delayMillis,及时消息delayMillis为0,延时消息delayMillis非0,消息链表时会在for(;;)中遍历已经存在链表中的消息,按when从小到大的顺序插入队列。
4、Looper.loop后,它会通过ThreadLocal找到第一步存进去的Looper对象,并且获取Looper对象中的属性mQueue,然后创建一个中死循环,循环中会实时调用queue.next()来检测mQueue中是否有消息,next方法中,会取链表头的消息,如果没有消息会调用nativePollOnce阻塞等待,一直等到enqueueMessage塞入队列一个消息,然后用jni方法nativewake控制一个信号,通知nativePollOnce醒来。如果有消息,但是消息延时的时间还没有到,那么会阻塞等待时间差的长度,消息准备好后它就会调用msg.target.dispatchMessage(msg);把消息发送给相应的对象,这样消息就发送出去了
5、在Looper调用了quit或者quitSafely后loop中调用queue.next()会返回null,这样,looper就退出死循环了。
网友评论