- 我們看下基本的概念
- messagequeue===中文的翻譯是消息隊列,它的內部存儲了一組消息,以隊列的形式對外提供增加和刪除的方法,但是他的內部不是隊列的結構形式,而是采用單鏈表的數據結構來存儲消息列表
- looper==輪詢器,也可以理解為消息循環,由于messagequeue是一個消息容器,所以他負責不斷的去輪訓消息,如果有消息處理的話就去處理消息,否則就一直等待著。他還有一個特殊的概念threadlocal
,并不是線程,他的作用是在每個線程中存儲數據,負責綁定當前的線程的loop
- 首先我們知道創建一個handel
new Handler();就行了但是其中內部干了什么呢?
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());
}
//獲取loper對象,如果lopper對象為空就會報異常,這就是為什么我們在子線程使用需要主動的調用 Looper.prepare();
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;
}
我們看下Looper.prepare();的源碼可以得知,只有sThreadLocal為空的時候起創建了一個Looper對象
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));
}
那么為什么我們在主線程就沒有調用就沒事呢!
其實你在創建activitythred的內部就給你調用了Looper.prepareMainLooper()調用了Looper.prepare()方法,因此我們應用程序的主線程中會始終存在一個Looper對象,從而不需要再手動去調用Looper.prepare()方法了。
-
然后我們發送消息需要什么?
messag對message,我們看看怎么創建一個message,那么創建message有那些方式,2中,我們一般推薦使用 Message.obtain();為什么推薦這個我么你看下源碼! //我們可以清楚,首先他會看Message對象是不是已經存在了,如果存在了就直接復用,沒有直接創建,這樣原因不說也明白了吧。 ` 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();
}`
- 有了消息我們就要發送出去,如何發送呢!
`handler.sendMessage(message);`,這樣我們就可以把消息發送出去。那么它里面是如何發送消息的,我們通過看源碼得知他最終回調用sendMessageAtTime(),我們看下源碼
//其中msg參數就是我們發送的Message對象,而uptimeMillis參數則表示發送消息的時間,它的值等于自系統開機到當前時間的毫秒數再加上延遲時間
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//如果quer為空就會停止輪訓消息
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
//進入enqueueMessage
return enqueueMessage(queue, msg, uptimeMillis);
}
//通過看源碼我們知道,MessageQueue是在調用looper的時候創建的,因此一個Looper也就對應了一個MessageQueue。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
我們看下enqueueMessage的方法,在這里進行消息的入隊,將消息插入到messagequene
final boolean enqueueMessage(Message msg, long when) {
if (msg.when != 0) {
throw new AndroidRuntimeException(msg + " This message is already in use.");
}
//如果為空將報異常,msg.target就是handel
if (msg.target == null && !mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit");
}
synchronized (this) {
//如果調用了quit就會賦值為true
if (mQuiting) {
RuntimeException e = new RuntimeException(msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
} else if (msg.target == null) {
mQuiting = true;
}
msg.when = when;
Message p = mMessages;
//在這里他們將按照時間的順序排列
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
this.notify();
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
this.notify();
}
}
if (needWake) {
//在native層進行消息的傳遞
nativeWake(mPtr);
}
return true;
}
- 接下來我們看下消息的輪訓 loop.loop()
public static final void loop() {
//獲取Looper
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
//這里面也是個死循環去取消息如果當前MessageQueue中存在mMessages(即待處理消息),就將這個消息出隊,然后讓下一條消息成為mMessages,否則就進入一個阻塞狀態,一直等到有新的消息入隊。
//MessageQueue中的nex方法,去輪訓消息內部是一個無限的循環輪詢,這里面要想退出這個無限的循環只有queue.next()
返回null,而要讓他返回null,通過看源碼mQuitting就行了,也就是說只要調用quit就可以了
Message msg = queue.next(); // might block
if (msg != null) {
//如果handel為空將直接退出循環
if (msg.target == null) {
return;
}
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
//這里就會調用handeld的dispatchMessage進行消息的分發,為什么是msg.target是handel通過源碼我們看到enqueueMessage里面進行的賦值 msg.target = this;我們看下怎么分發的
msg.target.dispatchMessage(msg);
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
msg.recycle();
}
}
}
//我們進入到這個方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//這個方法熟悉把就把消息傳遞到我們重寫的主線程的方法了,在這里進行回調handleMessage
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}