Android 学习笔记之Handler 总结

242 阅读7分钟

1、Handler存在的意义

Hnadler主要应用于通信,大大降低了Android 开发难度,降低了并发问题的可能性,几乎没出现死锁

Handler的学习知识点,大方向的总结如下:

1、工作流程

2、源码

3、设计思路

4、设计模式

5、异步消息与同步消息

6、消息屏障

7、HandlerThread

8、IdeHandler

在看Handler源码之前,首先了解下Handler的工作流程。

Handler的工作流程

截图.png

Handler的消息机制就类似于一个传送带

1、Handler将msg放到MessageQueue上,sendXXX()与postXX()->都会指向handler.senMessageAtTime() ,最后调用messageQueue.enqueueMessage(),将msg插入到messageQueue队列中。

2、由Thread提供动力,让Looper.loop()去让传送带运行起来

3、最后调用handler.dispatchMsg()->handleMessage()将msg由子线程传递给主线程进行处理,实现通信。

源码分析

MessageQueue()源码分析点:

1、next()方法

2、enqueueMessage()确定MessageQueue的数据结构

3、quit()方法作用

enqueueMessage()源码分析

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {//msg.target = handler,此处也是导致内存泄漏的主要原因
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }
    
    //synchronized 锁保证了同步的操作
    synchronized (this) {
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }

        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        //p == null 代表消息队列为空
        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 {
            // Inserted within the middle of the queue.  Usually we don't have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            //这个for循环展示的就是单链表的插入
            for (;;) {
                prev = p;
                p = p.next;
                //当前传进来的这个message带的when时刻小于当前的节点里的Message所运行的时刻
                //确定了当前的链表是按执行时间进行排序的
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);//唤醒
        }
    }
    return true;
}

next()方法源码分析

Message next() {
    // Return here if the message loop has already quit and been disposed.
    // This can happen if the application tries to restart a looper after quit
    // which is not supported.
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;//这个消息执行需要等待的时间
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        nativePollOnce(ptr, nextPollTimeoutMillis);//进行了休眠

        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {//取值前先判断是否有同步消息
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());//有同步消息,进行轮询,取异步消息出来执行
            }
            if (msg != null) {
                if (now < msg.when) {//取值时候会判断当前时间到没到这个msg执行时间
                    // Next message is not ready.  Set a timeout to wake up when it is ready.
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;//可以取到值,将该值返回
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                dispose();
                return null;
            }

            // If first time idle, then get the number of idlers to run.
            // Idle handles only run if the queue is empty or if the first message
            // in the queue (possibly a barrier) is due to be handled in the future.
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // Run the idle handlers.
        // We only ever reach this code block during the first iteration.
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // Reset the idle handler count to 0 so we do not run them again.
        pendingIdleHandlerCount = 0;

        // While calling an idle handler, a new message could have been delivered
        // so go back and look again for a pending message without waiting.
        nextPollTimeoutMillis = 0;//每次取完值,重置需要等待时间
    }
}

quit()源码分析

下面代码可以看出来quit作用,主要是清空消息队列,清空完后重新唤醒queue

void quit(boolean safe) {
    if (!mQuitAllowed) {
        throw new IllegalStateException("Main thread not allowed to quit.");
    }

    synchronized (this) {
        if (mQuitting) {
            return;
        }
        mQuitting = true;

        if (safe) {
            removeAllFutureMessagesLocked();
        } else {
            removeAllMessagesLocked();
        }

        // We can assume mPtr != 0 because mQuitting was previously false.
        nativeWake(mPtr);//重新对休眠进行唤醒,next()里会进行休眠
    }
}

问题:MessageQueue的数据结构是什么?

答:是一个优先级队列,内部是单链表实现,用插入排序实现的数据结构。

截图.png

当前要执行的是M1,M4与M1比较,比M1执行晚,则再往后对比,最前面消息是最早要执行的消息,取得永远是头部,优先级队列。

Looper的源码分析

Looper里主要的分析点: 构造函数 ,loop(), ThreadLocal的作用

构造函数分析

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);//队列初始化
    mThread = Thread.currentThread();//获取当前线程
}


public static void prepare() {
}

private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {//当前已有Looper,则抛异常,保证了唯一性
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));//将looper存到ThreadLocal中
}

loop()方法分析

