1. ActivityThread(APP应用启动入口)
Looper.prepareMainLooper();
Looper.loop();
MessageQueue.next();
取出消息MessageQueue#nativePollOnce()
处于阻塞状态,主线程会释放CPU资源进入休眠状态(linux pipe/epoll)
msg.target.dispatchMessage(msg);
消费消息,msg.target是一个Handler
2. Looper(消息轮询)
- ThreadLocal Map结构,保存不同线程下的Looper,一个线程只能有一个Looper
- app启动的时候会创建一个主线程的Looper
3. MessageQueue(消息队列)
MessageQueue.next()
;MessageQueue.enqueueMessage()
;#nativePollOnce
阻塞等待#nativeWake
唤醒postSyncBarrier
开启同步屏障removeSyncBarrier
移除同步屏障
4. Handler(消息生产者和消费者)
sendMessage(Message msg);
生产消息,默认发送的是同步消息,还可以发送异步消息MessageQueue.enqueueMessage();
存入消息MessageQueue#nativeWake()
唤醒;通过往pipe管道写端写入数据来唤醒主线程工作(linux pipe/epoll)
dispatchMessage(Message msg);
处理消息优先级排列,异步>>同步,同步屏障是个标识,不会被消费- 1->
msg.Callback!=null;
- 2->
Message.Callback!=null;
->Message.Callback.handleMessage(msg)
- 3->
handleMessage(msg);
- 1->
enqueueMessage
赋值msg.target发送消息private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
5. Message(消息)
- 消息种类:
- 普通消息(同步消息)
- 屏障消息(同步屏障)
- 异步消息
- Callback
- 发送消息的最优先处理方式
- what
- 发送消息的序列(key)
- obj
- 发送消息的内容(value)
- target
- 需要消费消息的handler
面试题:
1. Handler作为消费者和生产者角度来说,他既是生产者也是消费者。
-
作为消费者角度:
- 首先APP程序的应用入口为ActivityThread下的main方法,调用Looper.prepareMainLoop实例化一个主线程Looper对象存储于ThreadLocal(类似于Map结构,一个线程只能实例化一个Looper)中。
- 然后调用Looper.loop无限轮询消息队列MessageQueue,使得app不会退出。Looper.loop中又调用了MessageQueue.next取出消息,再里头又调用了MessageQueue#nativePollOnce。没有Message就阻塞等待唤醒(linux pipe/epoll机制),有Message的时候返回Message。
- 然后让Message.target.dispatchMessage处理消息,这个target就是一个Handler。handler下的dispatchMessage处理消息分为三种:
- 如果消息自带callback参数,则执行callback.run
- 如果消息不自带callback,且Message.Callback不为空,则执行Callback.handleMessage
- 如果都不成立,则调用Handler.handlerMessage
-
作为生产者角度:
- 调用sendMessage发送消息到消息队列MessageQueue,调用了MessageQueue.enqueueMessage,利用MessageQueue#nativeWake唤醒阻塞等待的nativePollOnce。
2.Handler同步屏障是什么?
同步屏障就是阻止同步消息,优先进行异步消息的执行。它也是跟同步消息一样,根据时间来插入到消息队列中的适当位置,并且只会挡住它后面的同步消息的分发,但它不会唤醒在等待的消息队列。(target==null不一定是屏障消息,但是屏障消息一定target==null)
- 发送同步屏障消息
- 通过MessageQueue.postSyncBarrier插入到消息队列中,返回一个token值表示屏障的位置
- 移除同步屏障消息
- 通过MessageQueue.removeSyncBarrier(int token)传入一个token移除屏障
- 在Android中的例子
- Android 应用框架中为了更快的响应UI刷新事件在 ViewRootImpl.scheduleTraversals 中使用了同步屏障。
mHandler.getLooper().getQueue().postSyncBarrier()
开启同步屏障Choreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
发送异步消息。Choreographer内部有一个FrameHandler(Handler),通过postCallback实际上调用了postCallbackDelayedInternal,将msg.setAsynchronous(true)发送到消息队列中。- 在页面销毁或者加载完成后,会调用
ViewRootImpl.unscheduleTraversals
取消同步屏障。
- Android 应用框架中为了更快的响应UI刷新事件在 ViewRootImpl.scheduleTraversals 中使用了同步屏障。
3.VSYNC(垂直同步)
思考ing...