美文网首页
[Android] Handler、MessageQueue、M

[Android] Handler、MessageQueue、M

作者: 5ad8582eba93 | 来源:发表于2016-09-17 23:04 被阅读0次

首先我们来看一下Google官方实例代码。如下:

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();
    }
}

从中我们可以看出有以下几种对象:Thread 、Handler、Message以及Looper。让我们一个一个来分析。
首先,有一个线程LooperThread,它是Handler的执行场所。如图:

点击图片放大显示-1.png

然后执行Looper.prepare()方法,我们走进去看一下源码:

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));
}

而sThreadLocal是ThreadLocal<Looper>的实例。

// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

原来调用Looper.prepare()方法后系统内部帮我们new了一个Looper,并且把这个Looper实例放入sThreadLocal中,从而保证这个Looper是当前线程唯一的。so 我们就有了一个唯一的Looper实例。如图:

点击图片放大显示-2.png

既然有了实例,那我们接着看下Looper的构造方法,看看里面做了什么。

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

原来在构造方法里面又new了一个MessageQueue实例,从名字上来看,可能是一个存放Message的队列,既然是队列,所以它是先进先出(FIFO—first in first out)的。接着画图:

点击图片放大显示-3.png

可以看出调用Looper.prepare()方法后,系统帮我们创建了Looper和MessqgeQueue实例,可以分别通过Looper.myLooper()和mLooper.mQueue获得对应的实例。

/** 
* Return the Looper object associated with the current thread.  Returns 
* null if the calling thread is not associated with a Looper. 
*/
public static @Nullable Looper myLooper() 
{   
    return sThreadLocal.get();
}
...
final MessageQueue mQueue;
...

Looper.prepare()的分析暂时到这里。我们接着看下面,下面我们new了一个Handler实例,先看Handler构造方法(省略其他,最后调用的是下面这个构造方法)。

public Handler(Callback callback, boolean async) 
{    
    ...   
    mLooper = Looper.myLooper();   
    if (mLooper == null) 
    {        
        throw new RuntimeException("Can't create handler inside thread that has         not called Looper.prepare()");    
    }    
    mQueue = mLooper.mQueue;   
    ...
}

可以看到在Handler的构造方法里面初始化了Looper和MessageQueue对象,并且回调了handleMessage方法。如图:

点击图片放大显示-4.png

我们接着往下看,执行Looper.loop()方法。看一下Looper.loop方法的源码:

/** 
* Run the message queue in this thread. Be sure to call 
* {@link #quit()} to end the loop. 
*/
public static void loop()
{    
    final Looper me = myLooper();   
    if (me == null)
    {        
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");   
    }    
    final MessageQueue queue = me.mQueue;    
    // Make sure the identity of this thread is that of the local process,    
    // and keep track of what that identity token actually is.    Binder.clearCallingIdentity();    
    final long ident = Binder.clearCallingIdentity();   
    for (;;) 
    {        
        Message msg = queue.next(); // might block        if (msg == null) 
    {            
        // No message indicates that the message queue is quitting.   
        return;        
    }        
    ...   
}       
    msg.target.dispatchMessage(msg);        
...
}

首先拿到Looper的MessageQueue对象,无限循环(利用for(;;))取出MessageQueue里面的Message对象(果然MessageQueue里面放的的Message,哈哈)。取出以后调用msg.target.dispatchMessage(msg)方法。那么这个msg.target是个什么东东?看下Messqge的源码:

...
/*package*/ Bundle data;
/*package*/ Handler target;
/*package*/ Runnable callback;
...

原来是Handler,其实是调用了Handler.dispatchMessage(msg)方法。还记得我们初始化Handler的时候回调了handleMessage(msg)方法吗?我们大胆的猜想下,会不会在dispatchMessage(msg)里面调用了handleMessage(msg)?看下Handler.dispatchMessage(msg)方法源码:

/** 
* Handle system messages here. 
*/
public void dispatchMessage(Message msg) 
{   
     if (msg.callback != null) 
    {       
         handleCallback(msg);    
    } else 
    {        
        if (mCallback != null) 
        {            
            if (mCallback.handleMessage(msg))
            {                
                 return;            
            }        
        }        
       handleMessage(msg);    
    }
}

