Android Handler之Handler消息取出和处理

Handler消息取出和处理

消息的取出

消息的取出主要是通过Looper的loop方法。
Looper.loop()主要是消息循环,从消息队列中获取消息,分发消息到Handler中。
查看一下loop的源码。

public static void loop() {

        // ---  1.获取当前Looper的消息队列MessageQueue -----
        
        // 第一步
        // 获取当前Looper对象
    final Looper me = myLooper();
    // myLooper()的作用是返回sThreadLocal存储的Looper实例
    // 若me为null,则抛出异常
    // 所以在执行loop()方法之前,必须执行prepare()方法,prepare()            //的作用是创建Looper实例
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    
    // 第二步
    // 获取Looper实例中的消息队列对象MessageQueue
    final MessageQueue queue = me.mQueue;

   // ......代码省略

        //------ 2. 消息循环,无限循环 --------------
        
        // 第三步
    for (;;) {
            // 从MessageQueue中取出消息
            // 第四步
        Message msg = queue.next(); // might block
        // 如果消息为空,则退出循环
        if (msg == null) {
        // No message indicates that the message queue is quitting.
            return;
        }

  // ......代码省略
        final long dispatchEnd;
        try {
        

                // 第五步
                // 分发消息到对应的Handler
                // 把消息派发到msg的target属性
                //target属性实际上是一个handler对象
            msg.target.dispatchMessage(msg);
            
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        
        // ......代码省略
    
      // 第六步
            // 回收消息
        msg.recycleUnchecked();
    }

}

消息循环Looper.loop(),主要作用的取出消息,通过以上代码分析,大致分为六步:

  • 第一步,获取Looper对象
  • 第二步,获取Looper实例中的消息队列对象MessageQueue
  • 第三步,while()无限循环遍历
  • 第四步,通过queue.next()从MessageQueue中取出一个Message对象
  • 第五步,通过msg.target.dispatchMessage(msg)来处理消息
  • 第六步,通过 msg.recycleUnchecked()来回收消息

其中第一二三步就别少了,第六步在
Message源码

下面介绍第四步和第五步。

MessageQueue.next()方法

MessageQueue.next()主要是从MessageQueue中取出一个Message对象,源码如下:

Message next() {
    //mPtr是关联到native层的一个long型变量,只有当MessageQueue被
    // 抛弃的时候(调用disposed()方法),mPtr才为0,这时直接return
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }
         // 记录空闲时处理的IdlerHandler的数量
    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    
    // native层用到的变量,在nativePollOnce(ptr,
    //nextPollTimeoutMillis)使用,
    //如果nextPollTimeoutMillis=-1,一直阻塞不会超时,
    //如果nextPollTimeoutMillis=0,不会阻塞,立即返回,
    //如果nextPollTimeoutMillis>0,最长阻塞nextPollTimeoutMillis
    //毫秒(超时),如果期间有程序唤醒会立即返回。
    int nextPollTimeoutMillis = 0;
  
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
        
                // 阻塞方法
        nativePollOnce(ptr, nextPollTimeoutMillis);
                // 同步锁
        synchronized (this) {
         // 获取开机到现在的时间
         final long now = SystemClock.uptimeMillis();
         
         //标记前一个message
         Message prevMsg = null;
         //获取消息队列中链表表头的第一个元素 
         Message msg = mMessages;
         //判断Message是否是同步屏障,如果是则执行循环,拦截所有同步消                     //息,直到取到第一个异步消息为止。
         if (msg != null && msg.target == null) {
         // 如果进入这个循环,则表示MessageQueue的第一个message就是 
         //同步屏障消息
          // 循环遍历,拦截所有同步消息,直到取出第一个异步消息
             do {
                  prevMsg = msg;
                  msg = msg.next;
          //退出循环的条件,msg==null,表示循环结束,
          //msg.isAsynchronous()为ture表示是异步消息,则退出循环
                } while (msg != null &&!msg.isAsynchronous());
            }
          
         if (msg != null) {
         //判断msg是否达到了执行时间
            if (now < msg.when) {
            //msg没有达到执行时间,设置一下阻塞时间
            //nextPollTimeoutMillis,进入下次循环的时候会调用
            //nativePollOnce(ptr,nextPollTimeoutMillis)进行阻塞
            nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
              } else {
              //msg已到执行时间
              //此时有消息,不能阻塞
                 mBlocked = false;
               //如果还有上一个元素
                 if (prevMsg != null) {
                 //上一个元素的next越过自己指向下一个元素
                      prevMsg.next = msg.next;
                  } else {
                  //如果没有上一个元素,说明是消息队列的头元素,直接
                  //让第二个元素变成头元素
                     mMessages = msg.next;
                  }
                  //msg要取出,msg的next指向null
                  msg.next = null;
                  if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                  //设置msg为正在使用的状态
                  msg.markInUse();
                  // 返回msg
                  return msg;
                }
            } else {
             //没有消息,会一直阻塞,直到被唤醒
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            //如果是退出状态,关闭消息队列,返回null,抛弃MessageQueue
            if (mQuitting) {
                dispose();
                return null;
            }
            
// 下面的代码是处理一些不紧急的任务
// 如果没有符合条件的消息,会处理一些不紧急的任务
// 每次调用MessageQueue.next(),这些代码只执行一次
            
            if (pendingIdleHandlerCount < 0
                  && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount =mIdleHandlers.size();
            }
            
            // 当执行过一次不紧急任务时,pendingIdleHandlerCount为
            //0,此时不会执行下面的代码,直接开始下一步循环
            if (pendingIdleHandlerCount <= 0) {
           // No idle handlers to run.Loop and wait some more.
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // Run the idle handlers.
        // We only ever reach this code block during the first iteration.
        //开始循环执行所有的IdleHandler,并且根据返回值判断是否保留
        //IdleHandler
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // Reset the idle handler count to 0 so we do not run them again.
        // IdleHandler只会在消息队列阻塞之前执行一次,执行之后改标示设
        //置为0,之后就不会再执行,一直到下一次调MessageQueue.next() 
        //方法。
        pendingIdleHandlerCount = 0;

        // While calling an idle handler, a new message could have been delivered
        // so go back and look again for a pending message without waiting.
        //当执行了IdleHandler 的 处理之后,会消耗一段时间,这时候消息
        //队列里的可能有消息已经到达可执行时间,所以重置该变量回去重新检
        //查消息队列。
        nextPollTimeoutMillis = 0;
    }
}

总的来说,MessageQueue的next()方法获取一个Message的时候,会执行下面的操作:

  • MessageQueue先判断消息队列中是否有同步屏障消息的存在,如果有的话,会循环取出第一个异步消息。

  • 当MessageQueue没有可以处理的消息的时候,它会进入阻塞状态,等待新消息的到来,在阻塞之前它会执行一次 IdleHandler处理不紧急的任务,所谓的阻塞其实就是不断的循环查看是否有新的消息进入队列中。

  • 当MessageQueue被关闭的时候,其成员变量mQuitting会被标记为true,
    然后next()返回null,在Looper.loop()的源码中可以看到,当获取的message为null时,会直接return。

msg.target.dispatchMessage(msg)

msg.target.dispatchMessage(msg)主要是进行消息的分发。

/**
 * Handle system messages here.
 */
public void dispatchMessage(Message msg) {
        // 1
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
            // 2
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}
  • 1.如果msg.callback不为空,则执行handleCallback(Message),然后最终调用message.callback.run()。
  • 2.如果msg.callback为空,但mCallback不为空,则执行mCallback.handleMessage(msg)。
  • 3.如果msg.callback 为空,且mCallback也为空,则执行handleMessage()方法。

在大多数情况下,消息分发后的处理是第三种情况,即handleMessage(msg),这一般是通过复写该方法的方式实现消息处理的业务逻辑。

以上就是消息的取出和处理的全部内容。

你可能感兴趣的:(Android Handler之Handler消息取出和处理)