• Android Handler机制(三)----Looper源码解析


    一、Looper

    Looper对象,顾名思义,直译过来就是循环的意思,从MessageQueue中不断取出message。

    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 prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.

    1.Looper的成员变量:

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // guarded by Looper.class
    
    final MessageQueue mQueue;  //一个MQ
    final Thread mThread;    //一个thread
    

    Looper的代码是非常简单的。在官方文档的注释中,它推荐我们这样来使用它:

    class LooperThread extends Thread {
        public Handler mHandler;
    
        public void run() {
            Looper.prepare();
    
            mHandler = new Handler() {
                public void handleMessage(Message msg) {
                  // process incoming messages here
                }
            };
    
            Looper.loop();
        }
    }
    

    先看看prepare方法。

    Looper.prepare

    public static void prepare() {
            prepare(true);
        }
    
        private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {//每个线程只能有一个looper
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            //设置本线程的looper。
            sThreadLocal.set(new Looper(quitAllowed));
        }
    

      注意prepare(boolean)方法中,有一个sThreadLocal变量(ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本),这个变量有点像一个哈希表,它的key是当前的线程,也就是说,它可以存储一些数据/引用,这些数据/引用是与当前线程是一一对应的,在这里的作用是,它判断一下当前线程是否有Looper这个对象,如果有,那么就报错了,"Only one Looper may be created per thread",一个线程只允许创建一个Looper,如果没有,就new一个。然后它调用了Looper的构造方法。

    Looper 的构造方法

    在上边调用了构造方法:Looper(quitAllowed),初始化了messageQueue并绑定当前线程。

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

    此时的初始化动作已经结束了,接下来看Looper.loop():

    public static void loop() {
            final Looper me = myLooper();//返回当前的looper
            if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }
            final MessageQueue queue = me.mQueue;//取得messageQueue
            
            for (;;) {
                Message msg = queue.next(); // might block
                if (msg == null) {
                    // No message indicates that the message queue is quitting.
                    return;
                }
                。。。。
                msg.target.dispatchMessage(msg);
                。。。
                msg.recycleUnchecked();
            }
        }

    loop()方法,省去了一些不关心的部分。剩下的部分非常的清楚了,首先调用了静态方法myLooper()获取当前Looper对象。没有looper则抛出异常。

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

    1. myLooper()同样是静态方法,它是直接从这个ThreadLocal中去获取Looper对象,拿到当前线程的Looper后;

    2. MessageQueue queue = me.mQueue;拿到与这个Looper对应的MQ,就开始无限循环,不断的从消息队列中取出Message,当获取到一个消息后,它调用了Message.target.dispatchMessage()方法来对消息进行处理。dispatchMessage这个方法在Handler中,就是处理message。

    3.msg.recycleUnchecked(),当这个msg处理完了,就没有用啦,把它回收到全局池中,注意不是销毁。

    总结

    Looper的代码看完了,我们得到了几个信息:

    • Looper调用静态方法prepare()来进行初始化,一个线程只能创建一个与之对应的LooperLooper初始化的时候会创建一个MQ,并和当前线程绑定,因此,有了这样的对应关系,一个线程对应一个Looper,一个Looper对应一个MQ。

    • Looper调用静态方法loop()开始无限循环的取消息,messageQueue调用next()方法来获取消息(这也是个无限循环)。

    MessageQueue源码解析:http://www.cnblogs.com/jycboy/p/5786682.html

     Handler源码解析:http://www.cnblogs.com/jycboy/p/5791457.html

    Message源码解析:http://www.cnblogs.com/jycboy/p/5786551.html

  • 相关阅读:
    课堂作业1(出题)
    微信小程序开发1
    asp.net实现通用水晶报表
    JS实现网络拓扑图
    注册与登录 接口与模板
    cookies and session
    Django路由及get请求post请求
    简析JavaScript事件冒泡机制
    屏蔽运营商流量球分析及解决方法
    使用github搭建个人主页
  • 原文地址:https://www.cnblogs.com/jycboy/p/5787443.html
Copyright © 2020-2023  润新知