Handler机制
- Handler机制的简单介绍
- 1 Handler
Handler对象允许你发送消息和Runnable对象加入到MessageQueue队列,同时也可以处理从MessageQueue中取出来的消息和Runnable对象。每一个Handler实例都跟一个线程和MessageQueue绑定在一起。当新的Handler创建时,Handler对象将会跟创建时所在的线程的线程实例和MessageQueue绑定。所以,Handler将会把消息和Runnable实例发送到和它绑定的MessageQueue,并且执行或处理从该队列分发出来的消息和Runnable对象。
- 2Looper
每一个线程最多只有一个Looper对象。使用Looper时需要在所在的线程调用静态方法Looper.prepare() ,这个方法会创建当前线程所属的Looper对象和MessageQueue对象。然后调用Looper.loop()方法开启一个死循环不断的从MessageQueue中取出消息交给Handler处理。
- 3MessageQueue
MQ本质上是一个存储Message的单链表,通过Handler对象发送Message对象加入到单链表里面,同时通过loop循环取出分发出来。
- 4Message
Message类描述了消息的类型以及它所承载的数据。创建Message最好的方法是调用Message.obtain()或者Handler.obtainMessage(),这两个方法是从一个Message对象的回收池获取对象。避免了频繁地创建Message对象产生额外的开销。
Handler机制大概原理如下图所示,首先Handler把Message发送到MessageQueue,同时Looper不断的从MessageQueue取出待处理的Message,然后回调Handler的dispatchMessage方法,把消息委托给Handler处理。
2.Handler之消息发送
Handler类包含如下方法,用于发送、处理消息
void handleMessage(Message msg):处理消息的方法。该方法在创建Handler时重写。处理消息
final boolean hasMessage(int what):检查消息队列中是否包含what属性为指定值(参数中的what)的消息
final boolean hasMessage(int what,Object object):检查消息队列中是否包含what属性值为指定值且object属性值为指定对象的消息
多个重载的 Message obtainMessage():获取Message,经常用于创建一个Message对象。例如obtainMessage(int what,Object object)。
sendEmptyMessage(int what):发送空消息
final sendEmptyMessageDelayed(int what,long delayMills):指定delayMills毫秒后发送空消息。
final boolean sendMessage(Message msg):立即发送消息
final boolean sendMessageDelayed(Message msg,long delayMills):指定delayMill毫秒后发送消息
一般是通过Handler中以下方法来创建的
public final Message obtainMessage()
public final Message obtainMessage(int what)
public final Message obtainMessage(int what, Object obj)
public final Message obtainMessage(int what, int arg1, int arg2)
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
3.Handler的使用方式
3.1子线程中创建Handler
* class LooperThread extends Thread {
* public Handler mHandler;
* public void run() {
* Looper.prepare();
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
* Looper.loop();
* }
* }
3.2UI线程创建Handler
static class MyHandler extends Handler{
private WeakReference<HandlerActivity> activityRef;
private MyHandler(HandlerActivity activity){
this.activityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
if (activityRef!=null) {
HandlerActivity activity = activityRef.get();
if (activity != null) {
......
}
}
}
4.Handler时序图
5.代码解析
5.1 发送消息
//发送消息,最终都会调用到此方法
689 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
690 MessageQueue queue = mQueue;
691 if (queue == null) {
692 RuntimeException e = new RuntimeException(
693 this + " sendMessageAtTime() called with no mQueue");
694 Log.w("Looper", e.getMessage(), e);
695 return false;
696 }
697 return enqueueMessage(queue, msg, uptimeMillis);
698 }
//加入消息队列
740 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
741 msg.target = this;
742 if (mAsynchronous) {
743 msg.setAsynchronous(true);
744 }
745 return queue.enqueueMessage(msg, uptimeMillis);
746 }
boolean enqueueMessage(Message msg, long when) {
537 if (msg.target == null) {
538 throw new IllegalArgumentException("Message must have a target.");
539 }
540 if (msg.isInUse()) {
541 throw new IllegalStateException(msg + " This message is already in use.");
542 }
543
544 synchronized (this) {
545 if (mQuitting) {
546 IllegalStateException e = new IllegalStateException(
547 msg.target + " sending message to a Handler on a dead thread");
548 Log.w(TAG, e.getMessage(), e);
549 msg.recycle();
550 return false;
551 }
552
553 msg.markInUse();
554 msg.when = when;
555 Message p = mMessages;
556 boolean needWake;
557 if (p == null || when == 0 || when < p.when) {
558 // New head, wake up the event queue if blocked.
559 msg.next = p;
560 mMessages = msg;
561 needWake = mBlocked;
562 } else {
563 // Inserted within the middle of the queue. Usually we don't have to wake
564 // up the event queue unless there is a barrier at the head of the queue
565 // and the message is the earliest asynchronous message in the queue.
566 needWake = mBlocked && p.target == null && msg.isAsynchronous();
567 Message prev;
568 for (;;) {
569 prev = p;
570 p = p.next;
571 if (p == null || when < p.when) {
572 break;
573 }
574 if (needWake && p.isAsynchronous()) {
575 needWake = false;
576 }
577 }
578 msg.next = p; // invariant: p == prev.next
579 prev.next = msg;
580 }
581
582 // We can assume mPtr != 0 because mQuitting is false.
583 if (needWake) {
584 nativeWake(mPtr);
585 }
586 }
587 return true;
588 }
5.2 消息队列的分发处理
public static void loop() {
//可以看到,在调用Looper.prepare()之前是不能调用该方法的,不然又得抛出异常了
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
/*
这里我们看到,mLooper()方法里我们取出了,当前线程的looper对象,然后从looper对象开启了一个死循环
不断地从looper内的MessageQueue中取出Message,只要有Message对象,就会通过Message的target调用
dispatchMessage去分发消息,通过代码可以看出target就是我们创建的handler。我们在继续往下分析Message的分发
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
/*好了,到这里已经能看清晰了
可以看到,如果我们设置了callback(Runnable对象)的话,则会直接调用handleCallback方法
*/
private static void handleCallback(Message message) {
message.callback.run();
}
//即,如果我们在初始化Handler的时候设置了callback(Runnable)对象,则直接调用run方法。比如我们经常写的runOnUiThread方法:
runOnUiThread(new Runnable() {
@Override
public void run() {
}
});
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
/*
而如果msg.callback为空的话,会直接调用我们的mCallback.handleMessage(msg),即handler的handlerMessage方法。由于Handler对象是在主线程中创建的,
所以handler的handlerMessage方法的执行也会在主线程中。
*/
5.Handler内存泄漏
1. Handler在使用过程中,需要注意的问题之一便是内存泄漏问题。
为什么会出现内存泄漏问题呢?
首先Handler使用是用来进行线程间通信的,所以新开启的线程是会持有Handler引用的,
如果在Activity等中创建Handler,并且是非静态内部类的形式,就有可能造成内存泄漏。
首先,非静态内部类是会隐式持有外部类的引用,所以当其他线程持有了该Handler,线程没有被销毁,则意味着Activity会一直被Handler持有引用而无法导致回收。
同时,MessageQueue中如果存在未处理完的Message,Message的target也是对Activity等的持有引用,也会造成内存泄漏。
解决的办法:
(1). 使用静态内部类+弱引用的方式:
静态内部类不会持有外部类的的引用,当需要引用外部类相关操作时,可以通过弱引用还获取到外部类相关操作,弱引用是不会造成对象该回收回收不掉的问题,不清楚的可以查阅JAVA的几种引用方式的详细说明。
private Handler sHandler = new TestHandler(this);
static class TestHandler extends Handler {
private WeakReference<Activity> mActivity;
TestHandler(Activity activity) {
mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Activity activity = mActivity.get();
if (activity != null) {
//TODO:
}
}
}
(2). 在外部类对象被销毁时,将MessageQueue中的消息清空。例如,在Activity的onDestroy时将消息清空。
@Override
protected void onDestroy() {
handler.removeCallbacksAndMessages(null);
super.onDestroy();
}