public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;//获取messageQueue

    // Make sure the identity of this thread is that of the local process,
    // and keep track of what that identity token actually is.
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    // Allow overriding a threshold with a system prop. e.g.
    // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
    final int thresholdOverride =
            SystemProperties.getInt("log.looper."
                    + Process.myUid() + "."
                    + Thread.currentThread().getName()
                    + ".slow", 0);

    boolean slowDeliveryDetected = false;

    for (;;) {//循环取出当前的msg
        Message msg = queue.next(); // 取出当前的msg
        if (msg == null) {// loop暂停的方式就是msg == null
            // No message indicates that the message queue is quitting.
            return;
        }

        // This must be in a local variable, in case a UI event sets the logger
        final Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }

        final long traceTag = me.mTraceTag;
        long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
        long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
        if (thresholdOverride > 0) {
            slowDispatchThresholdMs = thresholdOverride;
            slowDeliveryThresholdMs = thresholdOverride;
        }
        final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
        final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

        final boolean needStartTime = logSlowDelivery || logSlowDispatch;
        final boolean needEndTime = logSlowDispatch;

        if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
            Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
        }

        final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
        final long dispatchEnd;
        try {
            msg.target.dispatchMessage(msg);//将取到的msg传递给handler的handleMessage()
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        if (logSlowDelivery) {
            if (slowDeliveryDetected) {
                if ((dispatchStart - msg.when) <= 10) {
                    Slog.w(TAG, "Drained");
                    slowDeliveryDetected = false;
                }
            } else {
                if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                        msg)) {
                    // Once we write a slow delivery log, suppress until the queue drains.
                    slowDeliveryDetected = true;
                }
            }
        }
        if (logSlowDispatch) {
            showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
        }

        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

        // Make sure that during the course of dispatching the
        // identity of the thread wasn't corrupted.
        final long newIdent = Binder.clearCallingIdentity();
        if (ident != newIdent) {
            Log.wtf(TAG, "Thread identity changed from 0x"
                    + Long.toHexString(ident) + " to 0x"
                    + Long.toHexString(newIdent) + " while dispatching to "
                    + msg.target.getClass().getName() + " "
                    + msg.callback + " what=" + msg.what);
        }

        msg.recycleUnchecked();
    }
}

Looper中的ThreadLocal

问题1:为什么Handler要用thredaLccal?

一个线程里只有一个threadLocal,threadLocal内部有一个ThreadLocalMap <唯一的threadLocal,value>,可以保证只有一个Looper和一个MessageQueue。ThreadLocal原理可以看我下面的博客链接

ThreadLocal的原理:https://juejin.cn/post/7087580708079665160

问题2:为什么一个线程只有一个looper?,为什么MessaeQueue也是唯一的?

答:看源码里,Looper初始化时候会用到ThreadLocal,ThreadLocal原理是只有一个自己的threadLocal变量,prepare()里初始化之后,将looper存到ThreadLocal里,再进行初始化会报错,故线程里的lopper是唯一的。

MessageQueue是final修饰,在Lopper初始化里实现的,一个Looper只初始化一次,所有一个线程对应的messageQueue也是唯一的,MessageQueue是个容器,跟随着Looper创建的。

Handler的设计思想和设计模式

生产者与消费者模式

截图.png

Handler通过queue.enqueueMessage()往MessageQueue添加消息,为生产者,Looper通过loop()->messageQueue.next()取消息,为消费者。

这个队列出现的问题: 阻塞

1、队列消息已满,发生阻塞

原因:Handler对MessageQueue没有做大小限制,因为这个MessgaeQueue不光Handler在用,系统主线程也会去调用,往里面插入消息,所以Handler不能对MessageQueue大小做限制,如果一直调Handler插入消息,等消息占用内存达到系统内存大小,就会满,出现卡顿,闪屏。 解决:开发时候,避免一直调用Handler发延时消息。

2、队列消息为空,looper取消息取不出来,阻塞。

A、取消息时,第一个消息还没到执行时刻,故不能执行,会造成阻塞 在loop()代码for(;;)里,下面片段采用重点片段

