精简版Handler机制

精简版Handler机制

一.前言

 * <p>There are two main uses for a Handler: 
 * (1) to schedule messages and
 * runnables to be executed at some point in the future; and 
 * (2) to enqueue
 * an action to be performed on a different thread than your own.

官方文档给了Handler机制的两个主要用处:

  1. 定时执行任务

  2. 线程间通信

二. 用到的类

Message

官方定义:

/**
 *
 * Defines a message containing a description and arbitrary data object that can be
 * sent to a {@link Handler}.  This object contains two extra int fields and an
 * extra object field that allow you to not do allocations in many cases.
 *
 * <p class="note">While the constructor of Message is public, the best way to get
 * one of these is to call {@link #obtain Message.obtain()} or one of the
 * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
 * them from a pool of recycled objects.</p>
 */

简单来说Message就是信息载体,通过handler发送(post 发送的Runnable也会被封装成Message),主要成员变量:

  1. what 用来区分消息类别

  2. Arg1、Arg2、object 预制数据容器

  3. target 绑定Handler handler在发送Message对象的时候 会把自身赋值给target,在MessageQuene做消息分发的时候,才会回调对应的Hanlder处理消息

官方也给出了获取Message的推荐方法:

Message.obtain();
Handler.obtainMessage();

而Handler.obtainMessage( )最终也是调用了

Message.obtain()

@NonNull
public final Message obtainMessage()
{
    return Message.obtain(this);
}

public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;
    return m;
}

Handler

Handler 是我们使用最多的类,主要用来发送消息和处理消息。

主要方法:

new Handler().postDelayed();
new Handler().post();
new Handler().sendEmptyMessage();
new Handler().sendMessage();

这几个方法组中都会调用

public boolean sendMessageAtTime(@NonNull 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);
}

MessageQuene

/**
 * Low-level class holding the list of messages to be dispatched by a
 * {@link Looper}.  Messages are not added directly to a MessageQueue,
 * but rather through {@link Handler} objects associated with the Looper.
 *
 * <p>You can retrieve the MessageQueue for the current thread with
 * {@link Looper#myQueue() Looper.myQueue()}.
 */

Message的队列,本质是一个单链表,通过和Looper关联的Handler添加Message,可以通过Looper.myqueue获取到MessageQuene。

@UnsupportedAppUsage
    Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);//epoll 机制
            ...
            ...

这里有个重点,当Looper通过循环去获取Message的是时候,MessageQueue的next方法会先调用nativePollOnce方法,这个本地方法

private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/

这里用到了epoll机制

epoll是一种IO多路转接技术,在LINUX网络编程中,经常用来做事件触发,即当有特定事件到来时,能够检测到,而不必阻塞进行监听。

当messageQueue中没有message的时候,会让线程暂时休眠,而不是通过无限循环进行监听,提高性能

Looper

在列举的几个类中,个人认为Looper是个关键,它连接了Handler和MessageQueue,是一座桥梁,是整个Handler机制的引擎。

看下官方介绍对它的定义:

/**
  * Class used to run a message loop for a thread.  Threads by default do
  * not have a message loop associated with them; to create one, call
  * {@link #prepare} in the thread that is to run the loop, and then
  * {@link #loop} to have it process messages until the loop is stopped.
  *
  * <p>Most interaction with a message loop is through the
  * {@link Handler} class.
  *
  * <p>This is a typical example of the implementation of a Looper thread,
  * using the separation of {@link #prepare} and {@link #loop} to create an
  * initial Handler to communicate with the Looper.
  *
  * <pre>
  *  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();
  *      }
  *  }</pre>
  */

Looper通过名称可以看出它是一个循环体,Looper通过Looper.prepare()初始化并且保存在ThreadLocal中,和线程绑定,当调用Looper.loop() 的时候,开启循环,循环中不断去MessageQueue中获取Message,并执行消息分发。

官方距离Looper的使用过程,但我们看到在UI线程中我们并没有调用Looper的对应方法,应为Android系统在创建启动的时候就帮我们完成了这一步骤:

 public static void main(String[] args) {
 ...
 ...
 Looper.prepareMainLooper();
 ...
 ...
 Looper.loop();
 }

三.工作流程

介绍完主要的类,我们把几个类的职能串联起来就是Handler机制工作流程了:

  1. 线程使用Handler机制,首先创建Looper对象
    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");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
  1. Looper对象中创建MessageQueue

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    
  2. Looper对象开启循环

    public static void loop() {
    ...
    ...
     for (;;) {
     ...
     ...
  1. Handler发送消息到Looper对象中的MessageQueue中,Looper对象从中不断获取Message,并通过handler的dispatchMessage分发消息。

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

    发送消息时,handler会把自身赋值到Message中的target对象,这样做是为了在消息分发时各个handler能够处理需要自己处理的消息,避免混乱。

    try {
                    msg.target.dispatchMessage(msg);
                    if (observer != null) {
                        observer.messageDispatched(token, msg);
                    }
                    dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
                } catch (Exception exception) {
                    if (observer != null) {
                        observer.dispatchingThrewException(token, msg, exception);
                    }
                    throw exception;
                }
    

    去除message对象后,调用message对象的target对象的messageDispatched分发消息。

我们知道发送消息有多中方式:

new Handler().postDelayed();
new Handler().post();
new Handler().sendEmptyMessage();
new Handler().sendMessage();

那么它们的调用顺序是怎样呢?

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

这里非常清晰:

post的Runnable优先级最高

其次是handler声明的callback

最后是handler的handleMessage

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值