Handler机制

160 阅读3分钟

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);
  • 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取消同步屏障。

3.VSYNC(垂直同步)

思考ing...