一、基礎概念java
1)android.os.Handler android
2)主要接受子線程發送的數據, 並用此數據配合主線程更新UI. 緩存
3)應用程序一旦啓動,Android UI 這個主線程的生命週期就開始了,然而,Android UI 線程並非線程安全的,也就是說,更新UI只能在主線程中同步更新,子線程中異步操做是危險的。因此,項目中若是咱們直接new Thread 內部去更改Android UI,每每會報錯誤以下:安全
java.lang.RuntimeException: Can't create handler inside thread that has not called
異步
爲了不錯誤發生,那麼更新Android UI 必須在主線程中操做,具體如何操做呢?Handler就發揮了特的做用。Handler的使用同時也會帶來許多相關的知識,下面一一講解。ide
二、實例化oop
1)採用默認的方式 new Handler();項目中不多使用這種方式。若是他是主線程中運行的,那麼這個handler對象內部綁定了一個Looper對象Looper.getMainLooper();Looper對象是用來幹嗎的呢? Looper類是用來爲一個線程開啓一個消息循環。能夠這樣獲取對應的線程:handler.getLooper().getThread()。默認狀況下Android中新誕生的線程是沒有開啓消息循環的(主線程中new的則有)。換句話說,Looper內部有一個線程對象,這個對象會輪詢獲取消息隊列的消息,這個消息隊列就是MessageQueue,Looper對象經過MessageQueue來存放消息和事件,一個線程只能有一個Looper,對應一個MessageQueue。post
總結就是:性能
A:主線程中 handler = new Handler();那麼這個handler內部綁定了 Looper.getMainLooper() 對象或Looper.myLooper();spa
B:在子線程中,如在Thread中 handler = new Handler();那麼這個handler的Looper對象時空的。
那麼,關於子線程中應該如何爲handler註冊Looper呢?能夠這樣使用
HandlerThread handlerThread = new HandlerThread("sub thread");
handlerThread.start(); // 這句很重要 ,應該是爲線程異步運行提供環境
handler = new Handler(handlerThread.getLooper());
2)採用繼承方式,繼承方式就是多了Looper對象的綁定方法,這樣綁定確實有點麻煩。
class MyHandler extends Handler { public MyHandler() { } public MyHandler(Looper looper) { super(looper); } // 子類必須重寫此方法,接受數據 @Override public void handleMessage(Message msg) { // msg.what 進行判斷,調用對應的方法更新UI } }
3)採用內部類方式,內部類方式與默認new Handler相差無幾,惟一的區別就是內部類須要重寫handleMessage方法,否者意義就不大了,項目中每每使用這種方式。那麼爲何推薦這種方式呢?首先咱們定義個全局的私有Handler,而後定義時採用內部類實例化對象,下次使用時直接調用handler,只要保證這個handler的Looper對象是主線程的Looper就好,也就是不要在本身的Thread中去實例化handler。
三、handler調用
1)因爲一切關於消息隊列的事情都有Looper對象處理,那麼就沒必要過於深究了。如今只要好好理解如何使用handler,關於handler同步的問題,若是handler內部綁定的是主線程的Looper對象,那麼,在咱們調用 handler.post(new Thread())的時候,這個註冊的Thread實際上是在主線中串行,而不是並行。就好像調用的是Thread對象的run方法而非start方法,那麼意義就不大了!
2)項目中耗時的工做應該給一個異步的子線程處理,若是你放在主線程中的話,界面會出現假死現象,,若是5秒鐘尚未完成的話,會收到Android系統的一個錯誤提示 "強制關閉"。然而子線程又不能更新主線程的UI,那麼問題就來了,應該如何結合Handler讓子線程與主線程並行呢?一種方式就是採用 handlerThread 爲 當前的handler對象綁定一個全新的 Looper對象,那麼就能夠實現以上要求了。固然,更好的方式是:單獨new Thread ,在Thread內部調用已經實例化話好的handler對象,這樣也是一個異步調用。
4 handler消息傳送
1)Message對象是與handler綁定的,handler能夠採用sendMessage(Message)方式把Message對象發送到handler的handleMessage方法中,通常咱們採用message.what 方法做爲不一樣消息類型的標識;另外,message的兩個參數 arg1 與 arg2 是效率相對較高的,由於他們消耗系統性能較少。
2)Bundle對象是handler的一個成員變量,能夠把bundle當作是一個特殊的Map對象,兩者都是用來緩存數據,只是Bundle的key只能是String,並且Bundle的方法相對Map更爲豐富。另外,Bundle對象不侷限與handler,在intent或者在Activity的onCreate方法中到處可見。
總結:
不能在子線程中直接更新Android UI ,須要採用Handler處理,然而handler處理時須要注意內部的Looper對象是否已經綁定,若是沒有綁定須要手動註冊一個Looper。對於同步仍是異步調用,也須要適當的處理。