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的构造方法中,会调用Looper.myLooper()方法获取Looper,如果Looper为空,则会抛出异常,这也是我们在使用Handler之前一定要创建Looper的原因,也就是必须调用Looper.prepare()方法,而上述示例代码中却没有调用该方法,也能正常执行,是因为当进程启动时,ActivityThread的main()方法中已经调用了,我们再次调用反而会报错。
Looper创建时做了什么?
我们打开Looper.java,找到prepare()方法,可以看到,首先会通过ThreadLocal获取该线程绑定的Looper,如果已经存在,则抛出异常:Only one Looper may be created per thread(每个线程只能创建一个Looper),获取不到Looper,则调用Looper的构造方法创建一个Looper并放到ThreadLocal中,使这个创建的Looper和当前线程绑定。
接下来看看Looper的构造方法中做了什么?
Looper的构造方法是一个私有方法,这也就意味着我们不能通过new的方式直接创建Looper对象。在构造方法中初始化了MessageQueue。这个MessageQueue会在创建Handler的时候赋值给Handler的mQueue:
//Handler.java 构造方法
mQueue = mLooper.mQueue;
MessageQueue是怎么存放Message的?
MessageQueue是用来存放Message的,它的名字虽然有Queue(队列),其实它里面维护的是一个链表,结点就是Message。我们通过sendMessage()或post()方法是怎么存到MessageQueue中的,一起来看下:
从上面的代码可以看到,不管是使用sendMessage()还是post(),最终都会走到enqueueMessage()中,在enqueueMessage中将Handler自身传给了Message的target,这里的target其实就是Handler:
//Message.java 成员变量
Handler target;
这个target是Looper决定交给哪个Handler处理的关键!
接下来继续看enqueueMessage()方法,它是怎么添加Message的:
如果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()方法中首先还是检查了该线程绑定的Looper是否为空,可见prepare()是真的真的不能少啊。检查了Looper后,就获取该Looper中的MessageQueue,然后开启一个死循环一直轮询从MessageQueue中取Message,如果Message存在,则调用其target的dispatchMessage()方法,上文中已经提到这个target就是Handler,这也是为什么Looper知道交给哪个Handler处理的原因。继续进入到dispatchMessage()方法中:
在dispatchMessage()方法中分成了两种情况,一种是msg.callback不为null的情况:
这种情况是通过post()方式,会直接执行Runnable的run()方法,和线程Thread没有关系。
另外一种是msg.callback为null的情况:这种一般为sendMessage()方式,会调用了handleMessage()方法,这也正是我们创建Handler时需要重写的方法。这也是Handler的sendMessage()和post()的区别。
Looper的loop()执行了死循环为什么不会导致主线程阻塞?
原因写在注释中了,想要了解nativePollOnce方法可以看看nativePollOnce
Handler的分析到此就结束了,总结?不存在的。
本文地址:https://blog.csdn.net/You_v_Me/article/details/114242601