標籤:android style blog http color os io 使用 ar
首先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,總之不需要在意。
Handler用來讓其他線程修改UI啊,這個不用我說吧。
Android的訊息處理(Handler相關)