for (;;) {
    if (nextPollTimeoutMillis != 0) {
        Binder.flushPendingCommands();
    }
    //第一次循环,等待时间为0,继续往下执行
    //执行找到msg时,会对nextPollTimeoutMillis 赋值,所以这个地方就会等待
    nativePollOnce(ptr, nextPollTimeoutMillis);

    synchronized (this) {
        // Try to retrieve the next message.  Return if found.
        final long now = SystemClock.uptimeMillis();
        Message prevMsg = null;
        Message msg = mMessages;
        if (msg != null && msg.target == null) {
            // Stalled by a barrier.  Find the next asynchronous message in the queue.
            do {
                prevMsg = msg;
                msg = msg.next;
            } while (msg != null && !msg.isAsynchronous());
        }
        if (msg != null) {
            if (now < msg.when) {//当这个消息大于当前时间,说明还没到执行时间,会对nextPollTimeoutMillis赋值
                // Next message is not ready.  Set a timeout to wake up when it is ready.
                nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
            } else {
                // Got a message.
                mBlocked = false;
                if (prevMsg != null) {
                    prevMsg.next = msg.next;
                } else {
                    mMessages = msg.next;
                }
                msg.next = null;
                if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                msg.markInUse();
                return msg;
            }
        } else {//msg为空时,让nextPollTimeoutMillis =-1,会一直进行阻塞
            // No more messages.
            nextPollTimeoutMillis = -1;
        }

        // Process the quit message now that all pending messages have been handled.
        if (mQuitting) {
            dispose();
            return null;
        }

    ....
    }

 .....
}

看上面代码可以看到,MessageQueue在取消息时,在消息体还没到执行时间的阻塞,进行了处理,让其等待到时间,再继续往下执行。

B、消息队列为空

代码可以看到,当msg为空时,会把等待时间变成-1.此时就会一直进行等待。在重新调用enqueueMessage()时,会去判断是否需要唤醒。

boolean enqueueMessage(Message msg, long when) {
        ...
        ...
        ...
        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 {
            // Inserted within the middle of the queue.  Usually we don't have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {//判断当前队列是否睡眠,睡眠则唤醒
            nativeWake(mPtr);
        }
    }
    return true;
}

上面可以看到,当消息队列为空或者未到执行时间所造成的堵塞,在MessageQueue取消息时会进行处理。

享元模式

享元设计模式:减少对象的创建,减少内存,提高性能

Messgae的创建,最好是obtain()方法

public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {//判断现在的msg是不是空,不是空,可以直接复用
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

首先看一下,msg.recycleUnchecked(),这是享元模式的具体体现,在Looper.loop()方法结束后调用。

public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    ...
    ...
    ...

    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

       ...
       ...
       ...
        try {
            msg.target.dispatchMessage(msg);//msg在此处就回调给Handler
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        if (logSlowDelivery) {
            if (slowDeliveryDetected) {
                if ((dispatchStart - msg.when) <= 10) {
                    Slog.w(TAG, "Drained");
                    slowDeliveryDetected = false;
                }
            } else {
                if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                        msg)) {
                    // Once we write a slow delivery log, suppress until the queue drains.
                    slowDeliveryDetected = true;
                }
            }
        }
        ...
        ...
        }

        msg.recycleUnchecked();//用完之后调recycle回收
    }
}
```
void recycleUnchecked() {
    // Mark the message as in use while it remains in the recycled object pool.
    // Clear out all other details.
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = -1;
    when = 0;
    target = null;
    callback = null;
    data = null;

    synchronized (sPoolSync) {//将所有内容清空后,头插法插回到队列里
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}
```

为什么会这么用呢? 防止OOM, 每次new Message()都会占用内存,当申请之后用完了,虽然有fork机制处理,但是处理不一定及时,会出现一直申请内存,一直释放内存,出现内存抖动,出现OOM。 而上面可以看到msg使用完后,再头插法插回到队列中,继续使用,避免了内存抖动,不会出现OOM。

消息屏障之同步屏障与异步消息与同步消息

同步消息:正常的消息

异步消息:立即执行的消息,调用msg.setAsynchronous(true);即可设置成异步消息

消息屏障之同步屏障

场景:此时MessageQueue里面已经有个几十个任务,此时有一个任务十分紧急,必须立刻执行,如何去做?

首先看下MessageQueue的next()取Msg源码

Message next() {
    // Return here if the message loop has already quit and been disposed.
    // This can happen if the application tries to restart a looper after quit
    // which is not supported.
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {//msg不为空,msg.target为空
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());//开始轮询这个队列,直到找到下一个异步消息
            }
            if (msg != null) {
                if (now < msg.when) {
                    // Next message is not ready.  Set a timeout to wake up when it is ready.
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                dispose();
                return null;
            }

          ...
          ...
          ...

        // While calling an idle handler, a new message could have been delivered
        // so go back and look again for a pending message without waiting.
        nextPollTimeoutMillis = 0;
    }
}

上面的源码可以看到当msg.target == null时,会轮询找到下一个异步消息执行。会忽略后面排队的任务

在Handler发送消息时,sendMessageAtTime()->Handler.enqueueMessage(),可以看到我们正常插入的消息都是同步消息,是轮询执行。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;//每次都会给target赋值
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

