前一阵子面试,考官考到了Handler,虽然平常用的很多,但是没有从源码角度来看过,所以这次打算从源码角度来分析Handler。
先列出我用到的Handler的方法:
1.在类中创建一个Handler对象:
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
break;
default:
break;
}
}
};
2.发送消息:
Message msg = new Message();
msg.what = 1;
msg.obj = new Object();
mHandler.sendMessage(msg);
mHandler.sendEmptyMessage(1);
mHandler.sendMessage(mHandler.obtainMessage(1));
mHandler.sendMessageDelayed(msg, 5 * 1000);
mHandler.sendEmptyMessageDelayed(1, 5 * 1000);
mHandler.sendMessageDelayed(mHandler.obtainMessage(1),5 * 1000);
3.移除消息:
mHandler.removeCallbacksAndMessages(null);
讲讲我在面试中遇到的问题:
1.为什么子线程中不能创建Handler?
2.Handler使用不当为什么会发生内存泄漏?
3.Handler发送消息的这几种方法有什么异同?
4.多个Handler公用同一个MessageQueue,为什么不同的Handler发消息不会被其它Handler接收?
然后开始分析:
1.为什么子线程中不能创建Handler?从源码中来分析:
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
}
/**
* Use the {@link Looper} for the current thread with the specified callback interface
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(Callback callback, boolean async) {
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());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
第一段注释说得很清楚了,构造函数在一开始将Handler和当前线程的Looper绑定,如果这个线程没有Looper,那么这个Handler就不能接受到Messages,所以这里抛出异常。我们真正用到的构造方法其实是第二段,那么这段代码有什么含义呢:开始的if语句官方解释是设置这个标志位为true,如果这个Handler不是静态的匿名类、本地或成员类,那么这个类可能会发生泄漏。这个地方也是个考点:我示例创建的Handler不加static修饰的话是内部类,内部类默认持有外部类的引用;下面就是绑定Looper和MessageQueue,CallBack是用来回调的,至于mAsynchronous默认的是false,具体作用不知,这几个全都是用final修饰的,也就是说一个Handler只能绑定一个Looper和一个MessageQueue。
2.Handler使用不当为什么会发生内存泄漏?这个在上面也说明了,如果说使用了Handler.sendMessageDelayed,然后这个时候关闭了Activity,会导致Message持有MessageQueue的引用,MessageQueue又持有Handler的引用,Handler持有Activity的引用,然后就会导致内存泄漏。要解决这个,最好是使用弱引用,在Activity的onDestroy()方法里再加上Handler.removeMessagesAndCallbacks(null)即可
3.Handler发送消息的这几种方法有什么异同?其实从源码里看,这几种方法最终调用的发消息都一样
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return s
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
/**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* You will receive it in {@link #handleMessage}, in the thread attached
* to this handler.
*
* @param uptimeMillis The absolute time at which the message should be
* delivered, using the
* {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
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);
}
这里特殊的一点就是Messag.obtain(),这个是Message对象的方法,Message本身有一个回收池,obtain方法会复用回收池中没有被回收的Message对象。
4.多个Handler公用同一个MessageQueue,为什么不同的Handler发消息不会被其它Handler接收?这个也要看上面的源码,Message对象有一个what,这个what指定了具体哪个Handler,所以不会出现别的Handler接收的情况。