美文网首页oldPAndroid开发Android技术知识
深入理解Handler机制之引路篇

深入理解Handler机制之引路篇

作者: 剑舞潇湘 | 来源:发表于2017-07-08 23:16 被阅读140次

    要想深入理解Handler机制,就要理解:

    • Android为何要引入Handler机制?
    • Handler机制究竟是什么?

    如果去查阅官方Handler文档,会发现官方没有给Handler下过定义,更没有介绍为何要引入Handler机制。官方文档的第一句就说Handler允许你发送和处理与一个线程的消息队列关联的消息和任务。这是对Handler能力和用法的一种描述,并没有讲为什么和是什么,这就造成初学者只知道怎么用Handler,但是不知道其背后的设计思想和原理。

    Android为何引入Handler

    要知道Android为何引入Handler机制,首先要了解Java线程机制:

    • 线程执行任务
    • 任务在线程的run方法中执行
    • run方法结束,线程终止

    这种机制的问题在于,创建线程的开销非常大,即使通过线程池重用线程,线程调度的开销对于数量多、密度大、要求快速响应的UI更新任务来说也是不可接受的,于是Android引入Handler线程解决这个问题。Handler线程就是Handler机制的核心:Handler线程永不退出,在run方法中轮询任务,有任务就处理,没任务就等待。

    有些Handler线程是允许退出的。

    Android应用的主线程是一个不允许退出、生命周期与进程一样长的线程。

    Handler机制工作原理

    Handler机制是一整套任务处理机制,需要Handler、Looper、Message和MessageQueue配合。

    • Looper在线程中死循环,使线程不退出
    • Handler发送和处理Message
    • Message包含任务或者执行任务所需的数据
    • Message发送给MessageQueue,MessageQueue负责Message的排序与出队

    Message是Android中的一个重要概念,它把Android应用从Java的任务处理系统变成了消息处理系统。

    Handler机制工作原理

    Looper

    要把一个线程变成Handler线程,只需在线程的run方法中调用Looper.prepare()和Looper.loop()。

    class LooperThread extends Thread {
        public void run() {
            Looper.prepare();
            Looper.loop();
        }
    }
    

    Looper的创建非常巧妙,是在Looper.prepare()中完成的。Looper实例存储在ThreadLocal中,可以通过Looper.myLooper()获取。Looper默认是可以退出的,要创建不可退出的Looper,需要调用Looper.prepare(false),主线程Looper正是这样创建的。要注意的是,一个线程只能与一个Looper关联。

    Looper创建后通过Looper.loop()完成工作。正如上文所说,Looper.loop()在Thread.run方法中轮询消息,使线程不退出、消息串行处理。

    // Looper.java
    public static void loop() {
        for (;;) {
            Message msg = queue.next(); // might block
            msg.target.dispatchMessage(msg);
        }
    }
    

    MessageQueue

    MessageQueue是在Looper的构造函数内创建的。由此可知,线程、Looper和MessageQueue三者是一一对应的。

    MessageQueue的主要工作是处理Message入列和安排Message出列。MessageQueue并不是常规的先进先出队列,而是根据Message期望执行的时间排列的。

    • 入列:boolean enqueueMessage(Message msg, long when)
    • 出列:Message next()

    这两个方法都有用到native代码,实现比较复杂,就不分析了(因为没看懂😄)。

    Message

    Message是一个数据类,携带要执行的任务(Runnable)或执行任务所需的数据(what、arg1、arg2、obj、data)以及任务处理者(Handler)和任务执行时间(when)。Message的实现是一个单链表结点,因此可以携带下一条Message。MessageQueue正是基于Message单链表实现的。

    由于是数据类,且应用中需要大量Message,因此Message实现了重用缓存池,通过Message.obtain()获取。与MessageQueue一样,Message缓存池也是基于其单链表实现的,不同的是缓存池是栈而非队列。

    Handler

    官方文档说,Handler与创建它的线程及该线程的MessageQueue关联(When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it)。这说的是不指定Looper的情况下,Handler自动与该线程的Looper关联,上文说,线程、Looper和MessageQueue三者一一对应,因此默认情况下,Handler与创建它的线程及该线程的MessageQueue关联。但在创建Handler时是可以指定Looper的,这样就会与Looper所在的线程和MessageQueue关联。

    不管Handler在哪个线程创建,它发出的消息都是在与之关联的Looper所在的线程处理的,这正是Handler用于线程间通信的原理。由于后台线程不允许更新UI,因此后台线程通过一个与主线程Looper关联的Handler(new Handler(Looper.getMainLooper()))来更新UI。

    Handler发送消息有两种方式:

    • sendMessage(Message)
    • post(Runnable)

    但其实就一种,因为Runnable也会转为Message。Handler发送消息还可以设置延时或定时,但最终也是一种,因为延时也会被转为定时任务。因此所有的发送方式最终都调用下列方法处理:

    // Handler.java
    public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    

    放入MessageQueue中的Message会被逐个取出,串行处理。有3处对象可以处理消息:

    1. Message自身callback(一般是post(Runnable)方式发送的消息)
    2. Handler创建时设置的mCallback
    3. Handler
    // Handler.java
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    

    HandlerThread

    Android应用的大部分消息都可以由主线程处理,如果需要在后台线程中处理消息,可以创建一个新的Handler线程。

    开发者并不需要自己实现Handler线程,直接使用内置的HandlerThread即可:

    HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
    handlerThread.start();
    Handler handler = new Handler(handlerThread.getLooper());
    

    源码篇和实现篇

    要想深入理解Handler机制,光凭一篇引路文章是不够的,更重要的是阅读源码、动手实践和总结分享。

    是不是很期待源码篇和实践篇?你来写!

    看好你哦~

    拓展阅读

    相关文章

      网友评论

      • 西瓜真好吃:这部分真是好晕哦,谢谢分享
      • ade68a7462a8:很棒,感谢分享。对于初学者很有用。收藏了,期待楼主更多的文章:stuck_out_tongue_winking_eye::stuck_out_tongue_winking_eye::stuck_out_tongue_winking_eye:

      本文标题:深入理解Handler机制之引路篇

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