[Android]源码阅读之Handler

    前一阵子面试,考官考到了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接收的情况。

猜你喜欢

转载自blog.csdn.net/woaily1346/article/details/80914998