Handler的前世今生4 —— Handler

Handler文档

我们使用Handler其实就是就是2个功能:

  1. 发送消息
  2. 处理消息

但是在这之前 ,我们要做好准备工作,那就是必须得有LooperMessageQueue才行。

Handler就类似一个快递站,如果你没有对应的 运输设备(Looper)存储仓库(MessageQueue),就没办法运行啊。

1. 使用Handler的前提条件

通过源码,我们发现Handler其实有很多构造函数,但是最终都指向一个:

 public Handler(@Nullable Callback callback, boolean async) {
      // 此处省略监听 内存泄漏 的代码...
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

我们可以创建Handler都是要先获取到LooperMessageQueue 的.


2. Handler发送消息

消息的发送主要分为三种发送:

  1. 普通发送;
  2. 定时发送;
  3. 延时发送;

2.1 send方式

这些是Handler类关于sendMessage的方法。
sengMessage的重载

不得不感慨一下,如果使用Kotlin重写Handler,就不会存在这么多的重载方法啦。

那么Handler是如何处理三者(普通,定时,延时)的关系呢?这里不妨可以思考一下…

具体看一下源码的设计,验证一下我们的猜想:

2.1.1. 普通发送:sendMessage()

通过延时发送(sendMessageDelayed),设置延时为0来实现即时发送的。

  public final boolean sendMessage(@NonNull Message msg) {
  		// 注意这里,通过调用延时0发送,即:立刻发送
        return sendMessageDelayed(msg, 0);
    }

2.1.2. 延时发送:sendMessageDelayed()

具体的通过定时发送(sendMessageAtTime) 来实现的延时功能

 public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        // 这里:调用的定时发送—— 当前时间 + 延时时间
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
2.1.3. 定时发送:sendMessageAtTime()

消息在这里进行入队列操作,强调一点,真正的入队是由MessageQueue操作的

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

2.2 post方式

我相信大家在开发过程中,使用post() 的情况可能会更多一些吧。post 方式我们在使用过程上基本上都是与Runnable打交道,并未见到Message的身影。

难道Handler的消息机制不适用于post方式?今天我们去一探究竟。
post方式

先看一下使用最多的post()方法吧。

2.2.1. post()方法
  public final boolean post(@NonNull Runnable r) {
  		// 这里有个getPostMessage()方法
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
2.2.2. getPostMessage()

该方法给我们返回Message,将我们的Runnable赋值给Messagecallback属性。关于Message的更多内容,可以查看 Handler的前世今生3——Message

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

通过getPostMessage() 返回对应的Message对象,无缝对接 send方式。本质最后都是通过**sendMessageAtTime()**将消息入队。

2.3 消息的入队操作

强调一下:入队操作的主角是MessageQueue

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

2.4 消息的复用obtain()

可以看到,消息的复用本质上还是Message来做的,这里仅仅是做了一层封装,毕竟Handler才是Message的使用者。

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

3. Handler 处理消息

我们都知道Handler是自产自销,接下来我们就来讨论一下Handler 是如何处理消息的。

我们知道在Looper的loop()方法中,handler调用了其dispatchMessage()

/**
 * 最常用的方式
 */
 public interface Callback {
        /**
         * @param msg A {@link android.os.Message Message} object
         * @return True if no further handling is desired
         */
        boolean handleMessage(@NonNull Message msg);
    }
    
    /**
     * 继承Handler时重写该方法 
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(@NonNull Message msg) {
    }
    
    /**
     * Handle system messages here.
     */
    public void dispatchMessage(@NonNull Message msg) {
    	// post方式,则最终还是在post的runnable中执行
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
        // send方式,创建Handler中是否传入Callback,对应进行处理
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            
            handleMessage(msg);
        }
    }
  private static void handleCallback(Message message) {
  		// 妙啊...
        message.callback.run();
    }

可以看到消息处理操作是在Handler中进行的。消息出队列是在Looper中的loop()中进行的。

完美演绎啊,不得不感慨一下,这个设计真是太棒啦…


4. Handler的清理操作

在实际开发中,我们一般都会在Activity要销毁时,调用removeCallbacksAndMessages() 方法。

Remove any pending posts of callbacks and sent messages
其实就是MessageQueue清除post的回调和send的消息。

  public final void removeCallbacksAndMessages(@Nullable Object token) {
        mQueue.removeCallbacksAndMessages(this, token);
    }

5. 总结

  1. Handler的发送消息(post,send)最终都是sendMessageAtTime() 实现。
  2. post()是根据getPostMessage(),将RunnableMessage 进行绑定的。
  3. 消息的入队操作都是靠enqueueMessage()
  4. dispatchMessage() 分情况处理消息。

到这里,其实我们会发现,关于Message的重要属性 taget , callbackmAsynchronous 都已经在Handler中完成赋值,唯有 when属性 没有在Handler进行处理,奇哉怪哉…


希望大家能继续查看:Handler的前世今生5 —— MessageQueue

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章