handler源碼分析

首先看一下handler發送和接收數據的代碼

	private var mHandler = Handler {
		print(it.toString())
        false
    }

    private fun sendMessage() {
        Thread {
            mHandler.sendMessage(Message.obtain().apply {
                what = 0
                arg1 = 1
                arg2 = 2
                obj = "obj"
            })
        }.start()
    }

handler.sendMessage 調用的是 MessageQueue.enqueueMessage
handler的Callback 是looper的dispatchMessage,其中message獲取是通過MessageQueue.next

Handler

初始化

	public Handler(@Nullable Callback callback) {
        this(callback, false);
    }
    public interface Callback {
        boolean handleMessage(@NonNull Message msg);
    }

消息分發機制,再Looper中調用,爲了接收數據

 /**
     * Handle system messages here.
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

消息發送

 public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }

實際上調用下面的方法

public boolean sendMessageAtTime(@NonNull 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);
}

實際上調用MessageQueue的enqueueMessage方法,傳遞了消息和時間

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

Message

public final class Message implements Parcelable 

一個序列化的數據。

public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

要注意的是,新建Message的時候,使用obtain()方法,因爲這樣會使用Message的一個緩存。(性能優化)

void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = UID_NONE;
        workSourceUid = UID_NONE;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

消息回收的方法。

MessageQueue

數據入隊列的方法,並且再這裏控制線程的喚醒,此隊列爲優先級隊列

boolean enqueueMessage(Message msg, long when) {
		//加鎖操作
		synchronized (this) {
			//判斷是否要喚醒線程
			//消息隊列中的鏈表的頭部元素爲null;立即執行;msg的執行時間早與鏈表中的頭部元素的時間。這三個判斷都要把msg設置成消息隊列中鏈表的頭部是元素
			if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
            	//喚醒狀態判斷
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                //一個循環判斷新的消息放到哪個位置
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
	}
}

獲取數據的方法,Looper中調用

Message next() {
		//控制退出的方法
		final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }
        //死循環
        for (;;) {
        	//線程掛起,根據下一個要獲取message的時間
         	nativePollOnce(ptr, nextPollTimeoutMillis);
         	//同步鎖
         	synchronized (this) {
         			if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                 // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    //注意這個循環繼續,pendingIdleHandlerCount 很少大於0,所以很少會走到下面
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
         	}
        }
}

Looper

Looper的初始化

/** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
    	//這裏確定一個ThreadLocal只能和一個looper綁定
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

這裏說明開啓一個handler需要一個looper,一個是子線程開啓,一個是爲了主線程開啓。

 private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

私有的構造函數,必須通過方法初始化。新建了一個MessageQueue,獲取當前線程。(不是單例模式,可以看成是線程裏的單例,線程隔離)

 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

通過ThreadLocal來實現線程隔離。注意這裏使用的是static final

   public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

獲取當前looper的代碼,通過ThreadLocal獲取,下面會講解Looper的唯一性。

Looper的 loop()方法,主要是拿到Message和發送Message。

 public static void loop() {
 	//獲取當前looper
 	final Looper me = myLooper();
 	//獲取MessageQueue
 	final MessageQueue queue = me.mQueue;
 	//一個死循環
 	 for (;;) {
 	 		//獲取消息,詳見messageQueue
 	  		Message msg = queue.next(); // might block
 	  		//把數據發送出去
 	  		msg.target.dispatchMessage(msg);
 	  		//消息回收,內存優化
 	  		msg.recycleUnchecked();
 	 }
 }

ThreadLocal

首先看一下Thread源碼,裏面有ThreadLocal.ThreadLocalMap,ThreadLocal中有ThreadLocalMap,每一個線程都有自己的ThreadLocal。

 /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;

下面看一下ThreadLocal.ThreadLocalMap的代碼

 		static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        	}
	 		/**
	         * The table, resized as necessary.
	         * table.length MUST always be a power of two.
	         */
	        private Entry[] table;
	  }

實際保存的是一個數組,Entry是也Map,ThreadLocal<?>對應的是key,Object 對應所存儲的值,
table的長度必須是二的倍數,因爲第一位存放key,第二位存放value,以此類推。

 public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

這是ThreadLocal的set代碼,可以看出,ThreadLocalMap實際上key是this,value就是傳遞過來的Looper對象。

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

這裏的代碼是獲取Looper對象的代碼。
Thread 對應了一個 static final ThreadLocal(唯一確定了)再創建Looper時,Looper唯一確定, Looper 通過prepare保證了ThreadLocal和Looper 唯一綁定,整個線程只有一個Looper。
通過get和set方法,就可以設置和獲取當前線程的唯一looper了。

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