哈哈,果然调用了 handleMessage(msg)方法(这B装的太假了。。。)。
原来Looper.loop()方法就是在不停的取出MessageQueue里面的Message对象,并且执行handleMessage(msg)方法,所以初始化Handler的那个handleMessage回调会在这时候被调用。看图(表吐槽。。。):

点击图片放大显示-5.png

那么问题来了:
1,Message是怎么创建的?
2,MessageQueue里面的Message对象是怎么放进去的呢(从图中可以猜出是Handler放进去的)?
3,Handler是怎么赋值给msg.target的?。
我们回想下我们使用Handler的使用。

...
mHandler.sendEmptyMessage(0x01);
...

看下Handler的sendEmptyMessage源码:

public final boolean sendEmptyMessage(int what)
{    
    return sendEmptyMessageDelayed(what, 0);
}

接着走Handler的sendEmptyMessageDelayed方法。

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) 
{    
    Message msg = Message.obtain();    
    msg.what = what;    
    return sendMessageDelayed(msg, delayMillis);
}

原来Message对象在这时候被创建了,解决了问题1。再往下看Handler的sendMessageDelayed方法。

public final boolean sendMessageDelayed(Message msg, long delayMillis)
{   
     if (delayMillis < 0) 
     {        
        delayMillis = 0;    
    }    
    return 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);
}

终于出现MessageQueue对象了,是不是要放入Message到 MessageQueue 里面呢?接着看。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
 {   
    msg.target = this;    
    if (mAsynchronous) 
    {        
        msg.setAsynchronous(true);    
    }    
    return queue.enqueueMessage(msg, uptimeMillis);
}

haha, msg.target = this,这个this是当前的Handler对象,原来在这里把Handler对象赋值给msg.target,解决问题3,接着看MessageQueen的enqueueMessage方法:

boolean enqueueMessage(Message msg, long when)
{        
    msg.markInUse();        
    msg.when = when;        
    Message p = mMessages;      
    boolean needWake;       
   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
  {   
      // 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            
    prev.next = msg;       
 }
...        
}

其中有一句mMessages = msg。mMessages 保存的是当前消息队列,如果它为空就把消息添加到消息队列头,否则就要找到合适的位置将当前消息添加到消息队列。还记得Message是怎么取出来的吗(在Looper.loop方法里Message msg = queue.next(); )?看下queue.next()方法:

...
Message next() {
synchronized (this) 
{    
    Message prevMsg = null;    
    Message msg = mMessages;    
    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());  
    }    
   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);       
         } else
         {          
              // Got a message.           
               mBlocked = false;         
               if (prevMsg != null) 
               {       
                     prevMsg.next = msg.next;        
                } else 
                {               
                     mMessages = msg.next;        
                }           
               msg.next = null;   
               if (DEBUG) Log.v(TAG, "Returning message: " + msg);            msg.markInUse();       
     return msg;      
  }   
...
}
...

其中省去了许多代码,想看的同学可以自己去看看下。最后会返回找到的msg(其中没有分析msg.next还有msg.isAsynchronous),而Message msg = mMessages,所以在enqueueMessage里面被赋值的mMessages就被返回给了Looper.loop()里面的msg,紧接着回调msg.target.dispatchMessage()方法。这样所有的都关联起来了,大功告成。最后来张图:

点击图片放大显示-6.png

总结
1,1个线程有且只有一个Looper,在Looper里有且只有一个MessageQueue,这些对象的初始化都是在Looper.prepare()方法完成。
2,Handler往MessageQueue里面利用sendMessage方法添加Message,Looper利用Looper.loop()方法取出Message,并且回调msg.target.dispatchMessage方法.
3,在线程里必须调用一次Looper.prepare()和Looper.loop()方法。
4,主线程中怎么没见调用3中的2个方法?因为系统帮我们调用了。
(ps:由于第一次写简书,而且笔者水平有限,文中可能出现错误的地方,希望多多保函和指正。)

相关文章

网友评论

      本文标题:[Android] Handler、MessageQueue、M

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