Windows編程的朋友可能知道Windows程序是消息驅動的,並且有全局的消息循環系統。而Android應用程序也是消息驅動的,按道理來說也應該提供消息循環機制。Android通過Looper、Handler來實現消息循環機制,Android消息循環是針對線程的(每個線程都可以有自己的消息隊列和消息循環)。
在 Android 系統 ,這些工作由由由Looper 及 Handler 來完成。
先分析Looper類:
主要提供負責線程的消息循環和消息隊列
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(); // 進入消息循環
}
}
下面Looper類的準備函數:
private static final ThreadLocal sThreadLocal = new ThreadLocal();
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
這裡利用 ThreadLocal 線程局部存儲變量將將Looper與調用線程關聯起來。
而消息處理流程如何呢?
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static final void loop() {
Looper me = myLooper(); // 線程中存儲的Looper對象
MessageQueue queue = me.mQueue; // Looper類中的消息隊列
while (true) {
Message msg = queue.next(); // might block 獲取消息
//if (!me.mRun) {
// break;
//}
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
msg.target.dispatchMessage(msg); // 利用 Target 註冊的方法處理消息
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
msg.recycle();
}
}
}
可以通過Loop.myLooper()得到當前線程的Looper對象,通過Loop.getMainLooper()可以獲得當前進程的主線程的Looper對象。
在android系統,UI線程就是消息的主線程,在 ActivityThread.java 中創建:
public static final void main(String[] args) {
Looper.prepareMainLooper();
Looper.loop(); //消息循環處理
}
–>
public static final void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
if (Process.supportsProcesses()) {
myLooper().mQueue.mQuitAllowed = false;
}
}
private synchronized static void setMainLooper(Looper looper) {
mMainLooper = looper;
}
再來分析 Handler 類:
主要提供負責將消息加入到特定的Looper消息隊列中,並分發和處理訪消息隊列中的消息,構造Handler的時候可以指定一個Looper對象,如果不指定則利用當前線程的Looper創建。www.aiwalls.com
請看如下代碼即可明白:
public Handler(Looper looper, Callback callback) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
}
這裡也同時告訴我們將消息放入到主線程的消息隊列中,隻需要創建Hanlde對象時以主線程的Looper創建即可。則sendMessage及handleMessage都會在主線程中進行處理。
再看如下變量:
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
這裡也有 隊列,Looper對象及回調函數類,通過 Handler 不同構造函數完成相應的操作。
簡化使用隊列及消息傳遞的復雜性,提供方便的調用方法。其中最重要的函數是:
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg); // 1、利用 Calback 函數處理消息
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) { // 2、利用mCallback處理消息
return;
}
}
handleMessage(msg); // 3、利用子類處理消息,這裡最常用的方法,直接重載handleMessage函數
}
}
那麼這幾者的關系是怎麼樣的呢?
一個Activity中可以創建多個工作線程或者其他的組件,如果這些線程或者組件把他們的消息放入Activity的主線程消息隊列,那麼該消息就會在主線程中處理瞭。
還有一個問題就是Looper和Handler的同步關系如何處理,在android由HandlerThread類進行解決瞭。
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait(); // 如果新線程還未創建Looper對象,則等待
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
新線程創建運行run函數創建Looper對象:
public void run() {
mTid = Process.myTid();
Looper.prepare();// 這裡會創建程的Looper對象
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll(); // ok,創建好瞭則通知,最後調用Looper.loop()進入消息循環
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
這裡利用 notifyAll / wait 輕檢解決此問題瞭,所以多多使用用HanlderThread類完成多線程同步問題吧。
摘自 andyhuabing的專欄