Android消息机制剖析—Looper篇

来源:互联网 发布:湖人12年纳什数据 编辑:程序博客网 时间:2024/06/08 22:50

本篇文章在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。    }



0 0
原创粉丝点击