天天看點

Android異步通信機制(二)

在工作線程中使用Handler

在UI線程中已經有了Looper,但是在工作線程中要自己實作Looper:

       class LooperThread extends Thread {

                public Handler mHandler;

                   public void run() {

                       Looper.prepare();

                       mHandler = new Handler() {

                            public void handleMessage(Message msg) {

                            // process incoming messages here

                             }

                        };

                        Looper.loop(); //不能在這個後面添加代碼,程式是無法運作到這行之後的

                   }

      }

在建立Handler之前,為該線程準備好一個Looper(Looper.prepare),然後讓這個Looper跑起來(Looper.loop),抽取Message,這樣,Handler才能正常工作。

不是所有的Handler都能更新UI

    Handler處理消息總是在建立Handler的線程裡運作。而我們的消息進行中,不乏更新UI的操作,不正确的線程直接更新UI将引發異常。是以,需要時刻關心Handler在哪個線程裡建立的。如何更新UI才能不出異常呢?SDK告訴我們,有以下4種方式可以從其它線程通路UI線程(也即線程間通信):

·      Activity.runOnUiThread(Runnable)

·      View.post(Runnable)

·      View.postDelayed(Runnable, long)

·      在UI線程中建立的Handler

其中,重點說一下的是View.post(Runnable)方法。在post(Runnable action)方法裡,View獲得目前線程(即UI線程)的Handler,然後将action對象post到Handler裡。在Handler裡,它将傳遞過來的action對象包裝成一個Message(Message的callback為action),然後将其投入UI線程的消息循環中。在 Handler再次處理該Message時,有一條分支(未解釋的那條)就是為它所設,直接調用runnable的run方法。而此時,已經路由到UI線程裡,是以,我們可以毫無顧慮的來更新UI。

幾點小結

·      Handler的處理過程運作在建立Handler的線程裡

·      一個Looper對應一個MessageQueue,一個線程對應一個Looper,一個Looper可以對應多個Handler

·      不确定目前線程時,更新UI時盡量調用View.post方法

·      handler應該由處理消息的線程建立。

·      handler與建立它的線程相關聯,而且也隻與建立它的線程相關聯。handler運作在建立它的線程中,是以,如果在handler中進行耗時的操作,會阻塞建立它的線程。

·      Android的線程分為有消息循環的線程和沒有消息循環的線程,有消息循環的線程一般都會有一個Looper。主線程(UI線程)就是一個消息循環的線程。

·      Looper.myLooper();      //獲得目前的Looper

        Looper.getMainLooper () //獲得UI線程的Lopper

·      Handle的初始化函數(構造函數),如果沒有參數,那麼他就預設使用的是目前的Looper,如果有Looper參數,就是用對應的線程的Looper。

·      如果一個線程中調用Looper.prepare(),那麼系統就會自動的為該線程建立一個消息隊列,然後調用 Looper.loop();之後就進入了消息循環,這個之後就可以發消息、取消息、和處理消息。

Android提供了一個封裝好的帶有looper的線程類,即為HandlerThread,具體可參見下面的代碼:

public class HandlerThreadActivity extends Activity {

     private static final String TAG = "HandlerThreadActivity";

     private HandlerThread mHandlerThread;

     private MyHandler mMyHandler;

     @Override

     protected void onCreate(Bundle savedInstanceState) {

         // TODO Auto-generated method stub

         super.onCreate(savedInstanceState);

         TextView text = new TextView(this);

         text.setText("HandlerThreadActivity");

         setContentView(text);

         Log.d(TAG, "The main thread id = " +      Thread.currentThread().getId());

         //生成一個HandlerThread對象,實作了使用Looper來處理消息隊列的功能,

         //這個類由Android應用程式架構提供

         mHandlerThread = new HandlerThread("handler_thread");

         //在使用HandlerThread的getLooper()方法之前,必須先調用該類的start();

         mHandlerThread.start();

         //即這個Handler是運作在mHandlerThread這個線程中

         mMyHandler = new MyHandler(mHandlerThread.getLooper());

         mMyHandler.sendEmptyMessage(1);

     }

      private class MyHandler extends Handler {

         public MyHandler(Looper looper) {

              super(looper);

         }

         @Override

         public void handleMessage(Message msg) {

              Log.d(TAG, "MyHandler-->handleMessage-->thread id = " + Thread.currentThread().getId());

              super.handleMessage(msg);

         }

     }

}