[轉]Android中handler總結

來源:互聯網
上載者:User

標籤:

一、Handler的定義:

    Handler主要接收子線程發送的資料, 並用此資料配合主線程更新UI,用來跟UI主線程互動用。比如可以用handler發送一個message,然後在handler的線程中來接收、處理該訊息,以避免直接在UI主線程中處理事務導致影響UI主線程的其他處理工作,Android提供了Handler作為主線程和子線程的紐帶;也可以將handler對象傳給其他進程,以便在其他進程中通過handler給你發送事件;還可以通過handler的延時發送message,可以延時處理一些事務的處理。

通常情況下,當應用程式啟動時,Android首先會開啟一個主線程 (也就是UI線程) , 主線程為管理介面中的UI控制項,進行事件分發。如果此時需要一個耗時的操作,例如:連網讀取資料,或者讀取本地較大的一個檔案的時候,你不能把這些操作放在主線程中,如果你放在主線程中的話,介面會出現假死現象,如果5秒鐘還沒有完成的話,會收到Android系統的一個錯誤提示"強制關閉". 

這個時候我們需要把這些耗時的操作,放在一個子線程中,因為子線程涉及到UI更新,但是當子線程中有涉及到操作UI的操作時,就會對主線程產生危險,也就是說,更新UI只能在主線程中更新,在子線程中操作是危險的. 這個時候,Handler就出現了來解決這個複雜的問題,由於Handler運行在主線程中(UI線程中),它與子線程可以通過Message對象來傳遞資料,這個時候,Handler就承擔著接受子線程傳過來的(子線程用sedMessage()方法傳遞)Message對象,(裡麵包含資料), 把這些訊息放入主線程隊列中,配合主線程進行更新UI。

 

二、Handler一些特點

        handler可以分發Message對象和Runnable對象到主線程中, 每個Handler執行個體,都會綁定到建立他的線程中(一般是位於主線程), 也就是說Handler對象初始化後,就預設與對它初始化的進程的訊息佇列綁定,因此可以利用Handler所包含的訊息佇列,制定一些操作的順序。

 

三、Handler中分發訊息的一些方法

        post(Runnable)

        postAtTime(Runnable,long)

        postDelayed(Runnable long)

            post類方法允許你排列一個Runnable對象到主線程隊列中

        sendEmptyMessage(int)

        sendMessage(Message)

        sendMessageAtTime(Message,long)

        sendMessageDelayed(Message,long)

           sendMessage類方法, 允許你安排一個帶資料的Message對象到隊列中,等待更新.

 

四、應用執行個體:

   1,傳遞Message。用於接受子線程發送的資料, 並用此資料配合主線程更新UI

          在Android中,對於UI的操作通常需要放在主線程中進行操作。如果在子線程中有關於UI的操作,那麼就需要把資料訊息作為一個Message對象發送到訊息佇列中,然後,用Handler中的handlerMessge方法處理傳過來的資料資訊,並操作UI。類sendMessage(Message msg)方法實現發送訊息的操作。 在初始化Handler對象時重寫的handleMessage方法來接收Messgae並進行相關操作。

  2,傳遞Runnable對象。用於通過Handler綁定的訊息佇列,安排不同操作的執行順序。

Handler對象在進行初始化的時候,會預設的自動綁定訊息佇列。利用類post方法,可以將Runnable對象發送到訊息佇列中,按照隊列的機制按順序執行不同的Runnable對象中的run方法。

另外,Android的CPU分配的最小單元是線程,Handler一般是在某個線程裡建立的,因而Handler和Thread就是相互綁定的,一一對應。而Runnable是一個介面,Thread是Runnable的子類。所以說,他倆都算一個進程。

                                                                                                                                                                       

 視頻教程中的例子:

 

  1. public class HandlerActivity extends Activity {  
  2.      
  3.     //聲明兩個按鈕控制項  
  4.     private Button startButton = null;  
  5.     private Button endButton = null;  
  6.     @Override 
  7.     public void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.main);  
  10.          //根據控制項的ID得到代表控制項的對象,並為這兩個按鈕設定相應的監聽器  
  11.          startButton = (Button)findViewById(R.id.startButton);  
  12.          startButton.setOnClickListener(new StartButtonListener());  
  13.          endButton = (Button)findViewById(R.id.endButton);  
  14.          endButton.setOnClickListener(new EndButtonListener());  
  15.            
  16.      }  
  17.      class StartButtonListener implements OnClickListener{  
  18.   
  19.          @Override 
  20.          public void onClick(View v) {  
  21.              //調用Handler的post方法,將要執行的線程對象添加到隊列當中  
  22.              handler.post(updateThread);  
  23.          }  
  24.            
  25.      }  
  26.        
  27.      class EndButtonListener implements OnClickListener{  
  28.   
  29.          @Override 
  30.          public void onClick(View v) {  
  31.             handler.removeCallbacks(updateThread);  
  32.          }  
  33.           
  34.      }  
  35.      //建立一個Handler對象  
  36.      Handler handler  = new Handler();  
  37.      //將要執行的操作寫線上程對象的run方法當中  
  38.      Runnable updateThread =  new Runnable(){  
  39.   
  40.          @Override 
  41.          public void run() {  
  42.              System.out.println("UpdateThread");  
  43.              //在run方法內部,執行postDelayed或者是post方法  
  44.              handler.postDelayed(this, 3000);  
  45.          }  
  46.            
  47.      };  

