Android 线程间通信机制 —— Handler消息通信

1 作用

​ A:Android 不允许子线程操作 UI,只允许主线程操作 UI,因此通过 Handler 来实现子线程通知主主线程更新UI;

​ B:Handler 的出现解决了主线程与子线程的通信问题;

【关于为什么说 Android 不允许子线程操作 UI 的简要解释:

​ 在 Android 视图的管理基类 ViewRootImpl.java 中,对于视图的计算、绘制等操作之前,都会进行 checkThread() 线程检查,如果当前操作线程不是主线程,那么会抛出异常中断当前操作,表示如下,

void checkThread() {
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can                      touch its views.");
        }
    }

​ 值得一提的是,ViewRootImpl.java 类是在 Activity 的 onResume 方法回调之后才创建的,那么也就是说在 APP 显示出来时,系统就已经对于主线程绘制 UI 有了判断;在 onResume 方法之前,如果用线程去创建一个 UI 组件,是不会有异常,当然,这种行为并不常用。

2 概念

2.1 主线程

​ 当应用启动时,系统的 AMS 服务会告诉 Zygote 进程,Zygote 进程会 fork 一个新进程作为应用进程。这里的主线程也就指的是应用进程。

2.2 子线程

​ 在应用中,很多耗时工作不会在主线程中完成,像是数据下载、网络请求等,那么会选择使用线程的方式,在子线程中去完成此类操作。

2.3 Message(消息)

​ Android 定义的在线程间通信的数据格式,主线程与子线程之间的通信,是通过封装 Message 消息,然后传递实现的。它相当于是线程间通信的数据格式封装类。

2.4 MessageQueue(消息队列)

​ Android 中定义的存储消息的数据结构,存取方式是 先进先出,消息队列在主线程中维护,存储 Handler 发过来的消息。消息队列中实际上是维护一个 单向链表 数据结构去管理消息的。

2.5 Handler(处理者)

​ Android 中定义 Handler 是作为主线程与子线程之间的通信媒介,是消息的主要处理者,主要包括两方面:

​ A:消息发送,将 Message 消息发送到主线程的 MessageQueue 中

​ B:消息接收,处理主线程 Looper 发送过来的 Message 消息

2.6 Looper(循环器)

​ Android 中定义 Looper 是作为循环读取 MessageQueue 的通信媒介,是消息的主要分发者,主要包括两方面:

​ A:消息获取,循环读取 MessageQueue 中的 Message 消息

​ B:消息分发,将从 MessageQueue 中读出的每一条消息分发给对应的 Handler 处理者

2.7 线程、Handler、Looper对应关系

​ 一个线程只能对应一个 Looper

​ 一个 Looper 可以对应多个 Handler

​ 一个 Handler 只能对应一个 Looper

3 工作原理

3.1 工作流程

步骤一 线程间通信准备

​ 内容:主线程创建 Looper,并开启 MessageQueue 消息循环

​ 序列图:
在这里插入图片描述

​ 详细流程:前面提到 APP 启动时,系统 AMS 会通过 Socket 告诉系统的 Zygote 进程,Zygote 进程会 fork 出一个新的进程作为 APP 主进程(这一部分涉及到应用启动逻辑,这里不展开详述,仅介绍 Handler 相关部分~)。在这个过程中,应用进程会调用 ActivityThread 类的 main() 方法,在这个方法中实现的就是 线程间通信的准备工作——创建了 Looper,并开启了 消息循环。

​ 下面引用一张图来描述这个过程,(大家对这个流程有兴趣可以点击链接可跳跃到引用处~)
引用图片在这里插入图片描述

​ ActivityThread.main()

