Android中Looper,MessageQueue,ThreadLocal源码解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pihailailou/article/details/78746774

一,写在前面

       之前写过一篇关于Handler机制的文章,写得还算比较全面,本篇文章侧重以Looper,MessageQueue,ThreadLocal三者间的关系进行分析。建议在阅读本篇文章前,先阅读文章  全面解析Android之Handler机制 。针对ThreadLocal的原理分析,可参考文章 Android中ThreadLocal的工作原理 。

       Handler类是Android提供给开发者的上层接口,只需要使用Handler+Message即可完成消息的发送和接受过程。事实上,一个完整的Handler机制是离不开Looper,MessageQueue的帮助,当然Android已经为我们封装好了Looper,MessageQueue要做的事情。

       Handler的使用场景,开发实践中三种使用方法等等描述,在文章 全面解析Android之Handler机制 都有涉及。具体来说, Handler可以轻松的让一个任务的执行切换到Handler所在的线程。与其说是Handler所在线程,还不如说是Looper所在线程,当然Handler的创建与Looper也是有巨大关系的。对这里不理解的哥们,可查阅文章 全面解析Android之Handler机制 。

二,主线程中Looper的创建

       如果研究过Android四大组件的工作流程,相信应该对ActivityThread很熟悉了, ActivityThread是代表主线程的一个实例。Activity在启动前,需要先启动Activity所在的应用程序进程。应用程序进程启动是由ActivityManagerService$startProcessLocked方法来完成,最终会调用ActivityThread$main方法完成应用程序进程的启动。值得一提的是,这个main方法里完成主线程里Looper相关的操作,接下里以ActivityThread$main这个入口来分析。

       查看ActivityThread$main方法源码:
    public static void main(String[] args) {
        
	//...

        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
       第5行,创建主线程的Looper实例,并通过ThreadLocal存储Looper对象(后面会具体分析);
       第7行,创建ActivityThread实例;
       第8行,ActivityThread$attach方法里完成ContentProvider的启动,感兴趣哥们可以阅读文章  Android ContentProvider启动流程源码解析(8.0) ;
       第21行,进行消息循环,Looper不断抽取消息队列里的消息,并交给Handler处理(后面会具体分析);

        分析第5行,查看Looper$prepareMainLooper方法源码:
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    //继续查看...

    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();
    }
       第2行,调用Looper$prepare方法,传入参数为false。值得一提的是,Looper$prepareMainLooper方法是专门提供给主线程来创建Looper对象的,若在子线程中创建Looper对象,可以调用Looper.prepare(),它会调用Looper.prepare(true)。也就是说,主线程与子线程中创建Looper对象的区别:在于传入的参数不同,一个是false,一个是true。这里先做一个铺垫,后面会具体分析参数不同导致的问题。 继续看第13~18行...

       第14行,若ActivityThread中已经创建了Looper对象,那么再次创建会抛出异常。因此,我们不能在主线程中调用Looper.prepare(),否则抛出异常。ThreadLocal是存储和查询Looper对象的一个工具类,它在Looper类中结构:static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>()。对于ThreadLocal的原理分析,见文章 Android中ThreadLocal的工作原理 ,这里不再重复阐述。

       第17行,若ActivityThread中没有创建过Looper对象,那么new一个Looper对象,并调用ThreadLocal$set方法进行存储。
        需要明白一点的是,创建当前线程的Looper对象后,会通过ThreadLocal存储当前线程的Looper对象;同时若要获取Looper的实例,也是通过ThreadLocal来取数据。ThreadLocal可以很方便的在不同线程间,互不干扰的存储和查询数据。

       第23行,Looper的构造函数中,创建MessageQueue的实例。且带boolean类型的参数quitAllowed,它就是创建Looper对象时一步步传递下来的boolean值, 后面分析会用到这里
        Looper与MessageQueue的关系:线程中创建Looper对象时,Looper构造函数中会创建一个MessageQueue对象。

