Handler源码分析

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()方法中已经调用了,我们再次调用反而会报错。

ActivityThread

Looper创建时做了什么?

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

prepare

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

Looper构造方法

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

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

MessageQueue是怎么存放Message的?

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

sendPost

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

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

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

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

enqueueMessage

如果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()做了什么?

loop

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

在这里插入图片描述

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

post

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

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

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

在这里插入图片描述

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

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

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页