一、Handler的作用
- 官方解释
Handler允许你发送和处理Message和与线程的MessageQueue关联的Runnable对象。每个Handler实例与一个线程和它的MessageQueue相关联。当你创建一个新的Handler,它就被绑定到这个线程或者这个线程的消息队列上–从那时起,它会传递messages和runnables到那个消息队列,然后当他们离开消息队列时执行他们。 - 个人理解
Handler是一个线程消息处理者,是UI线程和子线程(工作线程)之间的信使。他可以将工作线程中需更新UI的操作信息 传递到 UI主线程,从而实现在工作线程对UI的异步更新。
ps:其实Handler可以完成任何线程之间的消息传递,不只是主线程与子线程。
二、为啥用Handler
- 在多个线程同时更新UI的时候,保证线程的安全。
- 假如最初的设计没有Handler,而是所有地方都能更新UI,那么我有很多个线程同时在给一个文本控件setText,那肯定会引起界面混乱。如果这时候要解决怎么办?加锁?这样又会影响性能。
- 所以Android在设计的时候就加入了这个Handler的机制让我们去遵守而不用去考虑多线程的问题。
三、Handler的机制(原理)
一句话解释:
Handler通过执行其绑定线程的消息队列(MessageQueue)中不断被Looper循环取出的消息(Message)来完成线程间的通信。
主要有几个类需要理解:
1. Looper
- 官方解释
用于运行线程的消息循环的类。默认情况下线程没有与之关联的消息循环;在要运行循环的线程中调用prepare来创建一个Looper,然后调用loop使其循环处理消息,直到循环结束为止。 - 主要方法
首先看prepare方法:
/**
* 将当前线程初始化为Looper,这使您有机会创建Handlers,然后在实际开始循环之前先引用这个Looper。
* 确保在调用此方法后调用{@link #loop()},并通过调用{@link #quit()}结束该方法。
*/
public static void prepare() {
prepare(true);
}
/**
* 这里sThreadLocal是一个ThreadLocal的对象,可以在一个线程中存储变量。
* 这里可以看到储存的是一个Looper的实例,前三行判断如果sThreadLocal.get()为空,则抛出异常。
* 说明此方法不能被调用两次,也保证了一个线程中只有一个Loopper实例。
*/
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
然后看最后一行中实例化Looper的构造方法:
/**
* 实例化了一个消息队列(MessageQueue)对象和将当前线程赋值给一个全局变量mThread
*/
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
再看loop方法,只保留了重点代码:
/**
*在此线程中运行消息队列。 确保调用{@link #quit()}以结束循环
*/
public static void loop() {
// 调用sThreadLocal.get()方法获取之前储存的Looper实例
final Looper me = myLooper();
if (me == null) {
// 如果me为null则抛出异常,也就是说loop方法必须在prepare方法之后运行。
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 拿到该looper实例中的mQueue(消息队列)
final MessageQueue queue = me.mQueue;
// 开启无限循环
for (;;) {
// 取出一条消息,如果没有消息则阻塞
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
// 使用调用 msg.target.dispatchMessage(msg);把消息交给msg的target的dispatchMessage方法去处理。
//Msg的target就是handler对象
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//释放消息占据的资源
msg.recycleUnchecked();
}
接下来就走到了Handler的dispatchMessage方法了
2. Handler
- 先看构造方法,通过as的structure可以看到Handler有7个构造方法,:
这里我们平时使用最多的可能是两种,一个是无参的,一种是传入Looper对象的。但是不管哪种,最终都是走到了最后两个构造方法。来看倒数第二个方法:
public Handler(Callback callback, boolean async) {
// 这个FIND_POTENTIAL_LEAKS变量恒为false,看不懂
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
// 获取当前线程保存的Looper实例
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
// 获取当前线程保存的Looper实例中实例化时保存的MessageQueue(消息队列)
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
这个构造方法保证了handler的实例与我们Looper实例中MessageQueue关联上了。
最后一种更粗暴,直接把需要的变量都传进去了,全部赋值:
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
总之,不管以哪种方式实例化Handler,目的都是要将其与MessageQueue关联上。
- sendMessage,这个方法平时是用的最多的了
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
经过一连串的调用以后到了sendMessageAtTime方法,在这里获取到MessageQueue然后调用enqueueMessage方法将其传入。
在enqueueMessage方法中把Message.target 赋值为this(在上面Looper的loop方法里面就是利用了这个target.dispatchMessage(msg)来传递的消息),也就是将当前的Handler实例传入Message赋值给其target属性;最后调用queue.enqueueMessage方法把消息保存到消息队列中。
说到这里,倒是可以看看这个dispatchMessage方法了:
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
// 这里mCallback是否为空取决于调用哪个构造函数,但是目的都是为了让我们执行handleMessage方法,不管是Handler的还是Callback
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
最后来看handleMessage方法:
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public boolean handleMessage(Message msg);
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
可以看到不管是不管是Handler的还是Callback的handleMessage方法,都是需要我们自己去重写然后根据回调的msg进行消息处理。
- 总结Handler机制
- 1.Looper.prepare()在当前线程使用ThreadLocal保存一个通过构造方法生成的Looper实例,并保存一个MessageQueue实例。该方法在同一个线程只能调用一次,所以一个线程只会存在一个Looper和一个MessageQueue。
- 2.Looper.loop()开启无限循环,每次从MessageQueue实例取出一条消息,再通过该消息的 msg.target.dispatchMessage(msg) 方法将消息进行传递。
- 3.通过Handler的构造方法获取当前线程中的Looper实例及获取当该Looper对象中实例化时保存的MessageQueue(消息队列)。
- 4.通过handler.sendMessage(Message msg)给msg的target赋值为handler自身,然后加入MessageQueue中。
- 5.msg.target.dispatchMessage(msg) 调用到最后实际是回调了Handler的handleMessage方法,由我们自行重写处理消息。
四、Handler的用法
常用有两种
- 直接new Handler(),通过handler.sendMessage()发消息,然后重写handleMessage()方法等待回调处理消息。
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
logic();
}
};
- 传入Looper,此处为封装主线程,传入Looper.getMainLooper(),保证了不管在什么线程中实例化,都是在主线程回调。然后调用handler.post(Runnable r)方法或postDelayed。
ps:在主线程中创建Handler时,主线程会自动创建Looper的,而自己在子线程中自定义handler时,需要手动创建Looper,并调用Looper的prepare方法,或者传Looper.getMainLooper()
public class MainThread {
private Handler mHandler;
public MainThread() {
mHandler = new Handler(Looper.getMainLooper());
}
public void post(Runnable runnable) {
postDelayed(runnable, 0);
}
public void postDelayed(Runnable runnable, long delayMillis) {
mHandler.postDelayed(runnable, delayMillis);
}
public void removeCallbacks(Runnable runnable) {
mHandler.removeCallbacks(runnable);
}
}
- 子线程创建Handler,如果不给Handler指定一个Looper就会出现异常
class MyThread extends Thread{
public Handler handler;
@Override
public void run() {
Looper.prepare(); //创建一个Looper对象
handler = new Handler(){
//此方法运行在子线程中
@Override
public void handleMessage(Message msg) {
System.out.println("当前的线程-->" + Thread.currentThread());
}
};
Looper.loop(); //开始轮询
}
}
MyThread thread = new MyThread();
thread.start(); //启动线程
//发送消息就会执行该handler的handleMessage方法(在子线程中)
thread.handler.sendEmptyMessage(1);
五、用到Handler的地方
- HandlerThread
本身是一个子线程,已经在run()方法中指定了Looper,可以直接进行异步操作。
- Activity的runOnUiThread(Runnable action)方法,实际上是用了handler.post(action)方式。内部先判断当前线程是不是主线程,如果不是就通过handler发送一个消息。
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
- Activity的启动流程中(在ActivityThread的main方法里面调用Looper.prepareMainLooper())
给sMainLooper赋值当前线程(即主线程)的Looper。