public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

        // Install selective syscall interception
        AndroidOs.install();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");

        // 创建 Looper 对象
        Looper.prepareMainLooper();

        // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
        // It will be in the format "seq=114"
        long startSeq = 0;
        if (args != null) {
            for (int i = args.length - 1; i >= 0; --i) {
                if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                    startSeq = Long.parseLong(
                            args[i].substring(PROC_START_SEQ_IDENT.length()));
                }
            }
        }
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        // 创建 MessageQueue,开启 Looper 循环执行消息读取,消息分发
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

​ Looper 类

​ 这里我们又需要回到 Looper 类中去继续分析,步骤一提到 应用在启动的过程中,ActivityThread 类会去创建本进程的 Looper 和 MessageQueue。按照步骤一的流程,我们去整理下 Looper 类所用到的关键方法和变量。

public final class Looper {
	// sThreadLocal.get() will return null unless you've called prepare().
    @UnsupportedAppUsage
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    @UnsupportedAppUsage
    private static Looper sMainLooper;  // guarded by Looper.class
	@UnsupportedAppUsage
    final MessageQueue mQueue;
    final Thread mThread;
    
    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
     // 这里是 ActivityThread 类调用方法,为创建主线程 Looper 而封装的。
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    
    // 创建 Looper 对象,此方法并没有返回 Looper 对象,而是保存到 ThreadLocal 对象中。
    private static void prepare(boolean quitAllowed) {
    	// 注意,这里就是确保一个线程只能对应初始化一次Looper的代码位置
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        // 实例化 Looper 对象,并且加入到 ThreadLocal 对象中保存
        sThreadLocal.set(new Looper(quitAllowed));
    }
    
    // Looper 私有构造函数,创建 Looper 对象对应的 MessageQueue,并且记录当前线程
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    
    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
     // 获取 Looper 对象,是从 ThreadLocal 中获取,之前提到 Looper 对象没有返回,是保存到 ThreadLocal 对象中去,这里获取 Looper 对象,也是从 ThreadLocal 对象中去拿。
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

​ 从上面的 Looper 实例化的过程中,我们发现,能够确保线程拿到的 Looper 对象是本线程创建的关键在于 ThreadLocal 类中。

​ ThreadLocal 类型变量叫做线程变量,表示 ThreadLocal 中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程的独有变量。其原理就是基于线程维护一个 ThreadLocalMap 数据结构,数据以 Key - Value 的对应格式保存,Key 为 ThreadLocal 类,对应的 Value 是我们传入的数据。在获取的时候,会先根据线程去获取线程对应的 ThreadLocalMap 类,然后从 ThreadLocalMap 类中根据 ThreadLocal 获取数据。

步骤二:消息按序入队

​ 内容:子线程创建 Handler 对象,并构建 Message 消息通过 Handler 对象发送给主线程
​ 实现方式:Handler 提供两种方式去发送消息,sendMessage() 和 post();这两种方式都有不同的方式去处理消息,sendMessage() 方式是通过重写 handleMessage() 方法去完成消息的接收处理;post() 方式是通过传入一个 Runnable 对象,实现其 run() 方法,在 run() 方法中完成消息的接受处理。在分析具体的实现方式之前,还有一些疑点需要先分析。

​ 分析一 Handler 与 Looper 的绑定

​ 前文有提到,子线程使用 Handler 时,要绑定主线程的 Looper & MessageQueue,这一块的实现,Handler 的构造函数帮我们完成了,如下:

/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
	// 此 Handler 构造函数是常用的构造函数,它调用的是重载方法执行创建。
    public Handler() {
        this(null, false);
    }

/**
* Use the {@link Looper} for the current thread with the specified callback interface
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages.  Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
	// 创建 Handler 对象。
	// 参数分析:参数一 Callback 对象,见 Callback 分析;参数二 async 标识 Message 消息是否 异步
    public Handler(@Nullable Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

		// 这里 Looper.myLooper() 就是去获取了本线程的 Looper 对象。每个线程都对应一个 Looper 对象。
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        // 这里通过主线程的 Looper 对象,也就拿到了 主进程的 MessageQueue,那么后续的消息发送,其实就是往这个 Queue 里写入数据,完成 Message 消息的按序发送。
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

// Callback 分析:
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*/
	// Callback 接口,创建者需要实现 handleMessage() 方法去完成消息的接收处理。创建者提供一个 Callback 对象,跟重写 handleMessage() 的方式如出一辙
    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);
    }