48. } 

    程式的運行結果就是每隔3秒鐘,就會在控制台列印一行UpdateTread。這是因為實現了Runnable介面的updateThread對象進入了空的訊息佇列即被立即執行run方法,而在run方法的內部,又在3000ms之後將其再次發送進入訊息佇列中。

  3, Handler和多線程

    post方法雖然發送的是一個實現了Runnable介面的類對象,但是它並非建立了一個新線程,而是執行了該對象中的run方法。也就是說,整個run中的操作和主線程處於同一個線程。

    這樣對於那些簡單的操作,似乎並不會影響。但是對於耗時較長的操作,就會出現“假死”。為瞭解決這個問題,就需要使得handler綁定到一個新開啟線程的訊息佇列上,在這個處於另外線程的上的訊息佇列中處理傳過來的Runnable對象和訊息。 

 

  1. public class HandlerTest2 extends Activity {  
  2.  
  3.     @Override 
  4.     protected void onCreate(Bundle savedInstanceState) {  
  5.         // TODO Auto-generated method stub  
  6.     super.onCreate(savedInstanceState);  
  7.     setContentView(R.layout.main);  
  8.     //列印了當前線程的ID  
  9.     System.out.println("Activity-->" + Thread.currentThread().getId());  
  10.      //產生一個HandlerThread對象  
  11.      HandlerThread handlerThread = new HandlerThread("handler_thread");  
  12.      //在使用HandlerThread的getLooper()方法之前,必須先調用該類的start(),同時開啟一個新線程;  
  13.      handlerThread.start();
  14.      //將由HandlerThread擷取的Looper傳遞給Handler對象,即由處於另外線程的Looper代替handler初始化時預設綁定的訊息佇列來處理訊息。  
  15.       // HandlerThread顧名思義就是可以處理訊息迴圈的線程,它是一個擁有Looper的線程

16. ,可以處理訊息迴圈;  其實與其說Handler和一個線程綁定,倒不如說HandlerLooper

17. 一一對應的。

  1.      MyHandler myHandler = new MyHandler(handlerThread.getLooper());  
  2.      Message msg = myHandler.obtainMessage();  
  3.      //將msg發送到目標對象,所謂的目標對象,就是產生該msg對象的handler對象  
  4.      Bundle b = new Bundle();  
  5.      b.putInt("age", 20);  
  6.      b.putString("name", "Jhon");  
  7.      msg.setData(b);  
  8.      msg.sendToTarget();  //將msg發送到myHandler
  9.      }  
  10.        
  11.      //定義類
  12.      class MyHandler extends Handler{  
  13.      public MyHandler(){  
  14.                
  15.      }  
  16.      
  17.     public MyHandler(Looper looper){  
  18.         super(looper);  
  19.      }  
  20.      @Override 
  21.      public void handleMessage(Message msg) {  
  22.         Bundle b = msg.getData();  
  23.         int age = b.getInt("age");  
  24.         String name = b.getString("name");  
  25.          System.out.println("age is " + age + ", name is" + name);  
  26.          System.out.println("Handler--->" + Thread.currentThread().getId());  
  27.          System.out.println("handlerMessage");  
  28.          }  
  29.      }  

47. }  

    這樣,當使用sendMessage方法傳遞訊息或者使用post方法傳遞Runnable對象時,就會把它們傳遞到與handler對象綁定的處於另外一個線程的訊息佇列中,它們將在另外的訊息佇列中被處理。而主線程還會在發送操作完成時候繼續進行,不會影響當前的操作。

這裡需要注意,這裡用到的多線程並非由Runnable對象開啟的,而是ThreadHandler對象開啟的。Runnable對象只是作為一個封裝了操作的對象被傳遞,並未產生新線程。

另外再強調一遍,在UI線程(主線程)中:

    mHandler=new Handler();

    mHandler.post(new Runnable(){

    void run(){

       //執行代碼..

     }

    });

    這個線程其實是在UI線程之內啟動並執行,並沒有建立線程。

 

    常見的建立線程的方法是:

    Thread thread = new Thread();

    thread.start();

 

    HandlerThread thread = new HandlerThread("string");

    thread.start();

[轉]Android中handler總結

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.