zoukankan      html  css  js  c++  java
  • handler+looper+messagequeue源码解析


    https://www.jianshu.com/p/b4d745c7ff7a
    handler机制源码

    1.handler机制的作用
    在多线程的场景中,将子线程中需要更新UI的操作信息传递到UI主线程。多个线程并发更新UI的同时 保证线程安全。

    Message
    线程间通信的数据单元(handler接受和处理的消息对象),存储需要操作的通信信息。

    Message Queue
    一种数据结构(先进先出)用来存储handler发过来的Message

    Handler
    主线程与子线程之间通信的媒介,线程消息的主要处理者.1、添加Message到MessageQueue中 2、处理Looper分派过来的Message.

    Looper
    MessageQueue与Handler之间的媒介,循环的取出MessageQueue里面的Message并分配给相应的Handler去处理。每个线程只能拥有一个Looper,但是一个Looper可以绑定多个线程的Handler
    即:多个线程可以向同一个Looper管理的MessageQueue中发送Message。

    handler发送消息的方式有2中
    handler.sendMessage() 和 handler.post()

    handler是怎样绑定线程的
    一个handler只能绑定一个Looper对象,一个线程只能绑定一个Looper,但是一个Looper可以有多个handler,一个线程也可以有多个handler。
    handler是通过绑定looper来绑定线程。
    是通过Handler的构造方法来绑定Looper的

    Looper的源码
    prepare();
    里面会调用prepare(true)方法
        public static void prepare() {
            prepare(true);
        }

        //去创建loopre对象
        private static void prepare(boolean quitAllowed) {
            //判断当前线程的loopre对象是否已经创建过 如果已经创建过就会抛出异常
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            //真正的去创建looper对象,并放进sThreadLocal中
            sThreadLocal.set(new Looper(quitAllowed));
        }
        //Looper的构造方法 创建Looper 和 MessageQueue的对象 和当前线程的引用
        private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            //获取当前线程的引用
            mThread = Thread.currentThread();
        }
        //主线程创建Looper的方法并且从sThreadLocal获取这个对象
        public static void prepareMainLooper() {
            prepare(false);
            synchronized (Looper.class) {
                if (sMainLooper != null) {
                    throw new IllegalStateException("The main Looper has already been prepared.");
                }
                sMainLooper = myLooper();
            }
        }
        //从ThreadLocal中获取当前线程的looper对象
        public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }        
        //获取主线程的looper对象
        public static Looper getMainLooper() {
            synchronized (Looper.class) {
                return sMainLooper;
            }
        }
        //获取当前线程的MessageQueue对象    
        public static @NonNull MessageQueue myQueue() {
            return myLooper().mQueue;
        }        
        //当前线程的引用是否是Looper所在的线程    
        public boolean isCurrentThread() {
            return Thread.currentThread() == mThread;
        }        
            
            
        //从开机到现在的毫秒数(手机睡眠的时间不包括在内)    
        final long now = SystemClock.uptimeMillis();    
        //当前消息的前一个消息
        Message prevMsg = null;    
        //当前的消息
        Message msg = mMessages;
        //如果当前的消息不为空并且处理该消息的handler也不为空
        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());
                    }        
            
            
    Message的回收和复用:https://www.cnblogs.com/leipDao/p/7850473.html    
    //使用的是单链表的数据结构sPool指向链表的头部
    private static Message sPool;
    public static Message obtain() {
            synchronized (sPoolSync) {
                if (sPool != null) {
                    Message m = sPool;
                    sPool = m.next;
                    m.next = null;
                    m.flags = 0; // clear in-use flag
                    sPoolSize--;
                    return m;
                }
            }
            return new Message();
     }        
    obtain()总结

    好了,到此主要逻辑就分析完了,obtain()主要逻辑就是先判断缓存池中是否存在空闲message,
    如果存在则返回头部message,并且指针指向下一个空闲message,
    然后头部的message与之后链表  断开连接。如果不存在空闲message则直接new一个直接返回        
            
            
            
    上面的逻辑都是从缓存池中获取的操作,那什么时候向缓存池中存放呢?
    public void recycle() {
            if (isInUse()) {
                if (gCheckRecycle) {
                    throw new IllegalStateException("This message cannot be recycled because it "
                            + "is still in use.");
                }
                return;
            }
            recycleUnchecked();
    }        
    void recycleUnchecked() {
            // Mark the message as in use while it remains in the recycled object pool.
            // Clear out all other details.
            flags = FLAG_IN_USE;
            what = 0;
            arg1 = 0;
            arg2 = 0;
            obj = null;
            replyTo = null;
            sendingUid = -1;
            when = 0;
            target = null;
            callback = null;
            data = null;

            synchronized (sPoolSync) {
                if (sPoolSize < MAX_POOL_SIZE) {
                    next = sPool;
                    sPool = this;
                    sPoolSize++;
                }
            }
    }

    recycle()最主要就是将当前message放入缓存池链表头部。        
            
    MessageQueue取出消息的原理: Message next() {}

    nextPollTimeoutMillis:阻塞的时间  -1表示会一直阻塞,0表示不阻塞  其他时间为具体阻塞的时间

    Handler是怎么发送消息到MessageQueue里面的,又是怎样处理消息的?

    1.通过
      private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
          super.handleMessage(msg);
        }
      };
        public Handler() {
        //第一个参数==null
            this(null, false);
        }        
            
        public Handler(Callback callback, boolean async) {
            if (FIND_POTENTIAL_LEAKS) {
                final Class<? extends Handler> klass = getClass();
                if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                        (klass.getModifiers() & Modifier.STATIC) == 0) {
                    Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                        klass.getCanonicalName());
                }
            }

            mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                    "Can't create handler inside thread " + Thread.currentThread()
                            + " that has not called Looper.prepare()");
            }
            mQueue = mLooper.mQueue;
            //此时这个值是空
            mCallback = callback;
            mAsynchronous = async;
        }
        public void handleMessage(Message msg) {
        }    

        public interface Callback {
            /**
             * @param msg A {@link android.os.Message Message} object
             * @return True if no further handling is desired
             */
            public boolean handleMessage(Message msg);
        }    
            
    可以看到在Handler创建的时候会绑定一个当前线程的Looper        
            
    在处理消息的时候:
        public void dispatchMessage(Message msg) {
            //如果msg.callback != null 标识是通过 handler.post(new Runnable() {}的方式发送消息的
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                否则就会回调我们的handleMessage方法。
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                否则就会回调我们的handleMessage方法。
                handleMessage(msg);
            }
        }
        handleCallback(msg);    就会执行下面的方法 进而回调我们的Run方法
        private static void handleCallback(Message message) {
            message.callback.run();
        }        
    发送消息:
    sendEmptyMessage(int what)
      --->sendEmptyMessageDelayed(int what, long delayMillis)
            --->sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
             消息入队列
        public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
            MessageQueue queue = mQueue;
            if (queue == null) {
                RuntimeException e = new RuntimeException(
                        this + " sendMessageAtTime() called with no mQueue");
                Log.w("Looper", e.getMessage(), e);
                return false;
            }
            return enqueueMessage(queue, msg, uptimeMillis);
        }
            
        private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;
            if (mAsynchronous) {
                msg.setAsynchronous(true);
            }
            //最终会跑到MessageQueue中去处理
            return queue.enqueueMessage(msg, uptimeMillis);
        }        
            
            
            
      

  • 相关阅读:
    linux查看系统挂载磁盘
    Jenkins REST API 实例
    Python中 __init__.py的作用
    转载:Python中打开文件的方式(With open)
    利用tail -f /dev/null命令防止container启动后退出
    echo -e 命令详解
    Python排序
    Linux操作系统下删除除具体文件或目录之外的文件
    linux pam模块学习
    vsftpd服务器配置
  • 原文地址:https://www.cnblogs.com/lianzhen/p/11686560.html
Copyright © 2011-2022 走看看