隨筆-348  評論-598  文章-0  trackbacks-0
          public class

          Looper

          extends Object
          java.lang.Object
             ? android.os.Looper

          Class Overview

          Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.

          Most interaction with a message loop is through the Handler class.

          This is a typical example of the implementation of a Looper thread, using the separation of prepare() and loop() to create an initial Handler to communicate with the 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();
          }
          }
          Looper提供了一種消息循環(huán)機制,主要為Handler服務(wù)。
          你會問,在主線程里面可以創(chuàng)建Handler,那為什么還要啟動一個線程去Loop另外一個Handler呢?
          那是因為每個Handler實例只能服務(wù)于一個線程和他的消息隊列(Each Handler instance is associated with a single thread and that thread's message queue),如果你單獨啟動了另外一個線程去進行某些操作,同時又要發(fā)送消息,那么就需要你創(chuàng)建一個Looper線程,里面聲明一個Handler實例,然后在其他某個線程中去調(diào)用這個Handler,這樣就不會有問題了。
          當(dāng)然這里需要注意的是,你不能在這個Handler中去修改UI控件的屬性,那是因為,你這個Handler仍然處于非UI主線程中,如果要修改UI,那么你可以在這個Handler中調(diào)用主線程的一個UI Handler去Post一個消息,在那個消息中對UI控件進行修改等操作。

          通過傳遞不同線程的Looper,可以使得Handler服務(wù)于不同的線程。

          1.  Message Queue的角色

          l   在你的Android程式裡,新誕生一個線程,或稱執(zhí)行緒(Thread)時,並不會自動建立其Message Loop。

          l   Android裡並沒有GlobalMessage Queue資料結(jié)構(gòu),例如,不同APK裡的物件不能透過Massage Queue來交換訊息(Message)

          l   一個線程可以誕生一個Looper之物件,由它來管理此線程裡的Message Queue。

          l   你可以誕生Handler之物件來與Looper溝通,以便push新訊息到Message Queue裡;或者接收Looper(Message Queue取出)所送來的訊息。

          l   線程AHandler物件參考可以傳遞給別的線程,讓別的線程BC等能送訊息來給線程A(存於AMessage Queue)。

          l   線程AMessage Queue裡的訊息,只有線程A所屬的物件可以處理之。

          l   使用Looper.myLooper可以取得目前線程的Looper物件參考值。

          l   使用mHandler = new EevntHandler(Looper.myLooper()); 可誕生用來處理目前線程的Handler物件;其中,EevntHandlerHandler的子類別。

          l   使用mHandler = new EevntHandler(Looper.getMainLooper()); 可誕生用來處理main線程的Handler物件;其中,EevntHandlerHandler的子類別。

          2. 範(fàn)例之一:Looper物件之角色

          Looper類別用來管理特定線程內(nèi)物件之間的訊息交換(Message Exchange)。你的應(yīng)用程式可以誕生許多個線程,或稱執(zhí)行緒(Thread)。而一個線程可以誕生許多個物件,這些物件之間常常需要互相交換訊息。如果有這種需要,您可以替線程誕生一個Looper類別之物件,來擔(dān)任訊息交換的管理工作。Looper物件會建立一個MessageQueue資料結(jié)構(gòu)來存放各物件傳來的訊息(包括UI事件或System事件等)。如下圖:

               每一個線程(Thread,或稱「執(zhí)行緒」)裡可含有一個Looper物件以及一個MessageQueue資料結(jié)構(gòu)。在你的應(yīng)用程式裡,可以定義Handler的子類別來接收Looper所送出的訊息。

          //----- Looper_01範(fàn)例 -----

          package com.misoo.kx04;

          import android.app.Activity;

          import android.graphics.Color;

          import android.os.Bundle;

          import android.os.Handler;

          import android.os.Looper;

          import android.os.Message;

          import android.view.View;

          import android.view.View.OnClickListener;

          import android.widget.Button;

          import android.widget.LinearLayout;

          import android.widget.TextView;

          publicclass ac01 extends Activity implements OnClickListener {

                     privatefinalintWC = LinearLayout.LayoutParams.WRAP_CONTENT;

                     privatefinalintFP = LinearLayout.LayoutParams.FILL_PARENT;

                     public TextView tv;

              private EventHandler mHandler;

              private Button btn, btn2, btn3;

             

              publicvoid onCreate(Bundle icicle) {

                          super.onCreate(icicle);

                          LinearLayout layout = new LinearLayout(this);

                          layout.setOrientation(LinearLayout.VERTICAL);

                                        

                          btn = new Button(this);

                          btn.setId(101);

                          btn.setBackgroundResource(R.drawable.heart);

                          btn.setText("test looper");

                          btn.setOnClickListener(this);

                          LinearLayout.LayoutParams param =

                              new LinearLayout.LayoutParams(100,50);

                          param.topMargin = 10;

                          layout.addView(btn, param);

                         

                          btn2 = new Button(this);

                          btn2.setId(102);

                          btn2.setBackgroundResource(R.drawable.ok_blue);

                          btn2.setText("exit");

                          btn2.setOnClickListener(this);

                          layout.addView(btn2, param);

                         

                          tv = new TextView(this);

                          tv.setTextColor(Color.WHITE);

                          tv.setText("");

                          LinearLayout.LayoutParams param2 =

                             new LinearLayout.LayoutParams(FP, WC);

                          param2.topMargin = 10;

                          layout.addView(tv, param2);

                          setContentView(layout);     

                         }

                        publicvoid onClick(View v) {

                               switch(v.getId()){

                               case 101:

                                          Looper looper;

                                    looper = Looper.myLooper();

                                    mHandler = new EventHandler(looper);

                                    mHandler.removeMessages(0);

                                    // 清除整個MessageQueue裡的事件,確保不會通知到別人

                                    String obj = "This my message!";

                                    Message m = mHandler.obtainMessage(1, 1, 1, obj);

                                    // 組裝成一個Message物件

                                    mHandler.sendMessage(m);

                                    // Message物件送入MessageQueue

                             break;

                               case 102:

                            finish();

                                          break;

                               }

                     }

          //------------------------------------------------------             

          class EventHandler extends Handler

                         {

                             public EventHandler(Looper looper) {

                                 super(looper);

                             }

                             @Override

                             publicvoid handleMessage(Message msg) {

                                tv.setText((String)msg.obj);

                         }

                     }

          }

          //-------------------------------------------------------

          說明:

              此程式啟動時,目前線程(即主線程, main thread)已誕生了一個Looper物件,並且有了一個MessageQueue資料結(jié)構(gòu)。

              指令:looper = Looper.myLooper();

          就呼叫Looper類別的靜態(tài)myLooper()函數(shù),以取得目前線程裡的Looper物件之參考值。

          指令:mHandler = new EventHandler(looper);

          誕生一個EventHandler之物件來與Looper溝通。Activity等物件可以藉由EventHandler物件來將訊息傳給Looper,然後放入MessageQueue裡;EventHandler物件也扮演Listener的角色,可接收Looper物件所送來的訊息。如下圖:

          指令:Message m = mHandler.obtainMessage(1, 1, 1, obj);

          先誕生一個Message物件,並將資料存入次物件裡。

          指令:mHandler.sendMessage(m);

          就透過mHandler物件而將訊息m傳給Looper,然後放入MessageQueue裡。

          此時,Looper物件看到MessageQueue裡有訊息m,就將它廣播出去,mHandler物件接到此訊息時,會呼叫其handleMessage()函數(shù)來處理之,於是輸出"This my message!"於畫面上,如下:

          3. 範(fàn)例之二:由別的線程送訊息到主線程的Message Queue

          //----- Looper_02範(fàn)例 -----

          package com.misoo.kx04;

          import android.app.Activity;

          import android.graphics.Color;

          import android.os.Bundle;

          import android.os.Handler;

          import android.os.Looper;

          import android.os.Message;

          import android.view.View;

          import android.view.View.OnClickListener;

          import android.widget.Button;

          import android.widget.LinearLayout;

          import android.widget.TextView;

          publicclass ac01 extends Activity implements OnClickListener {

                     privatefinalintWC = LinearLayout.LayoutParams.WRAP_CONTENT;

                     privatefinalintFP = LinearLayout.LayoutParams.FILL_PARENT;

                     public TextView tv;

             private myThread t;

              private Button btn, btn2, btn3;

             

              publicvoid onCreate(Bundle icicle) {

                          super.onCreate(icicle);

                          LinearLayout layout = new LinearLayout(this);

                          layout.setOrientation(LinearLayout.VERTICAL);

                                        

                          btn = new Button(this);

                          btn.setId(101);

                          btn.setBackgroundResource(R.drawable.heart);

                          btn.setText("test looper");

                          btn.setOnClickListener(this);

                          LinearLayout.LayoutParams param =

                              new LinearLayout.LayoutParams(100,50);

                          param.topMargin = 10;

                          layout.addView(btn, param);

                         

                          btn2 = new Button(this);

                          btn2.setId(102);

                          btn2.setBackgroundResource(R.drawable.ok_blue);

                          btn2.setText("exit");

                          btn2.setOnClickListener(this);

                          layout.addView(btn2, param);

                         

                          tv = new TextView(this);

                          tv.setTextColor(Color.WHITE);

                          tv.setText("");

                          LinearLayout.LayoutParams param2 =

                             new LinearLayout.LayoutParams(FP, WC);

                          param2.topMargin = 10;

                          layout.addView(tv, param2);

                          setContentView(layout);     

                         }

                        publicvoid onClick(View v) {

                               switch(v.getId()){

                               case 101:

                                           t = new myThread();

                                    t.start();

                                    break;

                               case 102:

                            finish();

                                          break;

                               }

                     }

          //------------------------------------------------------             

          class EHandler extends Handler {

                             public EHandler(Looper looper) {

                                 super(looper);

                             }

                             @Override

                             publicvoid handleMessage(Message msg) {

                                tv.setText((String)msg.obj);

                         }

                     }

          //------------------------------------------------------             

          class myThread extends Thread{

                      private EHandler mHandler;

                      publicvoid run() {

                          Looper myLooper, mainLooper;

                         myLooper = Looper.myLooper();

                          mainLooper = Looper.getMainLooper();

                          String obj;

                          if(myLooper == null){

                                 mHandler = new EHandler(mainLooper);

                                 obj = "current thread has no looper!";

                          }

                          else {

                               mHandler = new EHandler(myLooper);

                               obj = "This is from current thread.";

                          }

                          mHandler.removeMessages(0);

                          Message m = mHandler.obtainMessage(1, 1, 1, obj);

                          mHandler.sendMessage(m);

                      }

           }

          }

          //-------------------------------------------------------

          Android會自動替主線程建立Message Queue。在這個子線程裡並沒有建立Message Queue。所以,myLooper值為null,而mainLooper則指向主線程裡的Looper物件。於是,執(zhí)行到指令:

          mHandler = new EHandler(mainLooper); mHandler屬於主線程。

               指令:mHandler.sendMessage(m);

          就將m訊息存入到主線程的Message Queue裡。mainLooper看到Message Queue裡有訊息,就會處理之,於是由主線程執(zhí)行到mHandlerhandleMessage()函數(shù)來處理訊息。此程式輸出畫面為:

          4. 結(jié)語:

          l   Message Loop的用途很廣。請你參閱高煥堂所寫的Android系列書籍,尤其是其中的第4本書:<<Android設(shè)計招式之美>> 。

          l   以上只是本文的前半段而已,請你繼續(xù)閱讀後半段。



          ---------------------------------------------------------
          專注移動開發(fā)

          Android, Windows Mobile, iPhone, J2ME, BlackBerry, Symbian
          posted on 2010-02-18 10:52 TiGERTiAN 閱讀(3541) 評論(0)  編輯  收藏 所屬分類: Java 、Android
          主站蜘蛛池模板: 拜城县| 三河市| 健康| 长春市| 商南县| 盱眙县| 五寨县| 滨海县| 桃源县| 阿克陶县| 中阳县| 临桂县| 自治县| 霸州市| 保亭| 延边| 甘孜县| 田阳县| 金华市| 辛集市| 荔浦县| 肇源县| 库车县| 开封县| 广宗县| 章丘市| 宁晋县| 桃源县| 扎赉特旗| 蒙山县| 萨嘎县| 永济市| 湖南省| 西乌珠穆沁旗| 芮城县| 安溪县| 武穴市| 临朐县| 江永县| 安阳市| 通榆县|