在Android中每個應用的UI線程是被保護的,不能在UI線程中進行耗時的操作,其他的子線程也不能直接進行UI操作。
為了達到這個目的Android設計了handler Looper這個系統框架。
首先講解在主線程中使用Handler時源碼跟蹤過程。
正常在activity的oncreate函數中定義個handler,這種情況下就是默認的主線程的handler,並去復寫該類的handleMessage()函數。
private final Handler mMessageHandler = new Handler(){ @Override public void handleMessage(Message msg){ ....; } }
在這里new 了一個Handler類,跟入系統代碼
106 /** 107 * Default constructor associates this handler with the {@link Looper} for the 108 * current thread. 109 * 110 * If this thread does not have a looper, this handler won't be able to receive messages 111 * so an exception is thrown. 112 */ 113 public Handler() { 114 this(null, false); 115 }
188 public Handler(Callback callback, boolean async) { 189 if (FIND_POTENTIAL_LEAKS) { 190 final Class<? extends Handler> klass = getClass(); 191 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 192 (klass.getModifiers() & Modifier.STATIC) == 0) { 193 Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 194 klass.getCanonicalName()); 195 } 196 } 197 198 mLooper = Looper.myLooper(); 199 if (mLooper == null) { 200 throw new RuntimeException( 201 "Can't create handler inside thread that has not called Looper.prepare()"); 202 } 203 mQueue = mLooper.mQueue; 204 mCallback = callback; 205 mAsynchronous = async; 206 }
最后需要對mQueue;mCallback;mAsynchronous這三個變量賦值。
這里注意 mLooper = Looper.myLooper(); 對mLooper的初始化。這里進入了Looper類
191 public static @Nullable Looper myLooper() { 192 return sThreadLocal.get(); 193 }
68 // sThreadLocal.get() will return null unless you've called prepare(). 69 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
92 private static void prepare(boolean quitAllowed) { 93 if (sThreadLocal.get() != null) { 94 throw new RuntimeException("Only one Looper may be created per thread"); 95 } 96 sThreadLocal.set(new Looper(quitAllowed)); 97 } 98
最后new Looper(quitAllowed) 在這里在當前thread中新建了一個Looper對象(所以從這里可以看出來Looper是屬於當前thread的)。
正常在我們自己new的線程中都需要調用Looper.prepare();語句來為當前線程new一個looper對象。但是對於UI線程中創建的looper是不需要的,因為在初始化UI線程時就已經寫好了。
正常UI線程初始化時調用prepareMainLooper這個函數。
99 /** 100 * Initialize the current thread as a looper, marking it as an 101 * application's main looper. The main looper for your application 102 * is created by the Android environment, so you should never need 103 * to call this function yourself. See also: {@link #prepare()} 104 */ 105 public static void prepareMainLooper() { 106 prepare(false); 107 synchronized (Looper.class) { 108 if (sMainLooper != null) { 109 throw new IllegalStateException("The main Looper has already been prepared."); 110 } 111 sMainLooper = myLooper(); 112 } 113 }
對於一般的子線程需要繼續調用Looper.loop來啟動loop循環進行消息發送。
而同樣對於UI線程的looper同樣是在初始化過程中已經調用好了。
128 public static void loop() { 129 final Looper me = myLooper(); 130 if (me == null) { 131 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 132 } 133 final MessageQueue queue = me.mQueue; .............. 142 for (;;) { 143 Message msg = queue.next(); // might block 144 if (msg == null) { 145 // No message indicates that the message queue is quitting. 146 return; 147 } 。。。。。。。。。。 158 msg.target.dispatchMessage(msg);
在這個loop()函數中就能真正看到消息循環機制。在一個死循環中for(;;)不斷從queue消息隊列中獲取messager,如果沒有將阻止在該端口等待下一個messager。
在獲取一個消息后則放入message中的targe中進行消息分發。
這里的target其實就是最開始在封裝一個message進行發送時傳入的handler,所以從這里也可以看出,最后消息還是通過handler傳入到它所在的線程中調用handleMessage()進行處理。
message.java 的成員變量:
public final class Message implements Parcelable { public int what; public int arg1; public int arg2; public Object obj; public Messenger replyTo; public int sendingUid = -1; /*package*/ static final int FLAG_IN_USE = 1 << 0; /** If set message is asynchronous */ /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1; /** Flags to clear in the copyFrom method */ /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE; /*package*/ int flags; /*package*/ long when; /*package*/ Bundle data; /*package*/ Handler target /*package*/ Runnable callback; // sometimes we store linked lists of these things /*package*/ Message next;
在主線程中創建handler:
如上所述,如果在主線程中創建handler,並不需要經歷初始化looper等操作,因為在主線程剛創建的時候系統就自動為該主線程創建好了並啟動了循環,所以我們只需要在主線程中new一個handler並且重寫handleMessage方法,當其他的子線程需要更新UI的時候,只需要獲取該handle對象,並將信息發送即可。
在自己創建的子線程中創建handler:
當在自己創建的子線程中創建handler時,需要自己手動創建looper,初始化並啟動循環。
具體步驟:
1)初始化looper: Looper.prepare();
2) 創建looper對象: mLooper = Looper.myLooper();
3) 啟動looper循環: Looper.loop();
這樣就將子線程中的looper啟動起來,接下來就只要定義我們自己需要的handler並重寫handleMessage方法即可。
在Android中還提供一種常用的handler就是HandlerThread
創建步驟:
1)新建一個HandlerThread實例: mListenerThread = new HandlerThread("XXXX");
2) 啟動該handler實例: mListenerThread.start();
3) 將該looper開啟循環: final Looper looper = mListenerThread.getLooper()
4) 定義該handler的handleMessage方法
HandlerThread uIhandlerThread = new HandlerThread("update"); uIhandlerThread.start(); finale Looper looper = uIhanderThread.getLooper(); if(looper != null){ Handler uIhandler = new Handler(looper) { @Override public boolean handleMessage(Message msg) { ... return true; } }; }