在面试的过程中,反复的被问到Handler机制,在此对其做一个深入的剖析.

Google源码对Handler的定义

    看Handler源码开关注释:

    Handler允许你发送和处理和线程的MessageQueue相关的Message和Runnable对象,每一个Handler对象都对应一个单一的线程。

一.先看看我们平时怎么使用Handler

   平时我们Handler用的最多的就是子线程刷新UI,在Activity里new一个Handler,实现handleMessage方法,然后在子线程里调用handler实例发送消息,handleMessage处理消息,刷新UI.

二.那怎么Handler就能实现刷新UI的呢

         就是,怎么就从子线程切到主线程了呢?建议大家有空看看操作系统的入门书籍,理解下线程和进程的概念.(我给大家推荐一本吧<<操作系统真象还原>>,第9章,详细介绍了线程和进程的概念和区别)

1.Handler创建

1)通过构造方法创建

第1种,不带Looper参数。
     public Handler(Callback callback, boolean async)     

 第2种,不带Looper参数。
    public Handler(Looper looper, Callback callback, boolean async)

注意这个Callback的实现方法handleMessage的返回值为true,则Handler的handleMessage不会被执行。看下面的这个源码就能明白:

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {        //这里
                    return;
                }
            }
            handleMessage(msg);
        }
    }
  • 子线程中创建Handler

    在子线程中,不可直接调用Handler的构造函数创建Handler对象,否则会报错:

    Can't create handler inside thread  xxx that has not called Looper.prepare()

    看源码可以知道Handler的构造方法获取的Looper为空就会报这个错

    mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }

    那么疑问来了,我们平时使用Handler的时候,直接就是在Activity里new Handler,也没有什么设置Looper的操作,为啥就没有报错呢?请往下看。

  • 在Activity里直接创建Handler

    看Looper.myLooper()方法,官方的解释就是获取和当前线程关联的Looper。

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

    只有Looper.prepare()方法被调用了,sThreadLocal才会有值。

    // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal sThreadLocal = new ThreadLocal();

    那么就找到一个线索了,主线程肯定某个地方调用了Looper.prepare(),so where is it?

 
   强烈建议详细(滴水不漏)看一遍ThreadLocal和Looper的源码,答案自然就揭晓了。
 

ThreadLocal的源码分析


ThreadLocal类并非是android特有的类,而是Java解决线程问题的一种手段。
 

  • AtomicInteger (原子自增操作,线程安全)
    https://blog.csdn.net/a260724032/article/details/81940785
    https://blog.csdn.net/fanrenxiang/article/details/80623884
  • ThreadLocal定义
    https://www.jianshu.com/p/6fc3bba12f38 (推荐)
    https://www.jianshu.com/p/69ae8c213b30
    https://www.imooc.com/article/45196
    https://blog.csdn.net/u011860731/article/details/48733073

    看了这么多文章,也没有对ThreadLocal这个类完完全全地理解。大致的意思就是ThreadLocal通过变量备份的方法解决了线程安全问题。
      
    在Looper类中,ThreadLocal就起着为线程存放记录Looper的作用。


  •   

Looper的源码分析


  • 官方定义
    为一个线程启动消息循环,线程默认是没有消息循环的。
  • ActivityThread
    源码各个击破之-Handler_第1张图片
    没有错,主线程的Looper就是在此绑定的。这就是为什么在主线程里可以直接new Handler的原因,系统已经给我们执行了Looper.prepare()和Looper.loop()方法。
     
    如果你勤学好问,那么,请看ActivityThread这个类,它并不是继承自Thread,更不是我们常说的主线程(UI线程)。Android主线程到底是个什么,你真正明白吗?
    https://blog.csdn.net/u011631275/article/details/47337385

2)通过静态方法创建

注意8.0之前的Handler是没有静态方法来创建的。

    //9.0开始有此方法
 @NonNull
    public static Handler createAsync(@NonNull Looper looper) {

    }
  //9.0开始有此方法
    @NonNull
    public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) {

    }
        //8.0开始有此方法
    /** @hide */
    @NonNull
    public static Handler getMain() {

    }
   //8.0开始有此方法
    /** @hide */
    @NonNull
    public static Handler mainIfNull(@Nullable Handler handler) {

    }

2.Handler使用

上面创建了Handler,现在我们就来使用Handler

1)执行Runnable

    /**
     * Causes the Runnable r to be added to the message queue.
     * The runnable will be run on the thread to which this handler is 
     * attached. 
     *  
     * @param r The Runnable that will be executed.
     * 
     * @return Returns true if the Runnable was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.
     */
    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

看看官方的注释,执行runnable就是在Handler关联的线程里执行runnable。
 

可以看到postXXX各种方法,最终还是通过getPostMessage方法将Runnable封装在Message里

    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

然后执行sendMessageXXX方法,最终也就是执行sendMessageAtTime方法。
 
post与sendMessage的区别就在于post,Handler的handleMessage是没有回调的,至于为什么没有回调下面会讲到。

2)发送Message

下面看sendMessageAtTime方法的源码

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}