美文网首页
消息机制解析

消息机制解析

作者: 刘佳阔 | 来源:发表于2017-10-11 22:09 被阅读0次

    先上uml图

    handler.png
    1. 消息推送机制的主要角色: Handler 发送和处理消息的类.Message发送的消息对象.MessageQuene 消息队列,虽然叫消息队列,其实是单链表的数据结构,用来存储消息的类.Lopper,消息循环,不断的把消息从消息队列中拿出,交给Handler去处理.
    2. Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,可以分发Message对象和Runnable对象到主线程中.
    3. 先看ThreadLocal类.ThreadLocal是一个线程内部的数据存储类.他可以在指定的线程中存数数据,然后在指定的线程得到改数据.当某些数据是以线程为作用域并且不同线程有不同的数据副本时,可以考虑使用ThreadLocal.

    1. ThreadLocal 的set.get

    public T get() {
        Thread t = Thread.currentThread(); //得到当前线程
        ThreadLocalMap map = getMap(t);
       //ThreadLocalMap 是ThreadLocal的内部类.而每个Thread内部包含一个 ThreadLocal.ThreadLocalMap的变量,名字
    为threadLocals,getMap(t)返回线程的threadLocals.
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
        //map中有一个Entry[] 数组, Entry 就是当前线程保存的数据bean,
        table 通过ThreadLocal的hash值经过运算得到 当前线程的Entry 在table中的索引,
       然后通过索引找到Entry 返回给外边.
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }
    
    public void set(T value) {
        Thread t = Thread.currentThread(); //同样是找到该线程,
        ThreadLocalMap map = getMap(t); //得到线程的 ThreadLocalMap
        if (map != null)
            map.set(this, value);  //把要保存在线程中的值保存在map中的 table中.若table对这个ThreadLocal原来
    有数据就更新数据,没有数据就添加数据
        else
            createMap(t, value); //新建一个ThreadLocalMap,并赋值给Tread的threadLocals,同时新建table数组,把value保存起来.
    }
    
    可以看到,最终Threal保存数据,靠的是操作ThradLocalMap中的table数组.

    2. MessageQuene 的enqueueMessage和 next

    首先看一下Message 的主要参数
     Handler target.//发送Message的那个handler.
     Runnable callback . //handler.post(Runnable ) 方式发送消息时传递的参数.
     Message next; //当前msg执行完成后接下来要执行的msg的引用
     long when;  //消息需设置的延时时间,在入栈时会加入当前时间转化为消息需要执行的绝对时间.
    
     MessageQuene 的消息入队操作
     boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {  //msg是否正在被使用.
            throw new IllegalStateException(msg + " This message is already in use.");
        }
    
        synchronized (this) {
            if (mQuitting) { //表示线程需要退出了.消息加入失败
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                msg.recycle();
                return false;
            }
    
            msg.markInUse(); //把msg标记为使用状态,同上文照应.
            msg.when = when; //when表示消息需要执行的绝对时间
            Message p = mMessages; // mMessages表示队列中最先要执行的msg
            boolean needWake;
            //新增的msg比mMessage还要先执行,所以放在链表的头部
            if (p == null || when == 0 || when < p.when) { 
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else { //否则的话.就从mMessge 向后遍历,比较Message的when,将新增的msg插入到合适的位置
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next  //把msg插入到p前边
                prev.next = msg;
            }
    
            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) { 
                nativeWake(mPtr);
            }
        }
        return true;
    }  
    接下来看next 
       //返回一个msg出去.有可能是阻塞式的,因为他有一个循环一直返回msg
      Message next() {
          // Return here if the message loop has already quit and been disposed.
          // This can happen if the application tries to restart a looper after quit
          // which is not supported.
          final long ptr = mPtr;
          if (ptr == 0) {  //如果looper退出,就返回null
              return null;
          }
    
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {  //开始执行消息循环
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
    
            nativePollOnce(ptr, nextPollTimeoutMillis); 
    
            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();//得到当前时间
                Message prevMsg = null;  //相当于头结点
                Message msg = mMessages; //即将要执行的msg //相当于尾节点
                if (msg != null && msg.target == null) { //先排除掉同步的msg
                    // 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) { //到这里时.剩下了异步的msg
                    if (now < msg.when) { //标识msg的执行时间还没到. 就生成一个睡眠时间 nextPollTimeoutMillis 
                        // 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; //msg 就是即将要处理的消息把他从链表中移除
                        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) { //如果要退出的话.就结束msg队列的遍历 在 quite() 方法中赋值true
                    dispose();
                    return null;
                }
                  
                  //这里是对闲置handler的处理. 忽略------------------
       
        }
    }
    
    最后就清楚了,MessageQuene的next方法会阻塞,等到有msg到了且msg的执行时间到达,就把msg从链表中移除.返回出去.只有在返回了msg消息或者MessageQuene.quit被调用的时候才会退出循环.

    3.Looper 循环器.不断从MessageQuene中取出消息,交给Handler处理.

     1.构造函数和常量.
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); //在不同线程保存Looper的ThreadLocal.
     private static Looper sMainLooper;
     private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed); //直接创建一个MessageQueue 形参表示是否运行退出
        mThread = Thread.currentThread();  //拿到当前线程
    }
    
    2. //Looper 通过prepare 方法在线程中创建Lopper,
    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));
    }
    
    3. UI线程也是有Looper的,Looper 为主线程提供了 如下两个方法,本质也是通过prepare来创建Looper
    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;
        }
    }
    //拿到对应线程中的Looper方法
    public static Looper myLooper() {
          return sThreadLocal.get();
    }
    
    4.Looper 最主要的方法是loop(),loop会不断从MessageQuene中拿消息,然后交给handler处理
    public static void loop() {
        final Looper me = myLooper(); //得到当前线程的Looper对象
        if (me == null) { //需要在线程中先调用prepare 生成Looper 才能开启循环
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue; //拿到对应的消息队列
          //忽略--------
    
        for (;;) { //阻塞的循环
            Message msg = queue.next(); //  当MessageQueue的quite被调用,nxet就会返回null,然后looper也就终止循环了,此方法会阻塞
            if (msg == null) { 
                // No message indicates that the message queue is quitting.
                return;
            }
               //忽略--------------
             //target 就是当初发送msg的handler,到这里消息就交给了handler来处理
            msg.target.dispatchMessage(msg);
    
            //忽略-------
        
            msg.recycleUnchecked(); //消息回收
        }
    }
    
    5. looper的quite会调用MessageQueue的quite.然后在loop中遍历的msg就是null,然后Looper的循环就结束了.
     public void quit() {  
        mQueue.quit(false);
    }
    
     public void quitSafely() { //这两个方法的区别是,上边会直接结束loop()方法的循环,下边会等loop()将MessageQueue中的消息都处理完在结束loop()循环.
        mQueue.quit(true);
    }
    
    可见.Looper就是一个控制器,不断把MessageQueue中的msg取出交个msg对应的Handler去处理.

    4. Handler 兼顾发送消息和处理消息.

    1. 先看成员变量
    final MessageQueue mQueue;  //handler
    final Looper mLooper;
    final Callback mCallback; 内部接口,只有一个 handleMessage(Message msg); 方法
    2. 看构造方法,最后走向两个构造方法,
    public Handler(Callback callback, boolean async) {
         //忽略
        mLooper = Looper.myLooper();
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    //所以说,Handler所在的线程一定要有Looper,不然就会出错.
    3. Handler的sendMessage 和post 最终都会走入下边的方法
     private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis); //把消息和消息需要执行的之间加入到MessageQueue的消息链表中
    }
    //同样 移除消息也是调用MessageQuene的移除方法
    public final void removeMessages(int what) {
        mQueue.removeMessages(this, what, null);
    }
    4.所以,handler把msg发出后,就到了MessageQueue中了,然后Looper就阻塞式的取消息,当消息的执行时间到达,Looper就调用hander的dispatchMessage 来处理消息
       public void dispatchMessage(Message msg) {
        if (msg.callback != null) { //callback就是  Handler.post(Runnable) 的那个对象
            handleCallback(msg);  //调用runnable的 run方法  
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) { 这是handler内部类的执行方法,直接实现Handler时,就需要实现这种方法. new Hander(){ handlerMessage(); }
                    return;
                }
            }
            handleMessage(msg); //常规的执行方法 这是我们写内部类继承handler时的写法
              //public  class A extends Handler{  handlerMessage() }
        }
    }
    其实就是三种不同的 实现方式,handler会根据实现方式调用对应的方法.
    
    5.主线程中,系统自动为我们的Handler创建了Looper, 主线程是ActivityThread,入口方法是main,
    public static void main(String[] args) {
        //忽略 ---
    
        Process.setArgV0("<pre-initialized>");
        Looper.prepareMainLooper();
    
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler(); getHander 返回的是 mH
        }
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
    }

    相关文章

      网友评论

          本文标题:消息机制解析

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