兩張圖看透Android Handler使用與機制
1.Handler的使用
-
如圖所示,需要做的操作有兩步:
-
在主線程中實例化一個Handler,并且重寫HandleMessage方法用來處理子線程發送來的消息。
-
在子線程中,首先聲明Message對象,并將Message使用主線程中實例化的Handler的sendMessage(Message)方法發送給主線程。
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final Handler handler=new Handler(){ @Override public void handleMessage(Message m){ //更新ui操作 } }; new Thread(){//子線程開啟 @Override public void run(){ Message m=new Message(); handler.sendMessage(m); } }; } }
-
2.Handler的機制
-
在使用sendMessage和handleMessage之前是有很多已經隱藏的封裝好的過程的,現在一一講解。
2.1 被消息傳遞的線程A準備
-
首先要在被消息傳遞的線程中創建Looper,因為Handler創建的時候要綁定當前線程的Looper,使用Looper.prepare()建立。
- Looper.prepare()
public static void prepare() { prepare(true); } 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)); } private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
總的來說,prepare干了兩件事: 創建MessageQueue和綁定當前線程。
- Looper.prepare()
-
然后使用Looper.loop()讓Looper開始循環訪問MessageQueue。
-
Looper.loop();
public static void loop() { // 拿到與當前線程關聯的looper對象 final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; .......................................
for (;;) { Message msg = queue.next(); // might block ................................... msg.target.dispatchMessage(msg); .......................................... msg.recycleUnchecked();// 回收Message對象 }
}</code></pre>
總的來說,loop干了三件事:
1.拿到當前線程的looper。
2.根據looper拿到MessageQueue。
3.使用for循環對MessageQueu進行無限循環詢問。
在for循環中也主要干了三件事:
1.從消息隊列中取消息,如果沒有就阻塞。
2.調用msg.target.dispatchMessage(msg)方法對Message進行處理。
3.處理完成后調用msg.recycleUnchecked()回收資源。
</li> </ul> </li>創建Handler,作為線程間通信的工具。
public Handler(Looper looper, Callback callback, boolean async){ mLooper = looper; // 與這個Handler關聯的Looper中的消息隊列 mQueue = looper.mQueue; ............... }
創建Handler時將當前線程的Looper和Looper中的MessageQueue取到。
2.2 傳遞消息的線程B準備
-
創建Message時,使用Message.obtain()的效果大于New Message(),因為享元模式,維護了一個大小為50的Message對象池,比重復去創建Message更加高效。
-
Handler.sendMessage(Message)方法最終會調用sendMessageAtTime方法。
public boolean sendMessageAtTime(Message Message, long uptimeMillis) { // 1. 獲取Hndler中的消息隊列 MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } // 2. 將要發送消息和時間入隊 return enqueueMessage(queue, Message, uptimeMillis); }
總的來說,做了兩件事:
1.獲取handler中的MessageQueue。
2.調用enqueueMessage方法。
enqueueMessage()方法代碼如下:
private boolean enqueueMessage(MessageQueue queue, Message Message, long uptimeMillis) { // 1. 將Handler賦值給Message的target Message.target = this; if (mAsynchronous) { Message.setAsynchronous(true); } // 2. 將Message加入到消息隊列中(還有Handler) return queue.enqueueMessage(Message, uptimeMillis); }
總的來說,做了兩件事:
1.將handler賦值給Message.target。
2.并且將Message放入MessageQueue中。
2.3 線程間通信
-
線程B的sendMessage流程執行完畢,至于線程A的Looper和Handler都已經創建好了,并且開始處理MessageQueue中的Message,還記得之前for循環中Message.target.dispatchMessage()方法嗎,其實這里的Message.target就是handler,而且dispatchMessage()方法的源碼如下:
public void dispatchMessage(Message msg) { .......... handleMessage(msg); }
3.一些問題
-
為什么Activity主線程沒有執行Looper.prepare()和Looper.loop()?
因為在ActivityThread的main方法中已經執行了這兩個方法。
-
一個線程可以擁有幾個Looper?幾個Handler?
一個線程只能擁有一個Looper,無數個Handler。
-
如何從主線程發送消息給子線程?
在子線程中先建立Looper,然后再建立Handler,依靠sendMessage和handleMessage即可。
來自:http://www.jianshu.com/p/8862ab82d0f4
-