​ 这里出现一个问题,多个应用进程会有多个 Looper 对象,那么子线程通过 Looper.myLooper() 去获取 Looper 对象的时候,如何确定拿到的就是对应主线程的 Looper 对象。解答:这里是我对于 线程 与 Looper 对应的一个误区,我原本理解认为每个进程都会创建一个 Looper,进程下的线程在创建 Handler 时是共享这个 Looper,Handler 会自动关联到 Looper 对象,关联到主进程的 MessageQueue,基于这个理解才引出子线程创建Handler时,是怎么区分是本进程的 Looper。实际上,每一个线程都对应一个 Looper 对象,如果你使用主线程的全局 Handler,那么由于这个 Handler 是主进程创建的,也就自然绑定主进程的 Looper 对象,这是一种实现;如果你使用的是子线程自定义的 Handler 对象,那么在使用默认 Handler 构造函数的情况下,Handler 对象是绑定自己线程的 Looper 对象,也就是说默认的子线程的 Handler 并没有绑定主线程的 Looper,这种情况下,就要先去获取主进程的 Looper,在通过 Handler 带参构造函数,把 Looper 对象传进去创建 Handler 以实现主进程 Looper 绑定。

​ A:主线程创建 Handler,此 Handler 绑定了主线程的 Looper & MessageQueue,其他子线程使用此 Handler 处理消息。

​ B:子线程通过 Looper.getMainLooper() 获取主线程的 Looper 对象,通过 Handler(MainLooper) 创建 Handler,绑定主线程的 Looper & MessageQueue。

实现方式一:Handler.sendMessage(Message msg)

​ A:新建 Handler 子类或者是匿名内部类,内部重写 handleMessage(Message msg) 函数,添加消息处理逻辑;

​ B:主线程创建 Handler 对象;

​ C:子线程创建 Message 消息;

​ D:子线程调用主线程创建的 handler 对象的 sendMessage(Message msg) 函数将消息发送到主线程的 MessageQueue 中去;

在这里插入图片描述

​ 子线程创建 Message 消息:Message 类的创建一般使用静态方法 obtain() 及其多个重载函数。我们来看一下 Message 的结构,是如何描述一条消息的。

在这里插入图片描述

​ 上面是 Message 类的类图,下面简要描述:

​ what:消息标识;接收方可以通过此标识区分消息

​ arg1:存储 int 类型值;

​ arg2:存储 int 类型值;

​ obj:存储任意数据 Object 类型消息对象;

​ target:Handler 对象,标记在主线程循环过程中,会将此消息发送给这里的 Handler 对象,进行消息处理。此 target 指向的是 发送此 Message 消息的 Handler 对象

​ callback:Runnable 对象,如果有值,可能是采用 post 方式发送的,在处理消息的时候,会调用此 Runnable 对象的 run() 方法执行消息处理逻辑;

源码分析:

​ Message类:

​ 构造 Message 消息的逻辑:

	/**
     *  源码分析 Message.obtain()
     * 	作用:创建 Message 消息对象
     *  obtain()封装原因:在创建消息对象时,仍然可以使用 new Message() 的方式创建,但是直接 new 的方式	  *  会直接分配内存;而 Message 类内部维护了一个 Message 池,obtain()方法会先去 Message 池中寻找 
     *  是否有可复用的 Message 对象,没有复用则再去新建,避免直接新建而浪费内存。
     */
    public static Message obtain() {
    	// 这里则是在 Message 池中寻找是否有复用的 Message 对象,obtain() 从池中获取
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        // 若 Message 池内没有对象可以复用,则还是用 new 的方式创建
        return new Message();
    }

