Handler消息机制介绍,流程梳理

前言

Handler 是Android 的消息处理机制,其主要有两个作用:

1.发送消息,延迟处理。你可以通过Handler 来发送一个Message 或者Runnable 对象,并在收到消息时处理他们,另外可以指定延迟时间,以便在将来执行。

2.线程间通讯。简单来说就是在不同于Handler 所属的线程发送消息,在Handler 的依附线程中接受并处理消息。这也就要求Handler 实例必须与线程和线程的消息队列相关联,当创建一个新的Handler对象时,需要绑定到创建它的线程和线程的消息队列上,通过将Message/Runnable 添加到消息队列中,在它们从消息队列中出来时执行。

Handler 是整个消息机制的门面类,用来发送和接收消息。提供了两种形式的消息分发和处理,一种是post 一个Runnable 对象,另外一种是send 一个Message对象。

基本使用

发送和处理Runnable

Handler 支持通过 post 的相关方法来发送一个 Runnable 对象进入消息队列,当收到相应的消息时被调用。相关的方法有{@link #post}, {@link #postAtTime(Runnable, long)}, {@link #postDelayed}

Handler handler = new Handler();

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        // todo something
    }
}

// 立即发送
handler.post(runnable);

其他API介绍:

android.os.Handler#postDelayed(java.lang.Runnable, long)
将Runnable 添加到消息队里中,并在指定的延迟后执行

android.os.Handler#postAtTime(java.lang.Runnable, long)
将Runnable 添加到消息队里中,并在指定的时间执行

发送和处理Message

Handler 允许发送一个 message对象,实现 Handler的{@link #handleMessage}方法,在这里处理接收到的Message。相关的方法有{@link #sendEmptyMessage}, {@link #sendMessage}, {@link #sendMessageAtTime}, {@link #sendMessageDelayed} 等

private Handler mHandler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        // 处理消息 message
    }
};

// 获取 message
Message message = mHandler.obtainMessage(0);
// 发送 message 
mHandler.sendMessage(message);

其他API介绍:

android.os.Handler#sendMessageDelayed
将Message 添加到消息队里中,并在指定的延迟后发送,在handler的 handleMessage 中处理消息

android.os.Handler#sendMessageAtTime
将Message 添加到消息队里中,并在指定的延迟后发送,在handler的 handleMessage 中处理消息

流程梳理

使用Handler 发送一个Message时,在 MessageQueue 的enqueueMessage 方法中会对消息按时间优先级进行入队操作。
与线程绑定的Looper 不断的从MessageQueue中取消息进行发送(queue.next()),当某个Message 执行完毕后,释放资源并加入到缓存队列中以重复使用(msg.recycleUnchecked())

获取消息

虽然Message的构造函数是公共的,我们可以通过new 关键字来自行创建一个Message 对象,但是系统更推荐我们使用 {Message.obtain()}或{Handler#obtainMessage.obtainMessage()}相关的方法获取对象。

Handler 的消息获取内部采用了享元模式来实现,Message 内部有一个全局的缓存池sPool,保存着回收的Message 对象。当使用obtain() 方法时,会先从缓存池中获取Message 对象,如果没有再去创建一个新对象。在消息转发完成后,会对使用的消息进行回收再利用,节约因频繁创建对象带来的内存开销。

发送消息

Handler 提供了很多的 send 和post 的方法,这些方法最终都会走到android.os.Handler#enqueueMessage 这个方法,而在这个方法里又会调用MessageQueue 的enqueueMessage 方法执行消息的入队操作。
handler 调用流程

    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 msg, long when) 方法主要处理的就是入队操作,对新来的Message 根据绝对时间进行优先级排序,绝对时间小的Message往前排。

boolean enqueueMessage(Message msg, long when) {
        ...省略其他代码
        
        msg.when = when;
        Message p = mMessages;

        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;

        } else {
            ...省略其他代码
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                ...省略其他代码
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }
        ...省略其他代码
}

消息出队

在Handler 机制中,Looper类的主要作用是负责线程的消息循环,在Looper.loop() 方法中,循环不断的从MessageQueue.next() 函数中获取下一个消息进行派发,在发送完毕后回收释放该消息,完成消息的出队。

public static void loop() {
    final Looper me = myLooper();
    ...省略其他代码
    
    final MessageQueue queue = me.mQueue;
    for (;;) {
        // 从消息队列中获取下一个要执行的Message
        Message msg = queue.next(); // might block
        ...省略其他代码

        // 执行消息的分发
        msg.target.dispatchMessage(msg);
            
        ...省略其他代码
        // 释放、回收Message,完成消息出队
        msg.recycleUnchecked();
    }
}

理解

Handler:是消息机制的门面类,主要负责发送和处理消息,同样还有移除消息的功能。
Message:即要发送的消息,包含消息标记、消息数据、执行时间、处理响应的Handler等。
MessageQueue:内部包含一个由Looper调度的消息队列
Looper:负责线程的消息循环,从MessageQueue 中获取要发送的消息

以一家运输公司做个比喻
在这里插入图片描述

运输公司(Handler):承接货物的运输业务,负责货物的接受和发送。
运输车(Message):货物的载体,附带一些信息,比如所属公司(Handler)、编号(what)、运输的货物(arg1、arg2、obj)、发车时间(when)等等
备用车辆(Message.sPool):空闲状态的运输车,当有新需求的时候负责提供运输车辆
执行运输任务的车队(MessageQueue.mMessages):因任务而组成的运输车队,根据每辆车发车时间进行车辆排序。
调度站(Looper):负责对运输的车队车辆进行逐个派发

当客户有需求时,运输公司会从空闲的运输车中安排一辆车为其服务,货物打包好后加入执行运输任务的车队中。运输车队对新加入的运输车辆按发车时间进行排序。另一边,调度站如果发现有要执行任务的车队,则逐个对运输车辆进行派发,“下一辆、下一辆…”,如果没有,则处于等待的状态。运输车辆执行完当前任务后,把携带的信息清空,加入到备用车辆中,以供下次继续使用。

源码分析

本篇先对Handler 机制做个大概的介绍,源码部分将对Message、MessageQueue、Looper 分别做分析。

猜你喜欢

转载自blog.csdn.net/JM_beizi/article/details/106206959