轉自:http://blog.sina.com.cn/s/blog_5da93c8f0100y4ul.html
Android Looper和Handler
Message:消息,其中包含了消息ID,消息處理對象以及處理的數據等,由MessageQueue統一列隊,終由Handler處理。
Handler:處理者,負責Message的發送及處理。使用Handler時,需要實現handleMessage(Message msg)方法來對特定的Message進行處理,例如更新UI等。
MessageQueue:消息隊列,用來存放Handler發送過來的消息,並按照FIFO規則執行。當然,存放Message並非實際意義的保存,而是將Message以鏈表的方式串聯起來的,等待Looper的抽取。
Looper:消息泵,不斷地從MessageQueue中抽取Message執行。因此,一個MessageQueue需要一個Looper。
Thread:線程,負責調度整個消息循環,即消息循環的執行場所。
Android 系統的消息隊列和消息循環都是針對具體線程的,一個線程可以存在(當然也可以不存在)一個消息隊列和一個消息循環(Looper),特定線程的消息只能分發給本線程,不能進行跨線程,跨進程通訊。但是創建的工作線程默認是沒有消息循環和消息隊列的,如果想讓該線程具有消息隊列和消息循環,需要在線程中首先調用Looper.prepare()來創建消息隊列,然後調用Looper.loop()進入消息循環。 如下例所示:
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.loop()之後的代碼不會被立即執行,當調用後 mHandler.getLooper().quit()後,loop纔會中止,其後的代碼才能得以運行。Looper對象通過MessageQueue 來存放消息和事件。一個線程只能有一個Looper,對應一個MessageQueue。
這樣你的線程就具有了消息處理機制了,在Handler中進行消息處理。
Activity是一個UI線程,運行於主線程中,Android系統在啓動的時候會爲Activity創建一個消息隊列和消息循環(Looper)。詳細實現請參考ActivityThread.java文件。
......
public static final void main(String[] args) {
......
Looper.prepareMainLooper();
......
ActivityThread thread = new ActivityThread();
thread.attach(false);
......
Looper.loop();
......
thread.detach();
......
}
}
首先看Looper.prepareMainLooper函數的實現,這是一個靜態成員函數,定義在frameworks/base/core/java/android/os/Looper.java文件中:
2 //沒找到合適的分析代碼的辦法,只能這麼來了。每個重要行的上面都會加上註釋
3 //功能方面的代碼會在代碼前加上一段分析
4 public class Looper {
5 //static變量,判斷是否打印調試信息。
6 private static final boolean DEBUG = false;
7 private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
8
9 // sThreadLocal.get() will return null unless you've called prepare().
10 //線程本地存儲功能的封裝,TLS,thread local storage,什麼意思呢?因爲存儲要麼在棧上,例如函數內定義的內部變量。要麼在堆上,例如new或者malloc出來的東西。
11 //但是現在的系統比如Linux和windows都提供了線程本地存儲空間,也就是這個存儲空間是和線程相關的,一個線程內有一個內部存儲空間,這樣的話我把線程相關的東西就存儲到
12 //這個線程的TLS中,就不用放在堆上而進行同步操作了。
//ThreadLocal並不是一個Thread,而是Thread的局部變量。
13 private static final ThreadLocal sThreadLocal = new ThreadLocal();
14 //消息隊列,MessageQueue,看名字就知道是個queue..
15 final MessageQueue mQueue;
16 volatile boolean mRun;
17 //和本looper相關的那個線程,初始化爲null
18 Thread mThread;
19 private Printer mLogging = null;
20 //static變量,代表一個UI Process(也可能是service吧,這裏默認就是UI)的主線程
21 private static Looper mMainLooper = null;
22
23
29 //往TLS中設上這個Looper對象的,如果這個線程已經設過了Looper的話就會報錯,這說明,一個線程只能設一個looper。
//
31 public static final void prepare() {
32 if (sThreadLocal.get() != null) {
33 throw new RuntimeException("Only one Looper may be created per thread");
34 }
35 sThreadLocal.set(new Looper());
36 }
37
38
43 //由framework設置的UI程序的主消息循環,注意,這個主消息循環是不會主動退出的
44 //
45 public static final void prepareMainLooper() {
46 prepare();
47 setMainLooper(myLooper());
48 //判斷主消息循環是否能退出....
49 //通過quit函數向looper發出退出申請
50 if (Process.supportsProcesses()) {
51 myLooper().mQueue.mQuitAllowed = false;
52 }
53 }
54
55 private synchronized static void setMainLooper(Looper looper) {
56 mMainLooper = looper;
57 }
58
59
61 public synchronized static final Looper getMainLooper() {
62 return mMainLooper;
63