​ Handler类

​ sendMessage() 处理逻辑:

	/**
     * 源码分析:sendMessage(Message msg)
     * 入参:Message 对象
     * 逻辑:调用 sendMessageDelayed()继续执行
     */
    public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }

	/**
     * 源码分析:sendMessageDelayed()
     * 入参:Message 消息;delayMillis 延迟时间
     * 功能:在 当前时间+延迟时间 之后,将消息插入到队列中
     */
    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    
    /**
     * 源码分析:sendMessageAtTime()
     * 入参:Message 消息; uptimeMillis 消息插入时间
     * 功能:获取消息队列,在 uptimeMillis 时间将消息插入到队列中
     */
    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);
    }
    
    /**
     * 源码分析:enqueueMessage()
     * 入参:MessageQueue 要插入的消息队列;Message 消息;uptimeMillis 时间
     * 功能:设置 Message 的 target 对象、Uid、Asynchronous;调用 MessageQueue 的 enqueueMessage() 函数将消息插入队列中
     */
    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        // target 参数,这里的 target 指向发送方 Handler 对象,后续主进程在 loop 时,会根据 target 值确定发送方执行处理逻辑
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        // 调用消息队列的 enqueueMessage() 函数将消息插入队列
        return queue.enqueueMessage(msg, uptimeMillis);
    }

​ MessageQueue类

​ 将消息按序插入消息队列的逻辑:

	/**
	 * 源码分析:enqueueMessage()
	 * 入参:Message 消息;when 时间
	 * 功能:这里是具体将 Message 消息插入消息队列的逻辑
	 */
	boolean enqueueMessage(Message msg, long when) {
		// 如果 Message 消息没有指定 target,抛异常,没有指定谁去处理消息
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        // 此处标识,此消息是否已经使用
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }
			// 异常情况排查完毕,开始具体插入逻辑
			
			// 首先标记 Message 消息已使用
            msg.markInUse();
            // 标识消息执行的时间,队列是按照消息时间进行排序入队的
            msg.when = when;
            // mMessages 这里我理解是获取的消息队列中第一个消息
            Message p = mMessages;
            // 是否需要唤醒
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
            	/* 此条件判断处理分析
            	 * p == null 情况代表 当前消息队列中没有消息
            	 * when == 0 情况代表 当前消息需要立刻处理
            	 * when < p.when 情况代表 当前消息需要在队列中第一个消息前处理
            	 * 以上三种情况下:需要重新定义消息队列的第一个数据。
            	 */
            	 
                // New head, wake up the event queue if blocked.
                // 如果 p 为 null,标识当前的消息队列中没有消息
                msg.next = p;
                // 初始化头消息,传入的消息是第一个消息
                mMessages = msg;
                // true 表示没有消息,阻塞线程; false 表示有消息,唤醒线程
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                // 将消息放入到队列中,消息按照 when 时间排序
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                    	/* 寻找 msg 消息应该处于消息队列的位置
            	 		 * p == null 情况代表 已经找到最后一个位置
            	 		 * when < p.when 情况代表 当前消息要在 p 消息前处理
            	 		 * 以上两种情况下:则找到 msg 在消息队列中按时间顺序应处的位置
            	 		 */
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                // 上述循环 break 位置,就是此条消息在消息队列中按时间顺序应处的位置
                msg.next = p; // invariant: p == prev.next
                // 插入消息
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

实现方式二:Handler.post(Runnable r)

​ A:主线程创建 Handler 对象;

​ B:子线程实现一个 Runnable 对象,可以是个匿名内部类,重写 run() 方法指定消息处理逻辑;

​ C:子线程调用 handler 对象的 post(Runable r) 函数将消息发送到主线程的 MessageQueue 中去;

