美文网首页
Handler系列--Looper

Handler系列--Looper

作者: 小斌_bingor | 来源:发表于2019-03-23 19:10 被阅读0次

    前言

    本系列文章,将分享与Handler相关的知识,包括Handler的结构,运作流程,各个类的作用、之间的关系


    内容提要

    本篇文章将分析Looper的作用,以及主要的方法


    重要属性

        //线程局部变量,让每个线程存放自己的Looper
        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
        //主线程的Looper
        private static Looper sMainLooper;  
        //消息队列
        final MessageQueue mQueue;  
        //Looper对应的线程
        final Thread mThread;
    

    重要方法

    private Looper(boolean quitAllowed)

    Looper的构造方法

    • 1.这是一个私有的构造方法,想真正构造一个Looper,需要用prepare系列方法
    • 2.在这里就可以看到,消息队列由Looper创建,一个Looper,对应一个MessageQueue
    • 3.这里获取了当前线程,那么可以想见,Android一定在主线程就创建了属于主线程的Looper
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
    


    prepare系列方法
    public static void prepare()

    在当前线程创建一个Looper,如果需要为Handler自定义一个Looper,就需要调用这个。需要注意,在调用loop()方法之前,必须先调用prepare(),而当需要队列结束,则调用quit()

    private static void prepare(boolean quitAllowed)

    实际执行创建的方法

    • 1.通过ThreadLocal,存放属于线程自己的Looper,既防止多个线程访问到同一个Looper,也防止同个线程创建多个Looper
    • 2.队列是否允许退出,一经创建就不能更改
        /** Initialize the current thread as a looper.
          * This gives you a chance to create handlers that then reference
          * this looper, before actually starting the loop. Be sure to call
          * {@link #loop()} after calling this method, and end it by calling
          * {@link #quit()}.
          */
        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));
        }
    
    public static void prepareMainLooper()

    创建MainLooper,应用程序会在初始化的时候自动为我们创建MainLooper,所以我们自己永远不需要调用它,只需要在要用的时候getMainLooper()即可
    可以看到,mainLooper的创建,其实也是调用了prepare()方法,并且设置为不可退出,只是由于是在主线程创建的looper,并且在主线程调用了loop(),所以所有持有mainLooper的Handler,都得以在主线程执行handleMessage()

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

    我们重新捋一下Looper线程切换的逻辑

    • 1.应用程序在入口处(其实是在ActivityThread,有兴趣的可以去看一下源码)创建了一个不可退出的mainLooper,并且调用loop(),即是说,mainLooper在主线程不断地从MessageQueue取出到期的Message,执行handleMessage()回调
    • 2.我们在任意子线程创建Handler,并传入mainLooper(Looper.getMainLooper()),由于mainLooper里面存放了MessageQueue,等于说这个Handler所发送的Message,都会被在主线程里取出,并回调。这样就达成了线程切换
    • 3.总的来说,我们可以理解为,Handler这套机制,通过共享对象,达到了线程切换的目的


    public static void loop()

    Looper的核心方法
    其实很简单,一个死循环,将Message出列,当队列为空时,结束循环
    msg.target指的是Message持有的Handler

        public static void loop() {
            final Looper me = myLooper();
            final MessageQueue queue = me.mQueue;
    
            for (;;) {
                Message msg = queue.next(); // might block
                if (msg == null) {
                    return;
                }
                msg.target.dispatchMessage(msg);              
                msg.recycleUnchecked();
            }
        }
    


    public void quit()

    退出loop(),MessageQueue会把所有Message出列

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


    public void quitSafely()

    退出loop(),一般来说,建议使用quitSafely(),MessageQueue会把所有未到期的Message出列,但是到期的会继续发送

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


    public static Looper getMainLooper()

    获取主线程Looper

        public static Looper getMainLooper() {
            synchronized (Looper.class) {
                return sMainLooper;
            }
        }
    

    本篇内容到此结束,感谢收看~~

    相关文章

      网友评论

          本文标题:Handler系列--Looper

          本文链接:https://www.haomeiwen.com/subject/vxusvqtx.html