天天看点

Android消息机制剖析—Looper篇一、Looper的创建二、Looper的loop()

本篇文章在android6.0基础上分析。

Looper在消息机制中扮演的角色是创造无限循环从Messagequeue中取得消息然后分发。

一、Looper的创建

只要调用Looper.prepare()方法之后,然后再Looper.loop()即可,这里两个方法都是static方法,表面没有任何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");//限制Looper.prepare()只能调用一次
        }
        sThreadLocal.set(new Looper(quitAllowed));//这里才是Looper对象的创建,放入sThreadLocal中
    }
           
<pre name="code" class="java">   private Looper(boolean quitAllowed) {
      mQueue = new MessageQueue(quitAllowed);//创造了Messagequeue
      mThread = Thread.currentThread();
  }
           

代码中提到了sThreadLocal变量,类型为ThreadLocal,ThreadLocal的特殊作用在:可以多个线程共享,但set和get的作用域都是线程内的。例如thread-1和thread-2两个线程都调用了Loop.prepare(),使用的ThreadLocal是同一个对象,但set()放入的Looper是分别属于各自的。

二、Looper的loop()

先看源码,核心的地方被我加了注释。

public static void loop() {
        final Looper me = myLooper();//从ThreadLocal中获取本线程的Looper对象,这个对象是用Looper.prepare创建的
        if (me == null) {//如果没有Looper.prepare,就调用了loop就会抛出下面的异常
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // 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();

        for (;;) {//最重要的就是这个死循环,4.0之前是while(true)
            Message msg = queue.next(); // might block,MessageQueue没有消息,执行next()就会线程阻塞,直到有消息为止。
            if (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
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

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

这个Loop是消息机制的核心所在,尤其是for(;;)这个死循环;上面代码关注四个点: (1)调用myLooper来判断是否已经用Looper.prepare()创建了Looper对象(ThreadLocal保存) (2)Loop循环每次都会从MessageQueue中获取一个Message(next()方法),如果没有则线程阻塞。 (3)如果获取了一个Message,则调用target(Hanlder)的dispatchMessage方法来分派处理这个Message。 (4)最后调用msg.recycleUnchecked(),来格式化这个Message,重新进入消息池;

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();//如果是线程thread-1调用,则获得的thread-1的Looper,如果是thread-2调动,获得的是thread-2的looper。
    }