首先Message(消息)類不用多說,內部用what(啥)屬性來存放標識符,用obj(對象)來存放要攜帶的數據,用target(目標)來存放目標Handler。
所以需要有一個Handler(句柄)類來處理Message,方法是調用Handler類中的sendMessage(Message)方法,我之前一直覺得這個方法名的邏輯很奇怪,現在懂了,因為知道了另一個類:
MessageQueue(消息隊列),在調用sendMessage之後Handler會依次調用兩個不是重載但跟重載也差不多的內部方法,最後像這樣
sent = queue.enqueueMessage(msg, uptimeMillis);
把Message發送(send)給內部創建的一個MessageQueue對象,同時把Message中的target屬性設置為自己。
這時又要說到另一個類,Looper(循環器)。程序運行的時候安卓會在主線程裡創建一個Looper,
復制代碼
1 /**
2 * Initialize the current thread as a looper, marking it as an
3 * application's main looper. The main looper for your application
4 * is created by the Android environment, so you should never need
5 * to call this function yourself. See also: {@link #prepare()}
6 */
7 public static void prepareMainLooper() {
8 prepare(false);
9 synchronized (Looper.class) {
10 if (sMainLooper != null) {
11 throw new IllegalStateException("The main Looper has already been prepared.");
12 }
13 sMainLooper = myLooper();
14 }
15 }
復制代碼
它以for死循環的方式不斷嘗試從隊列中取出Message,
Message msg = queue.next();
取到了就調用這個Message中的target中存放的那個Handler的dispatchMessage(Message)方法。像這樣:
msg.target.dispatchMessage(msg);
Handler用這個方法稍微進行一下判斷,之後就轉交給自己的handleMessage(Message)方法來處理消息,這個方法和onCreate一樣是由程序員重寫,由系統調用的。
剩下的就很簡單了,handleMessage方法是程序員自己寫的,想做點什麼都行。
通常是根據Message中的what來switch一下,對於不同消息來源做出不同反應就可以啦。
那麼總結一下:
明面上程序員做兩件事。
首先是創建Handler,重寫好方法,決定用它來做點什麼;
後面的分為兩種情況。
如果調用Handler的時候需要攜帶信息,就用Message.obtain()方法或new關鍵字得到Message對象,然後使用Handler對象的sendMessage(Message)方法交由Handler處理。
如果並不需要攜帶額外信息,只需要通知Handler有事要做,就不需要自己得到Message對象,直接使用Handler對象的sendEmptyMessage(int)方法,Handler會像這樣
Message msg = Message.obtain();
msg.what = what;
自己創建一個Message對象,並用方法中傳入的int值作為Message的what屬性。
第一步,定義Handler。
第二步,發送消息。
這樣。
PS:
如果要在主線程之外使用Handler要注意一個問題。
首先按照上面說的,消息是由Looper從隊列中取出並分發的,只管自己的線程。可是主線程中使用的Looper是安卓系統創建的,用戶新建線程的時候並不會自動創建一個新的Looper,所以Looper告訴你
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
這個,Handler告訴你
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
這個。
因此,要在新線程裡創建Handler就需要調用Looper.prepare()方法來准備好一個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));
}
自己調用的時候參數是true,系統調用的時候是false,總之不需要在意。