欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Handler Looper源码解析(Android消息传递机制)

程序员文章站 2022-07-14 16:43:22
...

Android的Handler类应该是常用到的,多用于线程间的通信,以及子线程发送消息通知UI线程刷新View等等。这里我主要总结下我对整个消息传递机制,包括Handler,Looper,Message,MessageQueue类的理解。

 

Looper类:每一个线程都只能拥有一个Looper对象,这里Android是通过将Looper对象设置为当前线程的线程局部变量(这里涉及到ThreadLocal类),可以通过调用Looper.prepare()方法来使当前线程拥有一个Looper对象(主线程不用调用,因为主线程本身已经是拥有Looper对象了)。这里贴出prepare()的源码

 

public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");  /*如果当前线程已经拥有Looper对象,就会报错。*/
        }
        sThreadLocal.set(new Looper(quitAllowed));/*新建Looper对象并设置为当前线程的线程局部变量。*/
    }

 而Looper类的主要作用是进行消息循环,Looper类维护了一个MesageQueue,通过不停调用loop()方法来取出MeesageQueue中的Message并进行相应的处理。

 

 

public static void loop() {
        final Looper me = myLooper();  /*得到当前线程的Looper对象*/
        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;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycle();/* 回收msg(重复利用Message对象) */
        }
    }

 

这个留意到loop()方法里对Message的处理方式是调用msg.target.dispatchMessage(msg);,关于这个方法,我们了解完Handler后再看。

 

MeesageQueue:Message队列,队列就不详解了,先进先出。

Handler:Handler的作用主要是分发信息 相关方法有:

        post(Runnable)
        postAtTime(Runnable,long)
        postDelayed(Runnable long)
        sendEmptyMessage(int)
        sendMessage(Message)
        sendMessageAtTime(Message,long)
        sendMessageDelayed(Message,long)

 

 public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }


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

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


 public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }

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

 发现这些方法最后都是调用enqueueMessage(),看看这个方法的源码

 

 

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

 调用了MessageQueue的enqueueMessage方法,将Message对象加入了队列中去

 

再看看这几个方法

public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

 public final boolean postAtTime(Runnable r, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r), uptimeMillis);
    }

public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
    }

public final boolean postDelayed(Runnable r, long delayMillis)
    {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }

 发现post()系列的方法最后都是调用sendMessage系列的方法只是传入的Message对象有所不同,我们再看看getPostMessage()

 

 

  private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

    private static Message getPostMessage(Runnable r, Object token) {
        Message m = Message.obtain();
        m.obj = token;
        m.callback = r;
        return m;
    }

 发现其实就是把Runnable对象赋给Message的callback。通过以上代码的分析,基本上对整个消息机制有个概念了,当我们调用Handler的sendMessage()或post()等一系列方法时,Handler会将消息加入到MessageQueue中,这个MessageQueue为Handler对应的Looper对象所维护的queue(创建Handler时可以传入Looper对象,无参情况下为当前线程的Looper,想具体了解可以看下Handler的构造函数,这里不再赘述)然后由Looper类的loop()方法将消息取出。并做处理。至于怎么处理,我们就要看下msg.target.dispatchMessage(msg)这个方法了。我们知道msg的target是一个Handler对象,看下这个方法的源码

 

 

public void dispatchMessage(Message msg) {
/* 如果callback不为空,即发送消息的时候传入了Runnable对象,也就是调用的是post()系列的方法。那么就会执行handleCallback()这个方法,否则执行handleMessage() */
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

 handleMessge()方法想必大家都很熟悉,这个方法是我们new一个Handler对象时常常会去重写的,然后处理消息时会回调这个方法。再看看handleCallback()

 

 

private static void handleCallback(Message message) {
        message.callback.run();
    }

 代码很简单,就是调用了callback的run()方法。这里要特别注意的是调用的是run()而不是start(),这意味着将不会另起一个线程。而是在Looper对象所在的线程执行。至于为什么这么做笔者认为由于这样做即使是多次post也不需要开启多个线程,大大提高了程序的性能,同时,在某些情况下,我们希望能够顺序执行callback,那么使用这个方法无疑是非常棒的。当然,如果是要并发执行作那么就得使用其他法子了。总的来说post()方法相当于sendMessage()+handleMessage()使用方式的一种变体。