android Handler機制詳解

1、幾個相關概念簡述:java

    一、MessageQueue:  消息隊列,存放消息的容器。注意:每個線程最多隻有一個MessageQueue,建立一個線程的時候,並不會自動建立其MessageQueue。一般使用一個Looper對象對該線程的MessageQueue進行管理。主線程建立時,會建立一 個默認的Looper對象,而Looper對象的建立,將自動建立一個MessageQueue。其餘非主線程,不會自動建立Looper,要須要的時候,經過調用prepare函數來實現。android

    二、Message:消息對象,存儲與MessageQueue中,一個MessageQueue包含多個Message對象,這些Message對象遵循先進先出的原則。注意:一般會new一個message實例對象,或者經過Handler對象的obtainMessage()獲取一個Message實例,使用removeMessages()方法能夠將消息從隊列中刪除;數據結構

    三、Looper:消息封裝的載體,是MessageQueue的管理者。每個MessageQueue都不能脫離Looper而存在,Looper對象的建立是經過prepare函數來實現的。同時每個Looper對象和一個線程關聯。經過調用Looper.myLooper()能夠得到當前線程的Looper對象。注意:建立一個Looper對象時,會同時建立一個MessageQueue對象。除了主線程有默認的Looper,其餘線程默認是沒有MessageQueue對象的,因此,不能接受Message。如須要接受,本身定義一個Looper對象(經過prepare函數),這樣該線程就有了本身的Looper對象和MessageQueue數據結構了。多線程

    四、Handler:封裝了消息的發送和處理,handler負責將須要傳遞的信息封裝成Message,經過調用handler對象的obtainMessage()來實現; 將消息傳遞給Looper,這是經過handler對象的sendMessage()來實現的。繼而由Looper將Message放入MessageQueue中。 當Looper對象看到MessageQueue中含有Message,就將其廣播出去。該handler對象收到該消息後,調用相應的handler對象的handleMessage()方法 對其進行處理。併發

    五、HandlerThread:本質上是線程加消息的實現;ide

    總結:handler負責發送消息,Looper負責接收handler發送的消息,並直接把消息回傳給handler本身,MessageQueue是消息存儲的容器。函數

2、Handler機制:oop

    一、Handler是什麼?post

    FAQ:handler是android提供用來更新UI的一套機制,也是一套消息處理的機制,咱們能夠發送消息,也能夠經過它處理消息;性能

    二、爲何要使用Handler?

    FAQ:android設計的時候就封裝了一套消息建立、傳遞處理的機制,若是不遵循這樣的機制就沒法更新UI,就會拋出異常。

    三、如何使用Handler?

    FAQ:見Handler經常使用方法,sendMessage,sendMessageDelayed,post(Runnable),postDelayed(Runnable, long)等。

    四、android設計爲何只能經過Handler機制更新UI呢?

    FAQ:根本目的是解決多線程併發的問題,加鎖會致使性能降低;

    五、常見的handler異常分析。

    (1)android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views。

    這個問題主要是在子線程裏修改了UI致使的,

(2)Can't create handler inside thread that has not called

    這個問題是在子線程裏建立Handler前沒有調用Looper.prepare()和looper關聯致使的。

    六、如何實現一個與線程相關的Handler?

    FAQ:下面代碼實現了在子線程裏建立Handler對象。

class MyThread extends Thread {
 public Handler handler;
 @Override
 public void run() {
     Looper.prepare();//沒有這段代碼會報5中的(2)異常。
     handler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
      System.out.println("currentThread------------->"
       + Thread.currentThread().getId());
  }
     };
     Looper.loop();
 }
    }

    七、如何在主線程給子線程發送消息?

    FAQ:見下面代碼,實現了主線程和子線程互發信息。

public class MainActivity extends Activity implements OnClickListener {
    private TextView textView;
    private Button start, stop;
    private Handler thread;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.fragment_main);
 textView = (TextView) findViewById(R.id.textView1);
 start = (Button) findViewById(R.id.Start);
 stop = (Button) findViewById(R.id.Stop);
 start.setOnClickListener(this);
 stop.setOnClickListener(this);
 HandlerThread handlerThread = new HandlerThread("handlerThread");
 handlerThread.start();
 thread = new Handler(handlerThread.getLooper()) {
     @Override
     public void handleMessage(Message msg) {
    Message message = new Message();
  mainHandler.sendMessageDelayed(message, 1000);
  System.out.println("threadHandler---->" + Thread.currentThread().getId());
     }
 };
    }
    // 主線程
    Handler mainHandler = new Handler() {
 public void handleMessage(Message msg) {
     Message message = new Message();
     thread.sendMessageDelayed(message, 1000);
     System.out.println("mainHandler---->" + Thread.currentThread().getId());
 };
    };
    @Override
    public void onClick(View v) {
 if (v == start) {
     mainHandler.sendEmptyMessage(0);
 } else if (v == stop) {
     mainHandler.removeMessages(0);
 }
    }
}

    八、Android中更新UI有幾種方式?

    FAQ:常見android中更新UI的方式又如下四種,runOnUIThread ,handler.post ,handler.sendMessage view.post。經過源碼去看,實質上都是使用handler機制去處理UI的。

    九、android非UI線程真的不能更新UI嗎?

    FAQ:在android非UI現場中真的不能更新UI嗎,你們看下下面的代碼:

new Thread(){
     public void run() {
  textView.setText("updateview");
     };
 }.start();

運行這段代碼,你會神奇地發現更新了UI,再看下面的這段代碼:

new Thread(){
     public void run() {
     try{
        Thread.sleep(2000);
      textView.setText("updateview");
     }catch(Exception e){
     }     
         };
 }.start();

    你會神奇地發現報了「五、常見的handler異常分析」中的異常(1),因此不建議在非UI線程中去更新UI。

    十、Handler的Callback用法:

private Handler handler = new Handler(new Callback() {//截獲消息
  @Override
  public boolean handleMessage(Message msg) {
   Toast.makeText(getApplicationContext(), "1", 1).show();
   return false;//false會發送兩個消息,true,不會處理下面的消息
  }
 }) {
  @Override
  public void handleMessage(Message msg) {
   Toast.makeText(getApplicationContext(), "2", 1).show();
  }
 };
 
handler.sendEmptyMessage(0);
相關文章
相關標籤/搜索