一個Handler能夠發送、處理和線程的消息隊列關聯的Message和Runnable對象。每個Handler實例與一個線程以及這個線程的消息隊列相關。當建立一個新的Handler對象,它就會綁定到建立它的線程/消息隊列。它能夠分發Message對象和Runnable對象到主線程中。
java
Handler包含了兩個隊列,一個是線程隊列,一個是消息隊列。使用post方法會將線程對象放到該handler的線程隊列中,使用sendMessage(Message message)將消息放到消息隊列中。handler.post(r)並無單獨開啓一個新的線程,而是仍然在當前Activity線程中執行,handler只是調用了Runnable對象的run方法。android
它有兩個做用:canvas
安排Message對象和Runnable對象在線程的指定位置執行安全
使一個action在其餘線程中執行併發
當應用程序啓動時,Android首先會開啓一個主線程(UI線程),主線程管理界面中的UI控件。如界面上有一個Button, 點擊button時,android會分發事件來響應操做,這個過程都是在主線程中進行。這時若是須要一個耗時的操做,那麼界面會出現假死現象,若是5s沒完成,android系統會給一個錯誤提示"強制關閉"。因此應該把這些耗時的操做放在一個子線程中,由於子線程的操做涉及到UI更新,而主線程是線程不安全的,能夠用Handler解決。由於Handler運行在主線程中,它和子線程能夠經過Message對象來傳遞數據。Handler負責接收子線程傳過來的Message對象(子線程中經過sendMessage()傳遞),而後把消息放入主線程隊列中,配合主線程更新UI.ide
例一:oop
public class ProgressBarActivity extends Activity { ProgressBar pb; Button begin; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.progressbar); pb = (ProgressBar) findViewById(R.id.pb); pb.setMax(100); begin = (Button)findViewById(R.id.begin); begin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { pb.setVisibility(View.VISIBLE); //⑴點擊begin按鈕,將要執行的線程對象myThread放到線程隊列中 handler.post(myThread); } }); } Handler handler = new Handler(){ //⑷執行handleMessage public void handleMessage(Message msg) { pb.setProgress(msg.arg1); //當進度條已滿,將線程對象從隊列中移除 if(msg.arg1==pb.getMax()){ handler.removeCallbacks(myThread); }else{ handler.post(myThread); } } }; //⑵線程開始執行 Runnable myThread = new Runnable() { int i = 0; public void run() { System.out.println("begin thread"); i+=10; Message msg = handler.obtainMessage(); msg.arg1 = i; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //⑶將Message對象加入到消息隊列中,handler接收消息一定要執行handleMessage(Message msg) handler.sendMessage(msg); if(i==100){ //當i==100,將線程對象從隊列中移除,因爲handler接收消息會執行handleMessage,因此此處的代碼無心義 handler.removeCallbacks(myThread); } } }; }
若是上面的代碼中,handleMessage(Message msg)修改成:post
public void handleMessage(Message msg) { pb.setProgress(msg.arg1); handler.post(myThread); }
那麼在i=100時,雖然線程中執行了handler.removeCallbacks(myThread),當時仍然會繼續run方法,繼續打印begin thread。由於在線程的run方法執行後在handleMessage裏,handler.post(myThread)又把線程加入線程隊列,因此仍然會繼續執行線程。this
以上代碼的執行過程:點擊begin按鈕後,將myThread線程對象加入到線程隊列中,線程執行,併發出Handler消息通知UI更新,Handler接收消息執行handleMessage,更新UI。spa
注意:若是handler要接收消息,那麼就得執行handleMessage方法。
例二:
public class AHandler extends Activity { Handler handler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); handler.post(r); Log.d("M====>", "main"); setContentView(R.layout.main); } Runnable r = new Runnable() { @Override public void run() { Log.d("T====>","tread"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }; } 執行結果: M====> main T====> tread Handler在主線程,因此不管在onCreate()方法裏handler.post(r)不管出於那個位置,在執行時,是在主線程中添加r消息隊列,而不是另外開啓一條新線程,主線程代碼執行完畢,就執行線程r。 因此先打印M====> main,而後再打印線程r裏的T====> tread
例三:忽略BoundView class( onDraw(Canvas canvas) )
public class BounceActivity extends Activity { protected static final int GUIUPDATEIDENTIFIER = 0x101; BounceView bounceView = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.bounceView = new BounceView(this); this.setContentView(this.bounceView); new Thread(new MyThread()).start(); } Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case BounceActivity.GUIUPDATEIDENTIFIER: bounceView.invalidate(); break; } super.handleMessage(msg); } }; class MyThread implements Runnable{ @Override public void run() { while(!Thread.currentThread().isInterrupted()){ Message msg = new Message(); msg.what = BounceActivity.GUIUPDATEIDENTIFIER; BounceActivity.this.handler.sendMessage(msg); try { Thread.sleep(3000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } } } 運行正常. 在主線程中new Thread(new MyThread()).start()開啓了一條新的線程。 雖然在run()方法中循環執行handler.sendMessage(),由於這個操做處於子線程中,因此主線程的handler的Looper監聽到有消息,就會執行handleMessage()
例四: 將例三的代碼作了修改。
onCreate()方法裏將new Thread(new MyThread()).start()修改成handler.post(r).
public class BounceActivity extends Activity { protected static final int GUIUPDATEIDENTIFIER = 0x101; BounceView bounceView = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.bounceView = new BounceView(this); this.setContentView(this.bounceView); handler.post(r); } Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case BounceActivity.GUIUPDATEIDENTIFIER: bounceView.invalidate(); break; } super.handleMessage(msg); } }; Runnable r = new Runnable() { @Override public void run() { while(!Thread.currentThread().isInterrupted()){ Message msg = handler.obtainMessage(); msg.what = BounceActivity.GUIUPDATEIDENTIFIER; handler.sendMessage(msg); try { Thread.sleep(3000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }; } 主線程代碼執行完畢後,執行r,可是卻不執行handleMessage()。
例4,由於handler屬於主線程,handler.post(r)並非單獨開啓一條新線程,它只是執行r 線程的run()方法,在run()方法裏有個while()致使循環執行,因爲handler和這個run()方法的操做同屬一條線程,因此只有run()執行完畢,纔會執行handleMessage()。例4想要執行handleMessage()方法,去掉run()方法的while()循環便可。