Android源碼-Handler分析

Handler簡介

Handler是Android消息機制的上層接口,多數開發者會使用Handler去更新UI或做延時處理。如下代碼所示:

new Thread(new Runnable() {
       @Override
       public void run() {
           // do something
           handler.sendMessage(message)
       }
   }).start();
new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            //do something
        }
    }, 2000);

Handler分析

Handler類位於android.os包下,繼承Object類

其中可見的構造方法有三個

/**
 * Constructor associates this handler with the {@link Looper} for the
 * current thread and takes a callback interface in which you can handle
 * messages.
 *
 * If this thread does not have a looper, this handler won't be able to receive messages
 * so an exception is thrown.
 *
 * @param callback The callback interface in which to handle messages, or null.
 */
public Handler(Callback callback) {
    this(callback, false);
}

/**
 * Use the provided {@link Looper} instead of the default one.
 *
 * @param looper The looper, must not be null.
 */
public Handler(Looper looper) {
    this(looper, null, false);
}

/**
 * Use the provided {@link Looper} instead of the default one and take a callback
 * interface in which to handle messages.
 *
 * @param looper The looper, must not be null.
 * @param callback The callback interface in which to handle messages, or null.
 */
public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}

其中Callback是Handler內部定義的接口,只有一個回調方法handleMessage

/**
   * Callback interface you can use when instantiating a Handler to avoid
   * having to implement your own subclass of Handler.
   *
   * @param msg A {@link android.os.Message Message} object
   * @return True if no further handling is desired
   */
  public interface Callback {
      public boolean handleMessage(Message msg);
  }

這裏先來分析無參構造方法

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) {
        ....//省略
        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;
    }

這裏需要注意下@hide修飾爲隱藏方法,不能直接調用,可以通過反射調用。

這裏需要一個Looper對象,如果mLooper屬性爲空,會拋出異常。如果在主線程(UI線程)中創建Handler對象,默認在主線程中已經調用了Looper.prepareMainLooper()方法,詳細代碼在ActivityThread類中main方法中。Looper.myLooper()方法會獲取當前線程的Looper對象,噹噹前線程中沒有Looper對象時,創建Handler會拋出異常,這就是常見於在子線程中創建Handler之前沒有調用Looper.prepare()方法出現的崩潰,有問題代碼如下:

new Thread(new Runnable() {
          @Override
          public void run() {
              Handler mHandler = new Handler();
          }
      }).start();

正確在子線程中創建Handler如下:

new Thread(new Runnable() {
         @Override
         public void run() {
             Looper.prepare();
             Handler mHandler = new Handler();
             Looper.loop();
         }
     }).start();

這裏需要注意的是在創建完Handler後,這裏又調用了Looper.loop()方法,這個方法是爲了在這個線程中運行消息隊列。

Looper分析

我們可以查看Looper源碼中prepare方法可知,如下:

    public static void prepare() {
        prepare(true);
    }

    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.prepare方法時,調用重載方法,爲當前線程關聯一個新的Looper對象,這裏使用的是ThreadLocal,有興趣的可以查看下源碼。我們接着看Looper.loop方法:

   /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        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 slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            final long end;
            try {
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (slowDispatchThresholdMs > 0) {
                final long time = end - start;
                if (time > slowDispatchThresholdMs) {
                    Slog.w(TAG, "Dispatch took " + time + "ms on "
                            + Thread.currentThread().getName() + ", h=" +
                            msg.target + " cb=" + msg.callback + " msg=" + msg.what);
                }
            }

            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();
        }
    }

這裏主要邏輯是獲取當前Looper對象的MessageQueue隊列,for死循環不斷的從隊列中取出消息,調用msg.target.dispatchMessage(msg);這個的target就是Handler對象,這個target是在Handler中sendMessage系列方法中設置引用的,代碼如下:

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

msg.target = this,到這裏對Handler的調用關係就分析完畢了,有興趣的可以查看源碼,謝謝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章