美文网首页Android知识Android技术知识程序员
说说 Android 里的 Handler 的机制

说说 Android 里的 Handler 的机制

作者: cpacm | 来源:发表于2017-04-26 14:51 被阅读152次

    简介

    Q:什么是 Handler
    A:Handler 是 Android 系统里的消息处理机制,下面的一段文字是在 Handler 源码上的注释,它阐述了 Handler 作为消息处理机制的作用。

    Handler 是一个可以通过关联一个消息队列来发送或处理消息,Runnable对象。每个Handler都关联一个单个的线程和消息队列.当你创建一个新的Handler的时候它就将被绑定到一个线程或线程上的消息队列,从那时起,这个Handler就将为这个消息队列提供消息或Runnable对象,处理消息队列释放出来的消息或Runnable对象.

    Q:Handler 的主要用途
    A:(1)能够定时执行消息和Runable对象;(2)可以将一个执行的动作放在不同的线程中。

    Q:Handler 的主要用法
    A:通过一系列的 post、send 方法发送消息,通过 handleMessage 来处理消息。

    post(Runnable r)
    postAtTime(Runnable r, long uptimeMillis)
    postDelayed(Runnable r, long delayMillis)
    sendEmptyMessage(int what)
    sendMessage(Message msg)
    sendMessageAtTime(Message msg, long uptimeMillis)
    sendMessageDelayed(Message msg, long delayMillis) 
    

    Q:与 Handler 相关的一些类
    A:与 Handler 相关的主要是 Message,MessageQueue,Looper这些类。

    Message:消息的载体。
    MessageQueue:消息队列,主要功能是向消息池中投递消息和取走消息。
    Looper:线程的消息循环处理器。

    深入

    Q:各个类的对应关系
    A:每个线程只允许包含一个 Looper,每个 Looper 包含一个 MessageQueue。每个线程上可以生成多个Handler,Handler默认使用的是当前线程上的 Looper 。

    Q:如何确保每个线程上只有一个 Looper,且各个线程之间互不干扰
    A:Looper 类的实例必须通过方法 prepare() 创建,一个线程中多次调用 prepare() 方法将会抛出异常。Looper 实例将会保存在静态变量 ThreadLocal 中,ThreadLocal 实现了线程本地存储的功能,这样放入 ThreadLocal 对象的 Looper 对象就与线程关联在一起。

    Q:消息是如何按时间分发的
    A:向 MessageQueue 发消息使用的 enqueueMessage 方法,其方法在插入消息时根据时间来排序,时间早的插在前面。消息队列的组织利用了 Message 类中的 next 指针形成一个从头指向尾的单向链表,插入时计算是否需要唤醒处理线程。

    // 如果新来的消息时间比队列头的消息短则成为新的队列头,唤醒处理线程
    if (p == null || when == 0 || when < p.when) {
        // New head, wake up the event queue if blocked.
        msg.next = p;
        mMessages = msg;
        needWake = mBlocked;
    } else {
        ...
    }
    

    Q:消息队列是如何挂起,又是如何唤醒的
    A:MessageQueue 中的消息循环在方法 next() 中,而挂起和唤醒则是通过 native 层来实现。在 native 层的 Looper 类构造函数中创建了管道,同时使用 epoll 来监听读管道。epoll 的作用是监听管道上的数据,管道则用于线程间通信。

    nativePollOnce(ptr, nextPollTimeoutMillis);
    

    在 MessageQueue 的 next() 方法中会调用 nativePollOnce() 方法,该方法最后通过调用 epoll_wait()来执行等待操作。
    同样,调用 nativeWake() 可以唤醒处理线程。nativeWake()最终会调用到 native 层的 Looper 类的 wake()方法。wake() 方法通过向管道中写入数据来唤醒消息处理线程。

    Q:SyncBarrier 是什么
    A:SyncBarrier 或者叫“同步分割栏”,在 MessageQueue 类中有一个方法叫 enqueueSyncBarrier(long when),可以调用这个方法在消息队列中插入一条没有 Handler 对象的消息,这条不带 Handler 对象的消息就称为 “SyncBarrier”(开发者需要调用Looper的postSyncBarrier()来打入)。

    SyncBarrier就像一个卡子,卡在消息链表中的某个位置,当消息循环不断从消息链表中摘取消息并进行处理时,一旦遇到那么即使在分割栏之后还有若干已经到时的普通Message,也不会摘取这些消息了。此时如果还有消息需要处理,可以使用 setAsynchronous() 方法给消息做上标志。这也是‘普通Message’和‘异步Message’的区别了。

    总结

    概括的描述,无非就是通过 Handler 向 Looper 的 MessageQueue 发送 Message 消息,再由 Looper 在消息循环里处理。关于 Android 的消息机制能说的暂时就那么多了,详情可以结合代码源代码细细思考。


    一篇更详细的 Handler 机制——聊一聊Android的消息机制

    相关文章

      网友评论

        本文标题:说说 Android 里的 Handler 的机制

        本文链接:https://www.haomeiwen.com/subject/vkvizttx.html