在Handler 異步實現時,涉及到 Handler, Looper, Message,Thread四個對象java
Message:消息,其中包含了消息ID,消息處理對象以及處理的數據等,由MessageQueue統一列隊,終由Handler處理。多線程
Handler:處理者,負責Message的發送及處理。使用Handler時,須要實現handleMessage(Message msg)方法來對特定的Message進行處理,例如更新UI等。併發
MessageQueue:消息隊列,用來存放Handler發送過來的消息,並按照FIFO規則執行。固然,存放Message並不是實際意義的保存,而是將Message以鏈表的方式串聯起來的,等待Looper的抽取。異步
Looper:消息泵,不斷地從MessageQueue中抽取Message執行。所以,一個MessageQueue須要一個Looper。ide
Thread:線程,負責調度整個消息循環,即消息循環的執行場所。oop
實現異步的流程:post
主線程啓動子線程 -> 子線程運行並生成Message而後發送到MessageQueue -> Looper獲取Message並傳遞給Handler ->Handler逐個獲取Looper中的Message並進行UI更新等操做。ui
線程在空閒(原子操做之間的間隙)時啓動Looper的loop(),裏面是for(;;),直到沒有message纔會結束。spa
因此HandleMessage不能有太耗時操做,message過多也會對UI刷新有影響。線程
Framework在Activity,Service等系統組件的主線程(UI線程---這個名稱很差,好比Service就沒UI)中會默認建Looper。
一個線程對應一個Looper,一個Looper對應一個MessageQueue。
每一個線程最多隻有一個Looper對象,它的本質是一個ThreadLocal,而ThreadLocal是在JDK1.2中引入的,它爲解決多線程程序的併發問題提供了一種新思路。
子線程建立Handler要傳入new Looper,若是本身定義子線程的Looper,方法以下:
public static prepare();
public static myLooper();
public static loop();
public void quit();
使用方法以下:
1. 在每一個線程的run()方法中的最開始調用Looper.prepare(),這是爲線程初始化消息隊列。
2. 以後調用Looper.myLooper()獲取此Looper對象的引用。這不是必須的,可是若是你須要保存Looper對象的話,必定要在prepare()以後,不然調用在此對象上的方法不必定有效果,如looper.quit()就不會退出。
3. 在run()方法中添加Handler來處理消息
4. 添加Looper.loop()調用,這是讓線程的消息隊列開始運行,能夠接收消息了。
5. 在想要退出消息循環時,調用Looper.quit()注意,這個方法是要在對象上面調用,很明顯,用對象的意思就是要退出具體哪一個Looper。若是run()中無其餘操做,線程也將終止運行。
另一種經常使用方法,簡便:
mHandler = new Handler(); mRunnable = new Runnable() { @Override public void run() { mTextView.setText("haha"); } }; mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { new Thread() { public void run() { mHandler.post(mRunnable); } }.start(); } }); }
使用Handler的post()方法就顯得UI的更新處理很是簡單:在一個Runnable對象中更新UI,而後在另外一個線程中經過Handler的post()執行該更新動做。值得注意的是,咱們就算不用新開一個新線程照樣能夠更新UI,由於UI的更新線程就是Handler的建立線程---主線程。
表面上Handler彷佛能夠發送兩種消息:Runnable對象和Message對象,實際上Runnable對象會被封裝成Message對象。
總結:
· Handler的處理過程運行在建立Handler的線程裏
· 一個Looper對應一個MessageQueue
· 一個線程對應一個Looper
· 一個Looper能夠對應多個Handler
· 不肯定當前線程時,更新UI時儘可能調用post方法