文章目录
前言
Handler是Android消息机制的上层接口,所以Android的消息机制主要指的就是Handler的运行机制,其主要应用于UI线程(主线程)和子线程之间的交互。众所周知,一般情况下,出于安全的考虑,所有与UI控件的操作都要放在主线程,而一些耗时的I/O操作应当放在子线程中。当在子线程中完成耗时操作并要对UI控件进行操作时,此时就要用Handler来控制了。
在这我们先来简述一下Handler的运行过程:
在Handler创建完毕后,这个时候其内部的Looper以及MessageQueue就可以和Handler一起协同工作了,然后通过Handler的post方法将个Runnable 投递到Handler内部的Looper中去处理,也可以通过Handler的send方法发送个消息,这个消息同样会在Looper中去处理。其实post方法最终也是通过send方法来完成的,接下来主要来看一下send方法的工作过程。当Handler的send方法被调用时,它会调用MessageQueue的enqueueMessage方法将这个消息放入消息队列中,然后Looper发现有新消息到来时,就会处理这个消息,最终消息中的Runnable或者Handler 的handleMessage 方法就会被调用。注意Looper是运行在创建Handler所在的线程中的,这样-来Handler中的业务逻辑就被切换到创建Handler所在的线程中去执行了。
本文主要以解析Handler源码为主,包含Handler运行机制、MessageQueue的工作原理、Looper的工作原理、ThreadLocal的工作原理
首先我们先简介一下关于Handler机制中会出现的一些概念:
Message:消息(Message)代表一个行为(what)或者一串动作(Runnable),每一个消息在加入消息队列(MessageQueue)时,都有一个明确的目标(Handler)。
Handler:消息的真正处理者,具备获取消息、发送消息、处理消息、移除消息等功能。
MessageQueue:消息队列,以队列(实质还是链表)的形式对外提供插入和删除的操作,其内部结构是以链表的形式存储消息的。
Looper:Looper是循环的意思,它负责从消息队列(MessageQueue)中循环的取出消息然后把消息交给目标(Handler)处理。
线程:线程,CPU调度资源的基本单位。Android中的消息机制也是基于线程来完成的。
ThreadLocal:ThreadLocal的作用是提供线程内的局部变量(TLS),这种变量在线程的生命周期内起作用,每一个线程有他自己所属的值(线程隔离)。
一、Handler发送消息机制
1.Handler的简单使用
我们先通过一个简单的代码展示一下Handler的用法:
public class MainActivity extends AppCompatActivity {
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case 1:{
Toast.makeText(MainActivity.this,"UI操作",Toast.LENGTH_SHORT).show();
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
/*
*网络请求操作或者耗时的I/O操作
*
*/
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
}).start();
}
}
通过这段代码可以看到,我们在子线程中通过handler发送一个消息 Message,然后再由此handler处理接收到的消息,这样我们就可以实现在子线程里完成耗时的I/O操作,完成后我们再切换到主线程完成对UI的操作。
那Handler内部是怎么发送消息,又是怎么处理消息的呢?
2.Handler如何发送消息?
由于Handler中所有post方法最终都会调用send方法,所以这里不予讲述
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what) {
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
通过Handler的源码我们可以看出,sendMessage()和sendEmptyMessage(),最终都会调用sendMessageDelayed()方法。不同之处在于,sendMessage()方法接受的是一个Message对象,然后将这个对象传给sendMessageDelayed(),而sendEmptyMessage()需要的是一个名为what的int值,然后通过Message.obtain()方法得到一个Mesage对象,再将what值赋给他,最后传给sendMessageDelayed()。
那么我们需要思考一下what值是干什么的?还有就是new出来的Message对象和调用Message.obtain()方法得到的对象这两个有什么区别呢?
首先我们看一下Message类下what的简介:
/**
* User-defined message code so that the recipient can identify
* what this message is about. Each {@link Handler} has its own name-space
* for message codes, so you do not need to worry about yours conflicting
* with other handlers.
*/
public int what;
翻译:用户定义的消息代码,以便收件者可以确定这条消息是关于什么。每个{@link Handler}都有自己的消息代码名称空间,因此您不必担心与其他Handlers发生冲突。
可见,what值就是消息的一个代号,由于不同的Handler都有自己的命名空间,所以我们不必担心会引起冲突。
那我们再看一下obtain():
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static 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;
}
}
return new Message();
}
翻译:从全局池返回一个新的Message实例。允许我们在许多情况下避免分配新对象。
看代码,我们大概能看出Android为我们定义好了一个全局的Message池,这个池是一个链表型数据结构,通过obtain()方法可以从链表头取出一个Message对象并返回。
上面的两个疑问解决了,我们继续往下看,由于sendMessage()和sendEmptyMessage()最终都会调用sendMessageDelayed()方法,那我们一起看一下sendMessageDela