三,主线程中的消息循环

       在文章 全面解析Android之Handler机制 中有详细分析,Handler调用sendMessage相关的方法将消息发送到消息队列里,也就是最终会调用MesssageQueue$enqueueMessage方法完成这一过程,这是源码分析的第一条线。
       前面有讲到,ActivityThread$main方法第21行,调用Looper.loop()开启消息循环,获取消息对象并处理之,下面开始第二条线的分析。

       查看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;

        //...

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            //...

            msg.target.dispatchMessage(msg);

            //...

        }
    }
       第2行,通过ThreadLocal获取Looper的实例;
       第4行,若me为null,即没有创建Looper对象,抛出异常。
       可以得出这样一个结论:
       1,一个线程只能创建一个Looper对象,那么在该线程中,Looper.prepare()或Looper.prepareMainLooper()只允许调用一次;
       2,调用Looper.loop()时,确保该线程已经调用Looper.prepare()或Looper.prepareMainLooper();

       第6行,通过Looper的字段mQueue,获取MessageQueue的实例;
       第10行,开启无限for循环,不断的在MessageQueue中抽取消息并处理之;
       第11行,调用MessageQueue$next方法抽取消息;( 后面会具体分析
       第14行,若msg为null,无限for循环结束;( 后面会具体分析
       第19行,调用Handler$dispatchMessage方法处理消息,具体分析见文章 全面解析Android之Handler机制 ,这里不再重复阐述;

        分析第11行,查看MessageQueue$next方法源码:
    Message next() {
        
	//...code

        for (;;) {
            
	    //...code

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (false) Log.v("MessageQueue", "Returning message: " + msg);
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                //...code

            }

	    //...code
        }
    }
       第5行使用无限for循环,从消息队列里抽取消息,并将该消息从消息队列里删除。值得一提的是,消息队列的数据结构是单链表,有利于数据的插入和删除操作。对于抽取消息这一个过程的算法不做分析,并不是本篇文章重点。
       
       第35行,return msg,即当抽取出一个消息并返回时 ,无限for循环结束,next方法不再阻塞。消息交给Handler$dispatchMessage方法来处理,最后Looper完成一次循环操作。而,当没有MessageQueue中没有消息时,next的for循环就不会结束,next方法处于阻塞状态,导致Looper$loop方法也处于阻塞状态。

       第43行,若变量mQuitting为true,则return null。此时,MessageQueue$next方法的for循环结束。前面分析Looper$loop方法的第14行时提到,msg为null时,Looper$loop方法的for循环结束。
       
       要想使变量mQuitting为true,需要调用Looper$quit方法。
       查看Looper$quit方法源码:
    public void quit() {
        mQueue.quit(false);
    }
       
       继续查看MessageQueue$quit方法源码:
    void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            //...code

        }
    }
       第2行,变量mQuitAllowed有木有很熟悉,就是前面创建Looper对象时那个参数,在主线程中传入的是false。
       第3行,在主线程中调用Looper$quit方法时,会抛出异常,不会使主线程中Looper停止消息循环。
       第10行,变量mQuitting赋值为true,MessageQueue$next方法的无限for循环结束,并返回null。同时,Looper$loop方法的无限for循环也结束,消息循环停止了,当然只针对子线程中的消息循环。
       在实际开发中,若创建了子线程的Looper,当所要处理的消息都完成后,建议调用Looper$quit方法将子线程的消息循环关掉,否则子线程会一直处于等待状态。关闭Looper后,子线程会马上停止。

四,最后

       主线程中Looper的创建是调用Looper.prepareMainLooper(),开启消息循环是调用Looper.loop();
       MessageQueue的创建是在Looper构造方法中完成,它用于存储消息Message。其提供了enqueueMessage方法将Message插入到消息队列里,next方法获取消息队列里的Message,并删除该消息;
       ThreadLocal用于在不同线程中存储和查询Looper对象;





       

       






       





猜你喜欢

转载自blog.csdn.net/pihailailou/article/details/78746774