Android异步消息处理机制Handler

作者: IT枫 | 来源:发表于2016-11-18 09:44 被阅读116次

    简单来说就是在线程中开启无限循环,处理队列中的消息。

        @Override
        public void run() {
            Looper.prepare();
            synchronized (this) {
                mLooper = Looper.myLooper();
            }
            Looper.loop();
        }
    

    说明:数据结构队列:单链表。从如下源代码中看出,是一个单项链表。

    MessageQueue.java
    {    
        boolean enqueueMessage(Message msg, long when) {       
           Message p = mMessages;
                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 {
                    Message prev;
                    for (;;) {
                        prev = p;
                        p = p.next;
                        if (p == null || when < p.when) {
                            break;
                        }
                    }
                    msg.next = p; // invariant: p == prev.next
                    prev.next = msg;
                }
        }
    }
    

    问题一:无限循环?那会抛出异常的?没错,解决办法就是没有消息时阻塞。

    问题二:如何阻塞呢?

    问题三:又是如何唤醒线程的呢?

    无限循环追根溯源

    汇编语言实现无限循环

    fin:

    HLT
    
    JMP fin
    

    C语言实现无限循环

    fin:

    /**这里想写HLT,但是C语言不能使用HLT*/
    
    goto fin;    //这里是是有分号的
    

    Android Java实现无限循环

    
    for( ; ; ) {
    
    
    
    }
    

    1.线程中开启无限循环

    Looper.java

    
    Looper.java
    {
        public static void loop() {
            for(;;){
                Message msg = queue.next();//可能会阻塞
                if (msg == null) {
                    return;//退出函数,loop()函数结束导致main函数结束。
                }
            }
    
        }
    }
    

    2.获取队列中的Message对象

    MessageQueue.java
    {
    
        synchronized (this) {
            //Try to retrieve the next message.  Return if found.(试图获取下一条消息,如果有则返回)
            Message next() {
                //Handler target
                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.java
    {
        int flags;
        //<<位运算符,左移,左边的数值想左移动一位。
        //这里就是0001移动一位后变成0010
        static final int FLAG_ASYNCHRONOUS = 1 << 1;
        public boolean isAsynchronous() {
            //&位运算符,位与,位相同结果位1。
            //flag & 0010
            return (flags & FLAG_ASYNCHRONOUS) != 0;
        }
    }
    

    2.1.判断处理Message对象的的时间

    MessageQueue.java
    {
        Message next() {
            final long now = SystemClock.uptimeMillis();
            synchronized(this) {
                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);                   
                    }
                }
            }  
        }
    }
    
    Message.java
    {
        long when;
        Handler target;
        public Message() {    }
    
        /***/
        void recycleUnchecked() {
           when = 0;
        }
        /**回收*/
        public void recycle() {
            recycleUnchecked();
        }
    
        
        public long getWhen() {
            return when;
        }
    
    
    }
    

    2.2.MessageQueue如何组织Message队列的

    Message.java
    {   //以链表的形式存储Message对象
        Message next;
    
        private static Message sPool;
    
        private static int sPoolSize = 0;
    
        private static final int MAX_POOL_SIZE = 50;
    
        /**
         *返回一个新的消息实例从全球池。让我们在许多情况下,避免分配新对象。
         */
        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();
        }
    
        //<6>
        public void recycle() {
            if (isInUse()) {
                if (gCheckRecycle) {
                    throw new IllegalStateException("This message cannot be recycled because it "
                            + "is still in use.");
                }
                return;
            }
            recycleUnchecked();
        }
    
        //<7>
        void recycleUnchecked() {
            synchronized (sPoolSync) {
                if (sPoolSize < MAX_POOL_SIZE) {
                    next = sPool;
                    sPool = this;
                    sPoolSize++;
                }
            }
        }
    }
    
    MessageQueue.java
    {
        /**
         *
         *
         *<5>线程中调用到这个函数时是重点!重点!重点!
         *
         */
        boolean enqueueMessage(Message msg, long when) {
            //同步,在一个线程中
            synchronized (this) {
                if (mQuitting) {
                    msg.recycle();
                }
    
            }
        }
    }
    
    Handler.java
    {
        //<1>
        public final boolean sendMessage(Message msg)
        {
            return sendMessageDelayed(msg, 0);
        }
    
        //<2>
        public final boolean sendMessageDelayed(Message msg, long delayMillis)
        {
            if (delayMillis < 0) {
                delayMillis = 0;
            }
            return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
        }
    
        //<3>
        public final boolean sendMessageAtFrontOfQueue(Message msg) {
            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, 0);
        }
    
        //<4>
        private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;
            if (mAsynchronous) {
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);
        }
    }
    

    3.阻塞线程

    MessageQueue.java

    MessageQueue.java
    {
        Message next() {
            for(;;) {
                //刷新等待命令,猜测这里实现的就是线程阻塞,也是一个本地方法
                //查看注释:可能会阻止很长一段时间。
                Binder.flushPendingCommands()
                //这里调用了一个本地方法,方法名称上看--本地检测一次,检测什么呢?
                nativePollOnce(ptr, nextPollTimeoutMillis);
            }
        }
    }
    

    看到调用本地方法,是不是有种山穷水尽的嗡嗡感觉。其实看看上面描述的c语言无限循环代码大致就了解库中无非也就是这么实现的。

    队列中还有Message对象,但是处理该对象的时间未到,计算阻塞的时间。

    MessageQueue.java
    {
        Message next() {
            for(;;) {
                //nextPollTimeoutMillis阻塞时间
                nativePollOnce(ptr, nextPollTimeoutMillis);
                if (msg != null) {
                    if (now < msg.when) {
                        // 计算线程阻塞时间
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    }
                }
            }
        }
    }
    

    队列中没有Message对象,则无限期的阻塞直到有Message对象插入队列中时唤醒线程。

    MessageQueue.java
    {
        Message next() {
            for(;;) {
                //nextPollTimeoutMillis休眠时间
                nativePollOnce(ptr, nextPollTimeoutMillis);
                synchronized (this) {
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                
                }
                if (msg != null) {
                
                } else {
                    // No more messages.
                    //-1代表无限期的休眠
                    nextPollTimeoutMillis = -1;  
                }
            }
        }
    
        boolean enqueueMessage(Message msg, long when) {
            synchronized (this) {
                boolean needWake;
                if (needWake) {
                    //唤醒线程
                    nativeWake(mPtr);
                }
               
    
            }
        }
    
    }
    

    获取Message对象的代码写的非常好可以阅读学习学习

    相关文章

      网友评论

        本文标题:Android异步消息处理机制Handler

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