Android Looper源码解析

  我们都知道,Android中使用Looper来管理线程的消息队列,我们可以看看Google的介绍

   Class used to run a message loop for a thread.  Threads by default do not have a message loop associated with them; to create one, call {@link #prepare} in the thread that is to run the loop, and then {@link #loop} to have it process messages until the loop is stopped.

   大意是,线程默认是没有消息队列的,此类会在一个线程中运作一个消息循环队列。如果想使用它,先调用Looper.prepare()方法,然后调用Looper.loop()方法。

   那它的原理是什么呢?为什么调用Looper的静态prepare()方法就能给当前线程加入Looper呢 ?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));
}

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

可以看出,我们调用prepare()方法,其本质上是调用了私有的prepare(true),并调用了Looper的构造方法创建了一个新的实例,里面初始化了MessageQueue(消息队列,我们以后也会解析其源码)。true表示我们创建的子线程的Looper是一定能被停止的,那么什么线程不能被停止呢?当然是我们的UI线程主线程。

我们在来看看  sThreadLocal.set(...);  这行代码:

public void set(T value) {
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values == null) {
            values = initializeValues(currentThread);
        }
        values.put(this, value);
}

我们可以简单把上面的代码理解为给当前线程加入了指向Looper的变量。我们以后就可以通过当前线程来获取对应的Looper对象。


二、myLooper()方法:

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

其调用的为:

public T get() {
        // Optimized for the fast path.
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values != null) {
            Object[] table = values.table;
            int index = hash & values.mask;
            if (this.reference == table[index]) {
                return (T) table[index + 1];
            }
        } else {
            values = initializeValues(currentThread);
        }

        return (T) values.getAfterMiss(this);
    }
即本质上是得到当前线程,然后获取其中的Looper对象。

所以,调用了prepare()方法之后,当前线程即保留了Looper对象的引用,我们可以通过myLooper()方法获取当前线程的Looper对象。

顺便贴出主线程初始化Looper的代码:

    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
可以看出,其调用了prepare(false)方法来为主线程创建一个不会停止的Looper,并且Looper类中一个静态的Looper对象,指向了主线程的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.");
        }
        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 (;;) {
            Message msg = queue.next(); // might block
            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()的方法就很简单了,其本质上是先从当前线程中得到Looper对象,然后在得到Looper对象中的MessageQueue对象,从中获取下一个Message对象,然后进行事件的分发。

从上面的解析也可以看出,Looper只是不停的从MessageQueue中不停的取出Message,然后在进行事件处理。而我们的Message的队列管理是由MessageQueue来执行的。




  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值