Android 源码阅读 | Handler

582 阅读5分钟

Android 源码阅读.png

相关推荐:

类注释

 * A Handler allows you to send and process {@link Message} and Runnable
 * objects associated with a thread's {@link MessageQueue}.  Each Handler
 * instance is associated with a single thread and that thread's message
 * queue.  When you create a new Handler, it is bound to the thread /
 * message queue of the thread that is creating it -- from that point on,
 * it will deliver messages and runnables to that message queue and execute
 * them as they come out of the message queue.
  • Handler允许用户发送 Message 和 Runnable,并进行处理。
  • 每一个Handler对象都关联着一个线程和线程中的消息队列。当你创建一个新的Handler的时候,它会去绑定线程和消息队列。
  • Handler创建后,它就开始工作,将 message 和 runnable 传递给消息队列,在适当的时机去处理他们。
 * <p>There are two main uses for a Handler: (1) to schedule messages and
 * runnables to be executed as some point in the future; and (2) to enqueue
 * an action to be performed on a different thread than your own.

Handler有两个主要的作用:

  • 安排 message 和 runnable 在未来的某些时刻去执行
  • 向不同的线程中的消息队列发送 message 和 runnable
 * <p>Scheduling messages is accomplished with the
 * {@link #post}, {@link #postAtTime(Runnable, long)},
 * {@link #postDelayed}, {@link #sendEmptyMessage},
 * {@link #sendMessage}, {@link #sendMessageAtTime}, and
 * {@link #sendMessageDelayed} methods.  The <em>post</em> versions allow
 * you to enqueue Runnable objects to be called by the message queue when
 * they are received; the <em>sendMessage</em> versions allow you to enqueue
 * a {@link Message} object containing a bundle of data that will be
 * processed by the Handler's {@link #handleMessage} method (requiring that
 * you implement a subclass of Handler).
  • message 和 runnable 的发送由下面几个方法进行:postpostAtTime(Runnable, long)postDelayedsendEmptyMessagesendMessagesendMessageAtTimesendMessageDelayed,post相关的方法允许你发送 runnable 给消息队列,并由消息队列在适当的时机运行,sendMessage允许你发送 message 给消息队列,并在适当的时候回调对应的Handler的 handlerMessage 方法
 * <p>When posting or sending to a Handler, you can either
 * allow the item to be processed as soon as the message queue is ready
 * to do so, or specify a delay before it gets processed or absolute time for
 * it to be processed.  The latter two allow you to implement timeouts,
 * ticks, and other timing-based behavior.
  • 当发送message或者runnable,你可以让它立即被处理,也可以延时一定时间后执行。
 * <p>When a
 * process is created for your application, its main thread is dedicated to
 * running a message queue that takes care of managing the top-level
 * application objects (activities, broadcast receivers, etc) and any windows
 * they create.  You can create your own threads, and communicate back with
 * the main application thread through a Handler.  This is done by calling
 * the same <em>post</em> or <em>sendMessage</em> methods as before, but from
 * your new thread.  The given Runnable or Message will then be scheduled
 * in the Handler's message queue and processed when appropriate.
  • 应用程序创建进程后,它的主线程就会专门用于运行消息队列,该队列负责管理顶级应用程序(活动,广播接收者等)以及任何Windows的创建。
  • 您可以创建自己的线程,并通过Handler与主线程进行通信,使用方法像以前一样调用 post , sendMessage 等方法,但是是来自您的新线程,然后,在消息队列中调度给定的 Runnable 或 Message ,并在适当的时候处理。

构造函数

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;
    mCallback = callback;
    mAsynchronous = async;
}

在构造函数中,会绑定一个Looper和一个MessageQueue,Looper如果没有指定,则默认是当前线程的Looper,MessageQueue则是由Looper内部初始化好。消息队列的消息处理回调我们可以通过重写 void handleMessage(Message msg) 的方法,当然也可以传入一个 Callback:

public interface Callback {
    public boolean handleMessage(Message msg);
}

当然,Looper我们也可以指定:

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

post 方法

post开头的方法都是发送一个 runnable 的,其有很多个:

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

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

getPostMessage 方法,获取一个 message,其实发送的 runnable最终也是发送一个 message:

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

最终调用的方法:

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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

最后还是调用了 messageQueue 的入队方法,可以看我们之前分析的 messageQueue 源码。

remove,sendMessage

同样的,sendMessage 是发送一个 message,remove移除一个消息或者runnable,其都是调用 messageQueue 的方法。

dispatchMessage

在 Looper 的源码里面,当从消息队列取出一个消息后,回调:dispatchMessage

public static void loop() {
   final Looper me = myLooper();
   //省略...
   for (;;) {
       Message msg = queue.next(); // might block
       //省略...
       // 1. msg.target,其实就是 handler 对象,调用分发方法
       try {
           msg.target.dispatchMessage(msg);
       } finally {
           if (traceTag != 0) {
               Trace.traceEnd(traceTag);
           }
       }
       //省略...
       // 2. 分发完成后,直接 recycle 回收 messageBean
       msg.recycleUnchecked();
   }
}

dispatchMessage 对消息进行分发:

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

在这里,如果我们实现了接口Callback,那么就不会调用handleMessage方法了。如果没有设置Callback,就会调用handleMessage。

总结

通过Handler我们可以向消息队列发送消息,和在适当的时候去处理消息。

  • 所有的发送都是封装成message对象发送

  • 如果我们实现了接口Callback,那么就不会调用handleMessage方法了

  • Handler默认构造函数中去绑定当前线程的Looper和MessageQueue

  • 结合Android消息机制的源码,我们整体有一个流程图:

Android的消息机制不仅仅可以用在UI线程上,也可以用于你自己的子线程。以UI线程为例子,在创建UI线程的时候,会初始化一个Looper,然后Looper里面初始化好对应的消息队列MessageQueue。Looper和MessageQueue绑定,Looper遍历MessageQueue中的消息,当队列为空的时候,就阻塞当前的线程,一直无限循环,当一有消息,并且其消息的触发时机符合(msg.when<=now)则取出Message,调用Message.target.dispatchMessage方法,把消息分发到对应的Handler作处理。

  • 既然Looper会阻塞UI线程,那怎么程序不会卡死掉呢?其实,正因为是阻塞线程,所以程序才不会退出。我们跑一个程序,像Java,都有一个Main函数,从Main函数入口,跑完后程序就结束了,但要想我们的程序不退出,就需要构造一个死循环,在死循环内,进行消息的处理。这里的Handler消息机制正式这样,制造一个消息队列,循环读取消息并处理。在上面的注释中知道,主线程负责管理顶级应用程序(活动,广播接收者等)以及任何Windows的创建。总结来说:
    • (1)主线程由于死循环会一直不退出
    • (2)发起事务处理不在循环内,而是由其他的线程发送的
    • (3)它处理事务是在循环内完成的,如四大组件的相关调用

码字不易,方便的话素质三连,或者关注我的公众号 技术酱,专注 Android 技术,不定时推送新鲜文章,如果你有好的文章想和大家分享,欢迎关注投稿!

技术酱