​ post() 实现方式值得注意的点有两点:第一点,post方法执行之前子线程并没有去创建 Message 对象,那是因为在 Handler 源码实现中,基于 Runnable 对象帮我们完成 Message 的封装;第二点,Runnable 对象并没有创建新线程,而是发送消息到消息队列中,没有调用其 start() 方法。

在这里插入图片描述

源码分析:

​ Handler类:

​ post() 插入消息:

	/**
     * 源码分析:post()
     * 入参:Runnable 对象
     * 功能:通过 getPostMessage(Runnable) 方法构造一个 Message,将消息发送到消息队列中,此逻辑跟 
     * sendMessage() 逻辑一致
     */
    public final boolean post(@NonNull Runnable r) {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    
    /**
     * 源码分析:getPostMessage()
     * 入参:Runnable 对象
     * 功能:封装一个 Message 对象
     */
    private static Message getPostMessage(Runnable r) {
    	// 通过 obtain() 方法创建一个 Message 对象
        Message m = Message.obtain();
		// 指定 Message 的 Callback 函数,后续在处理 Message 时,会通过 callback 对象执行消息处理逻辑
        m.callback = r;
        return m;
    }
    
    // 下面的逻辑跟 sendMessage() 流程一致,分析同上
    
    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    
    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);
    }
    
    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);
    }

步骤三:消息循环分发

​ 内容:主线程循环读取 MessageQueue 中的 Message 消息,并分发

​ 序列图:

在这里插入图片描述

​ 实现方式:步骤一提到应用在启动过程中,在创建应用进程的过程中,会开启应用进程的 Looper 循环,循环读取 MessageQueue 中的消息,读取分发。

源码分析:

​ Looper类:

​ loop()函数:

	/**
     * 源码分析:loop() 函数
     * 入参:无
     * 功能:循环读取关联的 MessageQueue 队列中的 Message 消息,并分发处理
     */
    public static void loop() {
    	// 获取本 Looper 对象
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        // 获取 Looper 对象关联的 MessageQueue 对象
        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();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;

		// 开启循环读取
        for (;;) {
        	// 从队列中读取下一条 Message 消息
            Message msg = queue.next(); // might block 可能会阻塞
            // 这里的 msg == null,并不是说没有消息了,而是如果在消息队列正在关闭的情况下,会返回 null;
            // 如果消息队列中没有消息,上述会阻塞;
            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
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            // Make sure the observer won't change while processing a transaction.
            final Observer observer = sObserver;

            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;

            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            Object token = null;
            if (observer != null) {
                token = observer.messageDispatchStarting();
            }
            long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
            try {
            	// 分发消息,调用 Message 的 target Handler类型变量的 dispatchMessage() 方法处理消息
                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;
            } finally {
                ThreadLocalWorkSource.restore(origWorkSource);
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery", msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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);
            }

			// 将 Message 添加回收标记后,放入 Message 消息池中,以便重复使用
            msg.recycleUnchecked();
        }
    }

​ 这里可能会出现一个问题:上述表示在主线程中 Looper.loop() 会一致循环读取 MessageQueue 中的消息,如果没有消息,在 queue.next() 方法时会阻塞,那为什么不会导致 ANR 呢?

​ 解答:

​ 第一点:这个答案需要去 MessageQueue 类中寻找。MessageQueue 底层采用了 epoll 机制进行阻塞,当接收到消息时会唤醒主线程,由 Looper 监控管道中的消息,每当唤醒的时候,向管道中发送唤醒的文件描述符,而在 Looper.loop() 循环获取消息的时候,会优先调用 epoll_wait 等待,然后获取等待过程中管道的文件描述符的数量,判断是否要唤醒主线程。

​ 第二点:ANR 实际上也是一个 Message,实际上 ANR 的触发也是 Handler 机制完成的,但是这里如果 Looper 循环阻塞了,其实也就表示着线程没什么事情做了,这时候需要交出 CPU 资源,进行阻塞睡眠,再有消息来的时候,由底层来唤醒主线程,进行消息处理。

​ Handler类:

