涉及到的4個類:
Handler
Looper
ThreadLocal
MessageQueue
1.ThreadLocal
每個執行緒有一些和自己相關的變數,ThreadLocal的作用就是儲存這些變數的。所有的變數是通過內部的靜態類Value
儲存的。雖然,執行緒都是通過訪問相同的ThreadLocal
,但是每個執行緒儲存的變數是分開的:
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread); }
values.put(this, value);
}
複製程式碼
上面的set方法中,values方法返回當前執行緒的localValues成員變數:
/**
* Gets Values instance for this thread and variable type.
*/
Values values(Thread current) {
return current.localValues;
}
複製程式碼
那麼執行緒內部的localValues是什麼?
public class Thread implements Runnable {
/**
* Normal thread local values.
*/
ThreadLocal.Values localValues;
/*省略若干程式碼*/
}
複製程式碼
可以看到,Thread
中的localValues
是定義在ThreadLocal
中執行緒本地的變數。如果在 values ()
方法取得null
值,就執行initializeValues
方法。
initializeValues
是如何實現的呢?
Values initializeValues(Thread current) {
return current.localValues = new Values();
}
複製程式碼
然後將value的值放在當前執行緒的的localValues
裡。這樣,雖然看起來訪問的是用一個ThreadLocal,但是得到的值卻是根據執行緒而不同的。
注:不同sdk中ThreadLocal內部的實現時不一樣的,比如在6.0的版本實現的方式就不是上面的方式,但是原理還是一樣的
舉個例子
public class JsonTestMetaData {
public String json_str;
}
public class MainActivity extends Activity {
ThreadLocal<JsonTestMetaData> local = new ThreadLocal<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
JsonTestMetaData data = new JsonTestMetaData();
data.json_str = "main_thread";
local.set(data);
Log.e(TAG, local.get().json_str);
new Thread(new Runnable() {
@Override
public void run() {
JsonTestMetaData data = new JsonTestMetaData();
data.json_str = "other_thread";
local.set(data);
Log.e(TAG, local.get().json_str);
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
if (local.get() != null) {
Log.e(TAG, local.get().json_str);
} else {
Log.e(TAG, "local.get() is null");
}
}
}).start();
Log.e(TAG, local.get().json_str);
}
}
複製程式碼
得到的結果:
01-09 14:28:36.410 29303-29303/com.sparkfengbo.app.javabcsxtest E/MainActivity: main_thread
01-09 14:28:36.412 29303-29303/com.sparkfengbo.app.javabcsxtest E/MainActivity: main_thread
01-09 14:28:36.412 29303-29331/com.sparkfengbo.app.javabcsxtest E/MainActivity: other_thread
01-09 14:28:36.413 29303-29332/com.sparkfengbo.app.javabcsxtest E/MainActivity: local.get() is null
複製程式碼
2.MessageQueue
MessageQueue是一個訊息佇列,包含成員變數Message mMessages;
,可以理解成連結串列的頭部。儲存的形式不是佇列,而是單連結串列。
內部包含5個native方法:
private native static long nativeInit();
private native static void nativeDestroy(long ptr);
private native static void nativePollOnce(long ptr, int timeoutMillis);
private native static void nativeWake(long ptr);
private native static boolean nativeIsIdling(long ptr);
複製程式碼
底層還是通過native程式碼完成的。
在Java層面,
主要是next
方法,獲得下一個訊息;
和enqueueMessage
將訊息插入到佇列中。
3.Looper
Looper是做什麼的?Looper的職能是為一個執行緒建立MessageQueue
,繫結到這個執行緒,為此執行緒執行訊息迴圈。
Looper內部包含MessageQueue和Thread的引用
MessageQueue在prepare
方法中建立,在loop
方法開始迴圈。
Java層的Looper和MessageQueue有在C++對應的類,分別是Looper(Native)和NativeMessageQueue類
執行緒預設是沒有looper的,除非你線上程呼叫prepare
方法,然後才能執行loop
方法才能進行訊息處理。
prepare
做了什麼呢?
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));}
複製程式碼
你可以看到prepare()
方法只能呼叫一次。在最後會建立一個Looper放在ThreadLocal裡儲存。
Looper是如何建立的呢?
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
複製程式碼
可以看到,構造方法是私有的,新建立了一個MessageQueue,mThread就是當前執行緒。 那麼Looper是如何執行訊息迴圈的?
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;
for (;;) {
Message msg = queue.next();
msg.target.dispatchMessage(msg);
msg.recycleUnchecked();
}
}
複製程式碼
可以看到,通過一個無限迴圈,不停的在訊息佇列中拿訊息,將訊息分發到指定的地方。
Message的target其實就是Handler
所以,在你寫的執行緒中,可以這樣使用:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
複製程式碼
不過上述的方式太low,在程式碼中也不方便,可以這樣寫:
HandlerThread
HandlerThread thread = new HandlerThread("new_handler_thread");
Handler handler = new Handler(thread.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
return false;
}
});
複製程式碼
HandlerThread繼承自Thread,自身會建立一個Looper。
關於 HandlerThread可參考 Android HandlerThread 完全解析
大多數和訊息迴圈的互動都是通過Handler
去完成的,就像你在Handler
那部分看到的那樣。記得在你不再執行訊息迴圈的時候呼叫Looper
的quit
方法。
4.Handler
Handler
能夠傳送和處理和MessageQueue
關聯的 Message
或 Runnable
。每個Handler
和一個單獨的執行緒關聯,這個執行緒就是你建立這個Handler
的時候所在的執行緒,需要處理的MessageQueue
也是這個執行緒的MessageQueue
。
請看:
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;
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
複製程式碼
Handler有很多個建構函式,最終都會呼叫到這個建構函式。你可以看到Handler中的的Looper成員,就是通過Looper的靜態方法myLooper
得到的,myLooper
是幹啥的?你可以看Looper的內容,在上面程式碼中得到了一個和這個執行緒關聯的Looper。如果 mLooper
成員是null
,那麼就丟擲異常。你可能會問,我在activity中隨便建立handler啊,沒有呼叫Looper.myLooper()
方法。那是因為當你的應用執行的時候,Android已經通過Looper
的靜態方法prepareMainLooper
建立了,這個方法只能執行一次,否則就會丟擲異常了。這個Looper
適合執行緒繫結的,你再看看mQueue
,是從mLooper
中拿到的。
呼叫的順序如下:
- Message的callback是否是null?不是呼叫callback的run方法(其實這裡Message的callback是一個Runnable物件,通過Handler的post方法傳遞)
- Handler的callback是否是null?不是呼叫callback。這裡的callback的型別是
Handler.Callback()
- 最終呼叫Handler的handleMessage的方法。
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
複製程式碼
5. MessageQueue.IdleHandler
簡而言之,就是在looper裡面的message暫時處理完了,這個時候會回撥這個介面,返回false,那麼就會移除它,返回true就會在下次message處理完了的時候繼續回撥