Handler用法總結-Android學習筆記



一、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方法處理傳過來的數據信息,並操作UIsendMessage(Message msg)方法實現發送消息的操作。 在初始化Handler對象時重寫的handleMessage方法來接收Messgae並進行相關操作。

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

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

另外,AndroidCPU分配的最小單元是線程Handler一般是在某個線程裏創建的,因而HandlerThread就是相互綁定的,一一對應。而Runnable是一個接口,ThreadRunnable的子類。所以說,他倆都算一個進程。

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(updateThread, 3000);  

45.         }  

46.           

47.     };  

48. }

    程序的運行結果就是每隔3秒鐘,就會在控制檯打印一行UpdateTread。這是因爲實現了Runnable接口的updateThread對象進入了空的消息隊列即被立即執行run方法,而在run方法的內部,又在3000ms之後將其再次發送進入消息隊列中。


3Handler和多線程

    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和一個線程綁定,倒不如說Handler和Looper是

17. 一一對應的。

18.     MyHandler myHandler = new MyHandler(handlerThread.getLooper());  

19.     Message msg = myHandler.obtainMessage();  

20.     //將msg發送到目標對象,所謂的目標對象,就是生成該msg對象的handler對象  

21.     Bundle b = new Bundle();  

22.     b.putInt("age", 20);  

23.     b.putString("name", "Jhon");  

24.     msg.setData(b);  

25.     msg.sendToTarget();  //將msg發送到myHandler

26.     }  

27.       

28.     //定義類

29.     class MyHandler extends Handler{  

30.     public MyHandler(){  

31.               

32.     }  

33.     

34.     public MyHandler(Looper looper){  

35.         super(looper);  

36.     }  

37.     @Override 

38.     public void handleMessage(Message msg) {  

39.         Bundle b = msg.getData();  

40.         int age = b.getInt("age");  

41.         String name = b.getString("name");  

42.         System.out.println("age is " + age + ", name is" + name);  

43.         System.out.println("Handler--->" + Thread.currentThread().getId());  

44.         System.out.println("handlerMessage");  

45.         }  

46.     }  

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();

    轉載地址:http://blog.sina.com.cn/s/blog_77c6324101016jp8.html



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章