彻底理解handler的实现原理

205 阅读3分钟

说到handler大家都很熟悉,自己也用了很久,再此总结一下 从handler的源码角度看看handler是如何执行的。

涉及到的内容: Loop Message MessageQueue ThreadLocal Handler

Looper的相关问题 先看一下new Handler();的源码 带我们了解looper; 创建Handler对象时,在构造方法中会获取Looper和MessageQueue的对象

public Handler() {

    this(null, false);
}

public Handler(Callback callback, boolean async) {

  ...省略部分代码..
    mLooper = Looper.myLooper();//这里获取一个mLooper
    if (mLooper == null) {//如果mLooper为null抛出异常
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

看到这里知道了。在使用new Handler()之前必须要有一个mLooper这个对象。不然的话会抛出异常。 接着看

public static @Nullable Looper myLooper() {//这里就返回一个mLooper 了 return sThreadLocal.get(); }

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

这里有个注意的就是ThreadLocal 这个类 就是每次创建一次都会有一个单独的线程出现,每个线程自己做自己的事情 互不干扰。其实呢这个Looper就是为了在该线程中 创建一个messageQueue。然后后面是把handler放到message中。然后再把message放到了messageQueue中。这样 这个handler就可以发送和接受 在该线程中的所有操作了。如果还不理解ThreadLocal的意思。请自行搜索。

比如你有一个主线程和10个子线程,现在呢这11个线程里面都new Handler()。就会有11个不同的ThreadLocal。他们之前不顾干扰。然后呢你就需要在这10个子线程里面写都写一遍Looper.prepare()和Looper.loop()。

比如你有一个主线程和10个子线程,现在呢这11个线程里面都new Handler()。就会有11个不同的ThreadLocal。他们之前不顾干扰。然后呢你就需要在这10个子线程里面写都写一遍Looper.prepare()和Looper.loop()。

我们现在已经有了获取looper的方法了。肯定也得有set的方法。 看 Looper.prepare();方法

public static void prepare() { prepare(true); }

private static void prepare(boolean quitAllowed) {//这个参数的意思就是这个messagequeue是否可以销毁
    if (sThreadLocal.get() != null) {//这里执行了获取ThreadLocal方法。如果已经存在了抛异常。所以 prepare方法在一个线程里只能执行一遍。
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed)); //这里执行了我们想要的set方法。 
}

//这个looper方法里面直接new出来了 MessageQueue() 和获取当前线程作为 标示 private Looper(boolean quitAllowed) {

    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

// True if the message queue can be quit. private final boolean mQuitAllowed;//这里是判断该messageQueue是否可销毁 MessageQueue(boolean quitAllowed) {

    mQuitAllowed = quitAllowed;//赋值
    mPtr = nativeInit();
}

Looper和MessageQueue是通过Looper.prepare的时候创建的,在一个线程里面prepare()只能执行一次 从这里我们可以看出来 new Handler();10次。会有10个Threadlocal,会有10个MessageQueue。 到这里我们还有个疑问就是为什么主线程没有写Looper.prepare();

原因是:ActivityThread.java里面在执行main方法的时候,已经对主线程的Looper进行了初始化。

到这里就明白了为什么 子线程执行 Looper.prepare()方法了。 再来看Looper.loop();

public static void loop() {

    final Looper me = myLooper();//获取looper
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;//获取该looper下的queue

            。。。。。。
    for (;;) {//死循环。我看的源码是api 23的。记得以前是while(true)。为什么捏
        Message msg = queue.next(); // might block  可能会阻塞
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
        。。。。。
        msg.target.dispatchMessage(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.loop()方法就是一个死循环不断地从messageQueue中获取msg