Handler如何通過sendMessage(Message msg)方法將新消息加入當前消息隊列(一)

首先需要先理清 Handler、MessageQueue、Looper 之間的關係。

我們使用Handler的時候(UI主線程)一般是通過以下兩種方法去創建一個Handler實例

1. 最常用的方法:方法1

Handler mHandler =new Handler(){
    @override
    public void handleMessage(Message msg){
        //To Do Something
    }

}


mHandler.sendMessage(msg);//發送消息

去看一下Handler的無參構造方法是怎麼創建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 " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

 重點看下面兩句

mLooper = Looper.myLooper();

mQueue = mLooper.mQueue;//將Looper的mQueue賦值給mHandler的 mQueue

在Handler的構造方法裏面直接通過Looper的myLooper()方法初始化自己的mLooper,我們進入該方法

 

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }


    //下面是Looper中的靜態變量 sThreadLocal 的定義
    // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

 通過myLooper()方法的註釋也可以知道,該方法返回的是當前線程的 Looper (注意:一個線程對應唯一的一個Looper)

但是怎麼來獲取當前的線程呢,進入ThreadLocal的get()方法就知道了

/**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread's value of this thread-local
     */
    public T get() {
        Thread t = Thread.currentThread();//通過這句代碼獲取到當前的線程
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

 現在我們應該明白了當我們通過方法1創建一個Handler實例的時候,在Handler的構造方法裏會爲我們獲取當前線程的

Looper,並且將該Looper的MessageQueue對象的引用mQueue賦值給Handler的mQueue。所以我們通過Handler的se-

ndMessage()方法發送消息的時候自然也就發送到了該Handler所在線程的Looper所管理的MessageQueue消息隊列中。

所以下面這句代碼就是發送到了mHandler所在線程(UI線程)的Looper所管理的MessageQueue隊列中

mHandler.sendMessage(msg);

 

2. 還有一種使用Handler的方法:方法2

這裏我們採用了 IntentService 中的例子

private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
}


@Override
public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
}

重點關注以下代碼:

mServiceLooper = thread.getLooper();

mServiceHandler = new ServiceHandler(mServiceLooper);

在IntentService中自定義了一個Handler  ServiceHandler ,在 new 一個Handler實例的時候,傳入了一個參數mServiceLooper

這個Looper是哪裏來的呢,代碼裏是通過HandlerThread的getLooper()方法獲取,如果你去看HandlerThread的源碼,就會發

現它其實也是通過Looper的myLooper()方法獲取到的 HandlerThread 所在線程所對應的那個Looper。

ServiceHandler的構造方法直接調用了父類的構造方法:super(looper),也就是 Handler 的構造方法

接下來我們再去看一下 Handler 的另一個構造函數

/**
     * 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);
    }

可以看到,該構造方法又調用了Handler的另一個構造方法:

    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

這裏依然是和方法1中的構造方法一樣的操作,將傳入的serviceLooper 最終賦值給了 Handler的mLooper(同時也是子類ServiceHandler的mLooper),再將該Looper對應的 mQueue 賦值給了 Handler 的mQueue(同時也是子類ServiceHandler的mQueue)

 

 

 

 

 

 

 

 

 

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