​ dispatchMessage()分析:

	/**
     * 源码分析:dispatchMessage() 
     * 入参:Message 消息
     * 功能:处理消息逻辑
     */
    public void dispatchMessage(@NonNull Message msg) {
    	// post 方式发送消息,调用 post() 函数时会传入 Runnable 对象,调用 handleCallback() 函数处理
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
        // mCallback 对象是 Handler 类中自定义的 Callback 接口;内部定义方法 handleMessage() 描述了消息处理的逻辑,mCallback 的赋值时通过 Handler 初始化时传入的
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            // sendMessage 方式发送消息,调用 handleMessage() 函数处理
            handleMessage(msg);
        }
    }
    
    /**
     * Callback interface you can use when instantiating a Handler to avoid
     * having to implement your own subclass of Handler.回调接口,可以在实例化Handler时使用,以
     * 避免必须实现Handler的自己的子类。
     */
    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);
    }

​ Message 类:

​ recycleUnchecked() 函数:

	/**
     * Recycles a Message that may be in-use.
     * Used internally by the MessageQueue and Looper when disposing of queued Messages.
     * 回收消息,以便后续复用
     */
    @UnsupportedAppUsage
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        // 将消息保留在 Message 池中,Message 对象恢复初始状态
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = UID_NONE;
        workSourceUid = UID_NONE;
        when = 0;
        target = null;
        callback = null;
        data = null;

		// 将此 Message 消息添加到消息池中
        synchronized (sPoolSync) {
        	// 消息池最大容量判断
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
步骤四:消息接收处理

​ 内容:子线程实现 Handler 消息的处理逻辑

​ 实现方式:子线程实现消息的接受处理大概有三种方式,分别是 重写handleMessage()方法、实现Runnable接口run()方法、实现Callback接口handleMessage()方法;

​ 实现方式一:使用 sendMessage() 方式传递消息,重写 handleMessage() 方法;

	/**
	 * 具体使用方法
	 */
	 private Handler mhandler = new Handler() {
	 	// 通过重写 handleMessage() 方法完成消息的处理逻辑
	 	@Override
	 	public void handleMessage(Message msg) {
	 		...  // 需要执行的操作
	 	}
	 }
	 
	 /**
     * Handle system messages here.
     * Handler 处理消息分发逻辑
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    
    /**
     * Subclasses must implement this to receive messages..
     * 通过 Handler.dispatchMessage() 又会调回到此方法,此方法被应用重写
     */
    public void handleMessage(@NonNull Message msg) {
    }
    

​ 实现方式二:使用 post() 方式传递消息,实现 Runnable 接口的 run() 方法;

	/**
	 * 具体使用方法
	 */
	mhandler.post(new Runnable() {
		// 传入一个 Runnable 对象,复写 run() 方法完成消息逻辑的处理
		@Override
		public void run() {
			...  // 需要实现的操作
		}
	});
	
	/**
     * Handle system messages here.
     * Handler 处理消息分发逻辑
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    
    // 通过 Handle 的 dispatchMessage() 方法分发,会调用到 Runnable 对象的 run() 方法
    private static void handleCallback(Message message) {
        message.callback.run();
    }

​ 实现方式三:实现 Callback 接口 handleMessage() 方法

	/**
	 * 具体使用方法
	 */
	public class TestCallback implement Callback {
		@Ovierride
		boolean handleMessage(Message msg) {
			...  // 消息处理逻辑
		}
	}
	TestCallback testCallback = new TestCallback();
	
	// 新建 Handler 对象,传入创建的 testCallback 对象
	private Handler mhandler = new Handler(testCallback);

	/**
     * Handle system messages here.
     * Handler 处理消息分发逻辑
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    
    /**
     * Callback interface you can use when instantiating a Handler to avoid
     * having to implement your own subclass of Handler.
     * Handler 类内部的 Callback 接口的定义
     */
    public interface Callback {
        /**
         * @param msg A {@link android.os.Message Message} object
         * @return True if no further handling is desired
         * 消息会通过 Handler 的 dispatchMessage() 方法分发到这里,handleMessage() 实现
         */
        boolean handleMessage(@NonNull Message msg);
    }

4 Demo示例

4.1 子线程中处理 UI 更新报错

	/**
	 * 子线程中进行 UI 操作
	 */
	public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        button = view.findViewById(R.id.button_first);
        view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread("Thread_1") {
                    @Override
                    public void run() {
                        Log.d(TAG, "Thread is " + this.getName());
                        // 在子线程中设置 UI
                        button.setText("onclick1");
                        button.refreshDrawableState();
                    }
                }.start();
            }
        });
    }
    
