Handler、Looper、MessageQueue源码解析—

2017-05-13  本文已影响0人  windfall_


Looper


在Handler的构造函数中有这样一行代码:

mLooper = Looper.myLooper();

Looper是干什么的呢?

Looper负责创建一个MessageQueue,然后开启消息循环,不断的从MessageQueue取出消息,再交给Handler来处理消息。

Looper中两个最重要的方法是prepare()和loop(),我们分别来看看这两个方法的实现。

当我们要创建一个Looper对象时,我们要调用prepare()方法:

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

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }```

sThreadLocal 是一个ThreadLocal对象,ThreadLocal以key-value的方式储存变量,并保证该变量线程间互不影响。prepare()方法在调用了set方法把一个new Looper对象存进去,所以可以看出prepare()方法只能调用一次,否则sThreadLocal不为空会抛出Exception。接下来进入到Looper的构造方法,一探究竟。

``` java
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // guarded by Looper.class
    final MessageQueue mQueue;
    final Thread mThread;
   
    ...
   
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

在构造方法中新建的一个MessageQueue,并获取当前Thread对象。

在Handler构造方法中调用了Looper的myLooper()方法:

    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

可以看出myLooper()方法通过ThreadLocal获取当前的线程的Looper对象,回到Handler的构造函数

    public Handler(Callback callback, boolean async) {
        ...
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
       ...
    }```

如果myLooper得到的Looper对象为空,则会抛出异常,也就是说在新线程我们如果要创建一个Handler必须要调用Looper.prepare()。那么,为什么我们在主线程不需要调用prepare()方法呢?

那是因为在ActivityThread中主线程的Looper已经开启:

public static void main(String[] args) {
    ...

    Looper.prepareMainLooper();
    ...
}```

在Looper中:

    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }```

所以在主线程再次调用prepareMainLooper()同样会报错。

再看Looper另外一个重要的方法,loop():

``` java
    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;

       ...

        for (;;) {
            // 从MessageQueue中不断取出消息
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

          ...
            try {
                //调用Handler的dispatchMessage (msg)方法
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }

            ...

            msg.recycleUnchecked();
        }
    }```

可以看到,loop()方法是一个死循环,从MessageQueue中不断取出消息,然后调用handler的dispatchMessage(msg)方法,交给Handler来处理消息。直到消息队列为空才能结束循环,当然,我们也是可以手动结束消息循环的,Looper提供了两个方法:

public void quit() {
    mQueue.quit(false);
}

public void quitSafely() {
    mQueue.quit(true);
}```

调用MessageQueue的quit方法:

    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);
        }
    }```

>当我们调用Looper的quit方法时,实际上执行了MessageQueue中的removeAllMessagesLocked方法,该方法的作用是把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过sendMessageDelayed或通过postDelayed等方法发送的需要延迟执行的消息)还是非延迟消息。

>当我们调用Looper的quitSafely方法时,实际上执行了MessageQueue中的removeAllFutureMessagesLocked方法,通过名字就可以看出,该方法只会清空MessageQueue消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler去处理,quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息。

具体实现我会在后面的MessageQueue中讲到。

以上就是Looper的大部分源码解析,读到这我们应该能大致知道Handler、Looper、MessageQueue消息处理机制大致是一个怎样的流程了。在Looper的源码中,我们遇到了一个新的东西——ThreadLocal,接下来我会带来ThreadLocal的源码分析。
上一篇下一篇

猜你喜欢

热点阅读