Android多執行緒基礎 解析Handler機制
解析非同步訊息處理機制
Android的非同步訊息處理主要由4個部分組成:Message,Handler,MessageQueue以及Looper。
1.Message:是線上程之間傳遞資訊,它可以在內部攜帶少量資訊,用於在不同執行緒之間交換資料。
2.Handler:是處理者的意思,它主要用於傳送和處理訊息的。
3.MessageQueue:是訊息佇列的意思,他主要用於存所有通過Handler傳送的訊息,這部分訊息為一直存在於訊息佇列中,等待被處理。每個執行緒只會有一個MessageQueue物件。
4.Looper:每個執行緒MessageQueue的管理者。呼叫Looper.loop()方法後,會進入到一個無線迴圈中,只要一發現MessageQueue中存在一條訊息,就會將他取出,並且傳遞到Handler的handleMessage()方法中,每個執行緒也只會有一個Looper物件。
非同步訊息處理流程:
需要在主執行緒建立一個Handler物件,並重寫handleMessage( )方法,然後在子執行緒需要更新UI的時候,建立一個Message物件,並通過Handle將資訊傳送,之後這條訊息會被新增到MessageQueue中等待被處理,而Looper會一直迴圈的從MessageQueue中取出訊息,最後分發回撥handleMessage( )方法中。而此時操作也就變換到了主執行緒,因此可以放心的更新UI了。
問題一:在子執行緒想更新UI的時候,為什麼Handler必須宣告在主執行緒呢?
解決這個問題之前,要先知道,UI執行緒的訊息迴圈是在ActivityThread.main方法中建立的,該函式為Android應用程式入口,程式碼如下:
Looper.prepareMainLooper();//1.建立訊息迴圈Looper
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop(); //2.開啟訊息迴圈
throw new RuntimeException("Main thread loop unexpectedly exited");
由這段程式碼可以知道,當應用程式建立啟動時, Looper.prepareMainLooper();就已經幫我們建立了Looper,並且開啟了訊息迴圈。
而當我們在子執行緒執行耗時操作後,就需要Handler將一個訊息Post到UI執行緒,然後在handleMessage( )處理,然而每個Handler都會關聯一個訊息佇列,訊息佇列被封裝在Looper中。
問題二:既然Handler關聯了執行緒以及訊息佇列,那麼他們是如何關聯的呢?摘取一段程式碼
public Handler( ){
//省略上面程式碼
mLooper = Looper.myLooper();//獲取Looper
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物件,還有訊息佇列,那麼他們是如何獲取訊息物件的呢?進去 myLooper,如下:
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
發現它是 sThreadLocal.get( )獲取的,那麼它又是什麼時候存了 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));//建立了Looper物件並賦值給了sThreadLocal
}
這樣 Looper就和執行緒關聯上了,不同的執行緒就不能訪問對方的訊息佇列,再看回來Handler的預設建構函式, mQueue = mLooper.mQueue;//獲取訊息佇列,讓Looper物件和訊息佇列關聯,而Handler又和Looper關聯,Looper又與執行緒關聯,那麼他們就關聯起來了。
那麼問題一的答案就出來了:
預設情況下,訊息佇列只有一個即上面分析的主執行緒的訊息佇列它在 Looper.prepareMainLooper();方法中建立,而Handler又和Looper關聯,Looper又與執行緒(主執行緒)關聯,此時只有Handler宣告下主執行緒,handleMessage才會在主執行緒執行,在主執行緒更新UI才是安全的。
問題三:建立Looper後,是如何執行訊息迴圈的?
在ActivityThread.main方法中進去看Looper.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(); //獲取訊息
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//....省略
try {
msg.target.dispatchMessage(msg);//訊息處理
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//....省略
msg.recycleUnchecked();//回收訊息
}
}
在 msg.target.dispatchMessage(msg)中,msg是Message型別進去 Message
public final class Message implements Parcelable {
Handler target;
Runnable callback;
Message next;
}
可以知道target是一個Handler,在上一篇中知道,我們通過知道了Handler將訊息傳送給訊息佇列,然後在這裡訊息佇列又會把訊息分發給Handler處理。
看下訊息分發處理:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
從上面的Message型別可以知道callback是Runnable型別的,在分發的時候回進行判斷,不為空由 handleCallback(msg);處理,為空時 handleMessage(msg);處理,而 handleMessage(msg);是一個空方法,我們平時寫的更新UI操作也是在這裡面執行的。其實他就是Handler分發的兩種方式,一種Post(Runnable callback),一種sendMessage:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
這兩種最後都是會執行sendMessageDelayed()方法:
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
繼續進去看sendMessageAtTime()方法。
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);
}
繼續進去看enqueueMessage()方法。
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物件
因此可以知道不管是Pos方法還是sendMessage方法,最後Handler都會把訊息加到訊息佇列MessageQueue中。然後Looper會不斷的去獲取訊息,並且呼叫 Handle的dispatchMessage的訊息也就是( msg.target.dispatchMessage(msg);//訊息處理),這樣訊息就會不停的被產生,被新增,和被處理。這就是訊息的處理機制
相關文章
- 大話Android多執行緒(三) 執行緒間的通訊機制之HandlerAndroid執行緒
- 解析Java的多執行緒機制(2)(轉)Java執行緒
- 解析Java的多執行緒機制(1)(轉)Java執行緒
- Android多執行緒之Handler、Looper與MessageQueue原始碼解析Android執行緒OOP原始碼
- 多執行緒系列(1),多執行緒基礎執行緒
- 多執行緒系列(二):多執行緒基礎執行緒
- 多執行緒基礎執行緒
- Android執行緒間訊息機制-Handler原始碼分析(FrameWork)Android執行緒原始碼Framework
- 多執行緒學習一(多執行緒基礎)執行緒
- 【Java基礎】執行緒和併發機制Java執行緒
- java - 多執行緒基礎Java執行緒
- Java—多執行緒基礎Java執行緒
- Java 多執行緒基礎(四)執行緒安全Java執行緒
- 多執行緒系列(三):執行緒池基礎執行緒
- 多執行緒基礎-基礎實現執行緒
- Handler機制解析
- Java 多執行緒基礎(八)執行緒讓步Java執行緒
- 多執行緒基礎入門執行緒
- Java 多執行緒基礎 - CyclicBarrierJava執行緒
- Java多執行緒-基礎篇Java執行緒
- pthread 多執行緒基礎thread執行緒
- 基礎鞏固 --多執行緒執行緒
- 多執行緒基礎知識執行緒
- python多執行緒基礎Python執行緒
- Java高階-解析Java中的多執行緒機制(轉)Java執行緒
- Android的Handler訊息機制 解析Android
- 多執行緒之等待通知機制執行緒
- JAVA多執行緒與鎖機制Java執行緒
- Handler訊息機制完全解析Handler解析
- C#多執行緒開發-執行緒基礎 01C#執行緒
- C++多執行緒基礎教程C++執行緒
- 併發與多執行緒基礎執行緒
- JAVA_基礎多執行緒(一)Java執行緒
- JAVA多執行緒-基礎篇-synchronizedJava執行緒synchronized
- Android 基礎知識——執行緒Android執行緒
- 多執行緒程式設計基礎(一)-- 執行緒的使用執行緒程式設計
- Java 多執行緒基礎(六)執行緒等待與喚醒Java執行緒
- 細說C#多執行緒那些事:執行緒基礎C#執行緒