操作结果:会出现异常,只有创建 UI 的线程才能进行 UI 操作。
	D/HandlerTest: Thread is Thread_1
E/AndroidRuntime: FATAL EXCEPTION: Thread_1
    Process: com.example.handlertest, PID: 9705
    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
        at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:8372)
        at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1444)
        at android.view.View.requestLayout(View.java:25010)
        at android.view.View.requestLayout(View.java:25010)
        at android.view.View.requestLayout(View.java:25010)
        at android.view.View.requestLayout(View.java:25010)
        at android.view.View.requestLayout(View.java:25010)
        at android.view.View.requestLayout(View.java:25010)
        at android.view.View.requestLayout(View.java:25010)
        at androidx.constraintlayout.widget.ConstraintLayout.requestLayout(ConstraintLayout.java:3172)
        at android.view.View.requestLayout(View.java:25010)
        at android.view.View.requestLayout(View.java:25010)
        at androidx.constraintlayout.widget.ConstraintLayout.requestLayout(ConstraintLayout.java:3172)
        at android.view.View.requestLayout(View.java:25010)
        at android.widget.TextView.checkForRelayout(TextView.java:9686)
        at android.widget.TextView.setText(TextView.java:6274)
        at android.widget.TextView.setText(TextView.java:6102)
        at android.widget.TextView.setText(TextView.java:6054)
        at com.example.handlertest.FirstFragment$1$1.run(FirstFragment.java:43)

4.2 sendMessage() 方式

	/**
	 * 方式一:
	 * 主线程中创建 Handler,子线程使用 Handler 发送消息进行 UI 操作
	 */
	public Handler handler1 = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            Log.d(TAG, "Thread is " + Thread.currentThread().getName());
            button.setText("onclick1");
            button.refreshDrawableState();
        }
    };
    
	public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread("Thread_2") {
                    @Override
                    public void run() {
                        Log.d(TAG, "Thread is " + this.getName());
                        Message message = Message.obtain();
                        message.what = 1;
                        handler1.sendMessage(message);
                    }
                }.start();
            }
        });
    }
    
操作结果:UI 设置成功
日志:
	D/HandlerTest: Thread is Thread_2
	D/HandlerTest: Thread is main
	
	/**
	 * 方式二:
	 * 子线程中创建 Handler,绑定主线程的 Looper,重写 Handler 的 handleMessage() 方法实现 UI 的操作
	 */
	public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread("Thread_2") {
                    @Override
                    public void run() {
                        Log.d(TAG, "Thread is " + this.getName());
                        Looper loop = Looper.getMainLooper();
                        Handler handler = new Handler(loop) {
                            @Override
                            public void handleMessage(@NonNull Message msg) {
                                Log.d(TAG, "Thread is " + Thread.currentThread().getName());
                                button.setText("onclick1");
                                button.refreshDrawableState();
                            }
                        };
                        Message message = Message.obtain();
                        message.what = 1;
                        handler.sendMessage(message);
                    }
                }.start();
            }
        });
    }
    
操作结果:UI 设置成功
日志:
	D/HandlerTest: Thread is Thread_2
	D/HandlerTest: Thread is main

操作截图:

