1.处理消息过程
1.1 从HandlerThread开始
带有一个Looper的Thread,然后这个Looper可以被使用去创建Handler.
既然是一个Thread,那我就从run()开始!!进入Looper中.
1.1.1 Looper.prepare();
为当前线程初始化一个Looper对象,在调用Looper.loop()之前必须先调用该方法,结束时调用Looper.quit()
其中sThreadLocal是Looper中的一个静态常量.ThreadLocal用来存储线程的自己的成员变量,只与某个线程相关连;在Looper中定义,是存储当前线程的Looper对象(即,每个线程都拥有自己的Looper类型的变量)
1.1.2 mLooper = Looper.myLooper();
获取当前线程的Looper对象.
1.1.3 Looper.loop();
在当前线程中运行消息队列,loop()方法不会自己主动停止,需要调用quit()方法来停止.
1.2.Handler
1.2.1 Handler.dispatchMessage()
处理消息
1)handleCallback():Message中的callback成员属性是Runnable类型的,调用run()方法
2)如果Message没给callback赋值,就调用创建Handler时传进来的Callback.handleMessage(),或者执行Handler的子类实现的handleMessage.
以上是处理消息的过程,接下来分析Handler如何将消息发送到Looper的消息队列中.
2.发送消息过程
Handler发消息的方法:
sendMessage(Message msg),
sendEmptyMessage(int what),
sendEmptyMessageDelayed(int what, long delayMillis),
sendMessageDelayed(Message msg, long delayMillis)
最终都是调用的sendMessageAtTime(Message msg, long uptimeMillis)方法.
2.1 Handler.sendMessageAtTime(Message msg, long uptimeMillis)
其中,mQueue是当前线程中Looper的消息队列MessageQueue.uptimeMillis等于当前系统开机的时间+delayMillis
2.2 Handler.enqueueMessage()
3.MessageQueue
从上面的分析可以看出,消息链表是MessageQueue比较重要的部分,接下来主要分析MessageQueue中的next()和enqueueMessage()
3.1 MessageQueue.next()
-
mPtr是native层消息队列的地址,当mPtr=0的时候,代表调用的dispose()方法,代表消息队列已经被释放了.
mPtr在new MessageQueue时被初始化,调用nativeInit()方法,该方法是一个native方法,实际的实现在android_os_MessageQueue.cpp中
NativeMessageQueue的构造主要将成员变量mLooper赋值,与java层类似,Looper也是从当前线程中get该线程的Looper对象.
-
pendingIdleHandlerCount该局部变量指的是IdleHandler对象的数量,因为后面它的赋值是mIdleHandlers.size(),如果使用的Handler没有继承IdleHandler类,该变量在后面会被赋值为0,因为它不影响主要的循环逻辑,因此不过多描述.
Binder.flushPendingCommands():当后续操作会引起线程阻塞就调用该方法,具体的作用还不太了解.
-
nativePollOnce是一个阻塞方法,利用native层的epoll(Linux的管道机制)来实现,用来控制sendMessageAtTime时传入的uptimeMillis.
如果,nextPollTimeoutMillis=-1,则一直阻塞
nextPollTimeoutMillis=0,不阻塞直接返回
nextPollTimeoutMillis>0,最长阻塞nextPollTimeoutMillis毫秒,但如果其中程序被唤醒就直接返回.
因此,根据后续的代码可以看出,当链表为空的时候,nextPollTimeoutMillis=-1,该线程会一直阻塞,阻塞时对CPU资源的占用等极低.
4.最后就是从消息链表中取消息了,分3部分.
1)第一块判断:msg != null && msg.target == null,该判断条件是判断该msg是否是同步屏障,如果是同步屏障是找到异步消息,然后取出该异步消息.
同步屏障:Message分为3种消息,普通消息,消息屏障,异步消息.消息屏障中的target没有赋值,它的作用是用来保障它身后的异步消息比同步消息先被取出去处理.
通过postSyncBarrier(times)方法,将消息屏障根据when插入到消息链表中.
2)第二块now < msg.when,如果目前时间还小于当前要取出的消息的when,则重新设置阻塞时间.
3)第三块,就是将msg取出
3.2 MessageQueue.enqueueMessage()
- msg.markInUse():将要插入链表中的消息设置正在use.
when < p.when:判断当前要入队的消息的时间是否小于队列中头结点的消息的时间, 如果小于,就将当前消息设置为头结点.
其中mMessages是队列头节点.
2. 向队列中插入msg,逐个对比消息中的when,如果队列中的when大于msg的when了,就插入
3. 判断当前线程是否阻塞,若阻塞,唤醒线程.