Handler消息传递机制
出于性能优化考虑,Android的UI操作并不是线程安全的,这意味着如果有多个线程并发操作UI组件,则可能导致线程安全问题。为了解决这个问题,Android制定了一条简单的规定:只允许UI线程(主线程)修改Activity里的UI组件。
稍微想一想,如果新启动的线程需要动态修改界面组件怎么办呢。这时候就需要借助于Handler的消息机制来实现了。
Handler类简介
为了解决新线程动态修改界面组件的问题,所以引入了Handler类。所以Handler类主要作用有两个:
- 在新启动的线程中
发送消息
- 在主线程中
获取、处理消息
我们只需重写Handler类中处理消息的方法。当新启动的线程发送消息的时候,该消息就会放到与它相关的MessageQueue(不难想到,一个新线程只需要有一个MessageQueue)。Handler会不断从MessageQueue中获取并处理消息,这样就会让我们重写的方法被回调了。
Handler类包含如下的方法用于发送、处理消息:
void handleMessage(Message msg)
处理消息的方法。该方法通常用来重写
final boolean hasMessages(int what)
检查消息队列中是否包含what属性为指定值的消息
final boolean hasMessages(int what , Object object)
检查消息队列中是否包含what属性为指定值且object属性为指定对象的消息
Message obtainMessage()
获取消息
sendEmptyMessage(int what)
发送空消息
final boolean sendEmptyMessageDelayed(int what ,long delayMillis)
多少毫秒之后发送空消息
final boolean sendMessage(Message msg)
立即发送消息
finla boolean sendMessageDelayed(Message msg , long delayMillis)
多少毫秒之后发送消息
Handler获取,处理消息
上面提到Handler是得到消息,然后处理消息的一个类,而MessageQueue是一个消息队列。那么是不是还差一个把消息放入MessageQueue中和把消息拿出来交给Handler处理的一个类呢。所以引入了一个Looper类:
Looper的主要功能:
- Looper负责管理MessageQueue,会不断从MessageQueue中取出消息,并将消息分给对应的Handler处理。
获得一个Looper对象
上面提到每个线程最多只需要一个MessageQueue,所以一个线程中最多只能有一个Looper对象。看一下Looper构造器源码:
private Looper(){
mQueue = new MessageQueue();
mRun = true;
mThread = mThread.currentThread();
}
可以看到构造器是使用private修饰的,所以程序员不能通过new来创建一个Looper对象。所以Looper类提供了一个prepare()
方法来创建一个Looper对象。prepare()
方法的源码:
private static final void prepare(){
if(sThreadLocal.get() != null)
throw new RuntimeException("Only one Looper may be created per thread");
sThreadLocal.set(new Looper());
}
从上面的源码可以看出,prepare()
对象保证了每个线程最多只有一个Looper对象。
通过Looper对象分发消息给Handler
当获得一个Looper对象之后,我们现在应该做的就是通过Looper对象,向MessageQueue中取出消息然后分发给Handler。Looper提供了静态的loop()
方法。loop()
方法使用一个死循环不断取出MessageQueue中的消息,并将取出的消息分给该消息对应的Handle进行处理。
总结
Looper、MessageQueue、Handler各自的作用:
- Looper : 每个线程只有一个Looper,它负责管理MessageQueue,会不断从MessageQueue中取出消息,并将消息分给对应的Handler处理
- MessageQueue : 由Looper负责管理。
- Handler : 他能把消息发送给Looper管理的MessageQueue,并负责处理Looper分给它的消息。
新线程中使用Handler的步骤
- 调用Looper的
perpare()
方法为当前创建Looper对象,创建Looper对象时,他的构造器会创建与之配套的MessageQueue。 - 有了Looper之后,创建Handler子类的实例,重写
handleMessage()
方法,该方法负责处理来自其他线程的消息。 - 调用Looper的
loop()
方法启动Looper。