欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Handler源码分析

程序员文章站 2021-12-03 09:00:04
HandlerHandler机制是子线程和主线程、子线程和子线程通信的一种方法,其中包括Looper、MessageQueue、Message、Handler。Handler将Message发送到MessageQueue中,Looper不停的轮询从MessageQueue中取出Message交给Handler处理。先看一下Handler的基本用法Handler uiHandler = new Handler() { @Override public void handleMessage...

Handler

Handler机制是子线程和主线程、子线程和子线程通信的一种方法,其中包括Looper、MessageQueue、Message、Handler。Handler将Message发送到MessageQueue中,Looper不停的轮询从MessageQueue中取出Message交给Handler处理。

先看一下Handler的基本用法

Handler uiHandler = new Handler() {
    @Override
    public void handleMessage(@NonNull Message msg) {
        super.handleMessage(msg);
        //处理发送过来的消息
    }
};
        
Message message = new Message();
message.what = 1;
uiHandler.sendMessage(message);

Handler的创建

使用Android Studio点开Handler的构造方法,如下所示:

Handler源码分析

从源码中可以看到,在Handler的构造方法中,会调用Looper.myLooper()方法获取Looper,如果Looper为空,则会抛出异常,这也是我们在使用Handler之前一定要创建Looper的原因,也就是必须调用Looper.prepare()方法,而上述示例代码中却没有调用该方法,也能正常执行,是因为当进程启动时,ActivityThread的main()方法中已经调用了,我们再次调用反而会报错。

Handler源码分析

Looper创建时做了什么?

我们打开Looper.java,找到prepare()方法,可以看到,首先会通过ThreadLocal获取该线程绑定的Looper,如果已经存在,则抛出异常:Only one Looper may be created per thread(每个线程只能创建一个Looper),获取不到Looper,则调用Looper的构造方法创建一个Looper并放到ThreadLocal中,使这个创建的Looper和当前线程绑定。

Handler源码分析

接下来看看Looper的构造方法中做了什么?

Handler源码分析

Looper的构造方法是一个私有方法,这也就意味着我们不能通过new的方式直接创建Looper对象。在构造方法中初始化了MessageQueue。这个MessageQueue会在创建Handler的时候赋值给Handler的mQueue:

//Handler.java 构造方法
mQueue = mLooper.mQueue;

MessageQueue是怎么存放Message的?

MessageQueue是用来存放Message的,它的名字虽然有Queue(队列),其实它里面维护的是一个链表,结点就是Message。我们通过sendMessage()或post()方法是怎么存到MessageQueue中的,一起来看下:

Handler源码分析

从上面的代码可以看到,不管是使用sendMessage()还是post(),最终都会走到enqueueMessage()中,在enqueueMessage中将Handler自身传给了Message的target,这里的target其实就是Handler:

//Message.java 成员变量
Handler target;

这个target是Looper决定交给哪个Handler处理的关键!

接下来继续看enqueueMessage()方法,它是怎么添加Message的:

Handler源码分析

如果Message的target为null,则会抛出异常Message must have a target,这里也告诉我们必须要有target。如果这个Message已经使用了,则会抛出The message is already in use,因此,同一个Message不能使用两次!接下来会取出表头的Message是否为空或者延迟时间when来判断是放到表头的位置还是放到链表中间的位置。到此,sendMessage的流程就结束了。

接下来看看Looper是怎么从MessageQueue中取出消息交给Handler处理的?

Looper的loop()做了什么?

Handler源码分析

loop()方法中首先还是检查了该线程绑定的Looper是否为空,可见prepare()是真的真的不能少啊。检查了Looper后,就获取该Looper中的MessageQueue,然后开启一个死循环一直轮询从MessageQueue中取Message,如果Message存在,则调用其target的dispatchMessage()方法,上文中已经提到这个target就是Handler,这也是为什么Looper知道交给哪个Handler处理的原因。继续进入到dispatchMessage()方法中:

Handler源码分析

在dispatchMessage()方法中分成了两种情况,一种是msg.callback不为null的情况:

Handler源码分析

这种情况是通过post()方式,会直接执行Runnable的run()方法,和线程Thread没有关系。

另外一种是msg.callback为null的情况:这种一般为sendMessage()方式,会调用了handleMessage()方法,这也正是我们创建Handler时需要重写的方法。这也是Handler的sendMessage()和post()的区别。

Looper的loop()执行了死循环为什么不会导致主线程阻塞?

Handler源码分析

原因写在注释中了,想要了解nativePollOnce方法可以看看nativePollOnce

Handler的分析到此就结束了,总结?不存在的。

本文地址:https://blog.csdn.net/You_v_Me/article/details/114242601

相关标签: Android