那么怎么出现的msg.target == null 呢?

private int postSyncBarrier(long when) {
    // Enqueue a new sync barrier token.
    // We don't need to wake the queue because the purpose of a barrier is to stall it.
    synchronized (this) {
        final int token = mNextBarrierToken++;
        final Message msg = Message.obtain();
        msg.markInUse();
        msg.when = when;
        msg.arg1 = token;//此处的message赋值时,没有对target进行赋值

        Message prev = null;
        Message p = mMessages;
        if (when != 0) {
            while (p != null && p.when <= when) {
                prev = p;
                p = p.next;
            }
        }
        if (prev != null) { // invariant: p == prev.next
            msg.next = p;
            prev.next = msg;
        } else {
            msg.next = p;
            mMessages = msg;
        }
        return token;
    }
}

当我们调用了这个postSyncBarrier()之后,得到同步消息,怎么让Handler下一个调用的就是我们要执行的那个异步消息呢?

可以看到,里面有一个判断,!msg.isAsynchronous()

要继续发送一个异步消息,调msg.setAsynchronous(true),发送到队列里去,此时去遍历这个队列找到这个异步消息执行。比如UI 的刷新,ViewRootImpl的16ms刷新UI.

同步屏障参考博客https://juejin.cn/post/6844903910113705998

HandlerThread

好处:方便使用,保证了线程的安全,解决了异步的问题

正常自己使用的子线程中做操作,用Looper,代码如下

new Thread(new Runnable() {
    Looper looper;
    @Override
    public void run() {
        Looper.prepare();
        looper = Looper.myLooper();
        Looper.loop();
    }

    public Looper getLooper(){
        return looper;
    }
}).start();

上面的代码,可能会出现的问题,Looper需要退出,否则可能引起内存泄漏。 但是在主线程中获取Looper时,由于是异步操作,有可能出现主线程获取子线程Looper时,子线程中的Looper 还没有prepare()完成,要是想解决这个问题,需要自己加锁机制写,而HandlerThread就解决了这个问题。

解析下HandlerThread源码

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    /**
     * Constructs a HandlerThread.
     * @param name
     * @param priority The priority to run the thread at. The value supplied must be from 
     * {@link android.os.Process} and not from java.lang.Thread.
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
    /**
     * Call back method that can be explicitly overridden if needed to execute some
     * setup before Looper loops.
     */
    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {//加锁的机制,保证Looper初始化的完成
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    
 
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {//getLooper时候,会判断,先保证初始化完成才能获取
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

    /**
     * @return a shared {@link Handler} associated with this thread
     * @hide
     */
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

 
    public boolean quit() {//对Looper进行退出,防止内存泄漏
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    /**
     * Returns the identifier of this thread. See Process.myTid().
     */
    public int getThreadId() {
        return mTid;
    }
}

上面源码可以看到,HandlerThread完美的解决了自己写的时候出现的问题,当有主线程去获取子线程的Looper需求,或者子线程的Looper每次运行完都需要手动释放时,选择HandlerThread最合适。

IdeHandler

上面说到了MessageQueue的阻塞,在MessageQueue阻塞时候,就会触发IdeHandler,可以回调给主线程进行工作,先看IdeHandler的原理

/**
 * 当前队列将进入阻塞等待消息时调用该接口回调,即队列空闲
 */
public static interface IdleHandler {
    /**
     * 返回true就是单次回调后不删除,下次进入空闲时继续回调该方法,false只回调单次
     */
    boolean queueIdle();
}
```
Message next() {
    ......
    for (;;) {
        ......
        nativePollOnce(ptr, nextPollTimeoutMillis);
        synchronized (this) {
            ......
            //把通过addIdleHandler添加的IdleHandler转成数组存起来在mPendingIdleHandlers中
            // If first time idle, then get the number of idlers to run.
            // Idle handles only run if the queue is empty or if the first message
            // in the queue (possibly a barrier) is due to be handled in the future.
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {//当有延迟消息执行的队列才有值
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // Run the idle handlers.
        // We only ever reach this code block during the first iteration.
        //循环遍历所有IdleHandler
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                //调用IdleHandler接口的queueIdle方法并获取返回值。
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }
            //如果IdleHandler接口的queueIdle方法返回false说明只执行一次需要删除。
            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }
        ......
    }
}
```

当主线程处理好消息后,此时有线程空闲,可以用IdeHandler回调去处理一些预加载的东西,可以应用于启动优化,减少响应时间。