在这里插入图片描述

4.3 post() 方式

	/**
	 * 方式一:
	 * 主线程中创建 Handler 对象,调用 handler.post() 传递信息
	 */
	public Handler handler2 = new Handler();
	
	public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread("Thread_3") {
                    @Override
                    public void run() {
                        Log.d(TAG, "Thread is " + this.getName());
                        handler2.post(new Runnable() {
                            @Override
                            public void run() {
                                Log.d(TAG, "Thread is " + Thread.currentThread().getName());
                                button.setText("onclick1");
                                button.refreshDrawableState();
                            }
                        });
                    }
                }.start();
            }
        });
    }
    
操作结果:UI 设置成功
日志:
	D/HandlerTest: Thread is Thread_3
	D/HandlerTest: Thread is main
	
	/**
	 * 方式二:
	 * 子线程中创建 Handler 对象,绑定主线程的 Looper 对象,调用 Handler.post() 传递消息
	 */
	public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread("Thread_3") {
                    @Override
                    public void run() {
                        Log.d(TAG, "Thread is " + this.getName());
                        Looper loop = Looper.getMainLooper();
                        Handler handler3 = new Handler(loop);
                        handler3.post(new Runnable() {
                            @Override
                            public void run() {
                                Log.d(TAG, "Thread is " + Thread.currentThread().getName());
                                button.setText("onclick1");
                                button.refreshDrawableState();
                            }
                        });
                    }
                }.start();
            }
        });
    }
操作结果:UI 设置成功
日志:
	D/HandlerTest: Thread is Thread_3
	D/HandlerTest: Thread is main

操作截图:

在这里插入图片描述

4.4 实现 Handler.Callback 方式

	/**
	 * 方式一:
	 * 主线程中创建 Handler,传入 Callback 接口的实现,子线程使用 handler.sendMessage() 方式传递消息
	 */
	// 定义带 Callback 参数的 Handler
    public Handler handler3 = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            Log.d(TAG, "Thread is " + Thread.currentThread().getName());
            button.setText("onclick1");
            button.refreshDrawableState();
            return true;
        }
    });
    
	public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread("Thread_4") {
                    @Override
                    public void run() {
                        Log.d(TAG, "Thread is " + this.getName());
                        Message message = Message.obtain();
                        handler3.sendMessage(message);
                    }
                }.start();
            }
        });
    }
    
操作结果:UI 设置成功
日志:
	D/HandlerTest: Thread is Thread_4
	D/HandlerTest: Thread is main
	
	/**
	 * 方式二:
	 * 子线程创建 Handler,绑定主线程 Looper,传入 Callback 实现,调用 handler.sendMessage() 传递消息
	 */
	public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread("Thread_4") {
                    @Override
                    public void run() {
                        Log.d(TAG, "Thread is " + this.getName());
                        Looper loop = Looper.getMainLooper();
                        Handler handler3 = new Handler(loop, new Handler.Callback() {
                            @Override
                            public boolean handleMessage(@NonNull Message msg) {
                                Log.d(TAG, "Thread is " + Thread.currentThread().getName());
                                button.setText("onclick1");
                                button.refreshDrawableState();
                                return true;
                            }
                        });
                        Message message = Message.obtain();
                        handler3.sendMessage(message);
                    }
                }.start();
            }
        });
    }
    
操作结果:UI 设置成功
日志:
	D/HandlerTest: Thread is Thread_4
	D/HandlerTest: Thread is main

操作截图:

在这里插入图片描述

5 总结

​ 以上就是关于 Android Handler机制的基础知识,涉及功能类 Handler、Looper、Message、MessageQueue等,以及关于 Handler 原理及使用 Demo 示例;对于 Native 层 Handler 原理,MessageQueue 如何获取 Message、阻塞线程、唤醒线程,大家有兴趣可以再研究。
​ 若文中有错误,请大家指出,必当有则改之。谢谢~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值