handler機制

handler機制的一個引子android

在android系統當中,有一個很是重要的鐵律,在UI線程以外,是不能修改UI的,在後臺線程,新起一個線程,獲得的數據結果是不能直接反映在UI上的。
MainThread (UI線程或主線程)和 WorkrThread (除了主線程以外的其餘的線程都叫workThread,對一些可能產生阻塞的操做要放在workthread中完成)
workthread從原則上來說是不容許操做UI的,個別控件除外(ProgressBar)
在一個應用程序當中,UI線程一般用於接收用戶的界面輸入以及將運算結果反饋給用戶程序員

一個問題,workThread中運算,結果沒法反饋到UI,又不能把運算的過程放在主線程中,就產生了workThread和mainThread通信的問題。網絡

handle機制就是解決這一問題的ide

什麼是handler,handler消息處理機制:oop

handler就是一個消息處理器,handler,looper(循環器),messageQueue 所構成的這樣的一個系統,是android系統當中最重要的消息傳遞,以及消息處理機制。
handler負責把消息對象加入到消息隊列當中去,looper(循環器)負責把消息對象從消息隊列當中取出。handler負責放,looper負責從消息隊列中往外取。
若是消息隊列中沒有消息對象,那麼負責取出消息對象的LOOP的這行代碼就會產生阻塞(處於等待的狀態),looper把消息對象從消息隊列中取出來以後幹什麼呢?
looper將會調用handler的handlerMessage方法來處理message對象

線程

主線程中 Handler A發了一個消息,Handler B在主線程中能不能接收到這個消息呢?一個handler的實例只能接受到本身發的message的信息,對象

不少handler共享的是一個messageQueue,經過Message 的what的屬性來進行標的,只能收到本身handler相關的message隊列

主線程有一個Looper,是一個死循環,監聽消息隊列,但又不是額外的線程,可是不會阻塞主線程,Looper由系統來控制的,底層的vm來控制的消息隊列

並不是每一個線程都有Looper的實例string

handler類的主要做用有兩個:

在新啓動的線程中發送消息,在主線程中獲取、處理消息。
每一個線程只擁有一個Looper,loop方法負責讀取消息隊列中的消息,讀到信息以後就把消息交給發送該消息的handler處理

在UI線程中,系統已經初始化了一個Looper對象,所以程序直接建立handler便可,而後經過handler發送處理消息
程序員本身啓動的子線程,程序員須要本身建立一個Looper對象,用prepare方法建立looper對象。


示例1(從workThread向mainThread發消息)

public class MainActivity extends Activity {

  private TextView textView;
  private Button button;
  private Handler handler;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    textView = (TextView)findViewById(R.id.textviewId);
    button = (Button)findViewById(R.id.buttonId);
    button.setOnClickListener(new ButtonListener());
    handler = new MyHandler();
  }
  class ButtonListener implements OnClickListener {

    @Override
    public void onClick(View v) {
      Thread thread = new NetWorkThread();
      thread.start();
    }
  }

  class NetWorkThread extends Thread {
    @Override
    public void run() {
      try {
        Thread.sleep( 2 * 1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      String string = "從網絡測獲取的數據";
      Message msgMessage = handler.obtainMessage();
      msgMessage.obj = string;
      //sendmessage方法不管在主線程中仍是workthread中都是能夠發送的
      handler.sendMessage(msgMessage);
    }
  }

  class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
      String string = (String)msg.obj;
      //在主線程中就能夠隨意的操做UI了
      textView.setText(string);
    }
  }
}

示例2(從mainThread向workThread發消息,在workThread中生成handler對象)

public class MainActivity extends Activity {

  private Handler handler;
  private Button button;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    button = (Button)findViewById(R.id.buttonId);
    button.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        Message msg = handler.obtainMessage();
        handler.sendMessage(msg);
      }
    });
    WorkerThread wtThread = new WorkerThread();
    wtThread.start();
  }

  class WorkerThread extends Thread {
    @Override
    public void run() {
      //準備Looper對象
      Looper.prepare();
      //在workThread當中生成一個handler對象
      handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
          System.out.println("收到了消息對象");
        }
      };
      //調用Loop()方法以後,Looper對象不斷的從消息隊列當中取出消息對象,而後調用handler的handleMessage方法
      //處理消息對象,若是消息隊列當中沒有消息對象,則線程阻塞
      Looper.loop();
    }
  }

      LOOPER是由系統控制的,底層實現的,不阻塞主線程

      HandlerThread類有Looper對象,不須要prepare}

相關文章
相關標籤/搜索