Hander Looper 学习

来源:互联网 发布:java erp源码 编辑:程序博客网 时间:2024/06/06 23:17

1.  Message Queue的角色

 

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

l  Android裡並沒有GlobalMessage Queue資料結構,例如,不同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 = newEevntHandler(Looper.myLooper()); 可誕生用來處理目前線程的Handler物件;其中,EevntHandlerHandler的子類別。

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

 

2. 範例之一:Looper物件之角色

 

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

 

 

Hander <wbr>Looper <wbr>学习

 

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

 

//-----Looper_01範例-----

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;

 

public class ac01extends Activityimplements OnClickListener{

          private final int WC=LinearLayout.LayoutParams.WRAP_CONTENT;

          private final int FP=LinearLayout.LayoutParams.FILL_PARENT;

          public TextViewtv;

   private EventHandlermHandler;

   private Buttonbtn, btn2, btn3;

   

   public void onCreate(Bundleicicle) {

               super.onCreate(icicle);

               LinearLayoutlayout = new LinearLayout(this);

               layout.setOrientation(LinearLayout.VERTICAL);

                              

               btn = new Button(this);

               btn.setId(101);

               btn.setBackgroundResource(R.drawable.heart);

               btn.setText("testlooper");

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

              }

            public void onClick(View v){

                    switch(v.getId()){

                    case 101:

                               Looper looper;

                        looper = Looper.myLooper();

                        mHandler =new EventHandler(looper);

                        mHandler.removeMessages(0);

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

                        String obj = "This mymessage!";

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

                        // 組裝成一個Message物件

                        mHandler.sendMessage(m);

                        // Message物件送入MessageQueue

                 break;

                    case 102:

               finish();

                               break;

                    }

          }

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

class EventHandlerextends Handler

             {

                 public EventHandler(Looperlooper) {

                     super(looper);

                 }

                 @Override

                 public void handleMessage(Messagemsg) {

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

             }

          }

}

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

說明:

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

   指令:looper = Looper.myLooper();

 

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

指令:mHandler =new EventHandler(looper);

 

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

 

Hander <wbr>Looper <wbr>学习

 

 

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

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

指令:mHandler.sendMessage(m);

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

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

 

 

Hander <wbr>Looper <wbr>学习

 

 

3. 範例之二:由別的線程送訊息到主線程的Message Queue

 

//-----Looper_02範例-----

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;

 

public class ac01extends Activityimplements OnClickListener{

          private final int WC=LinearLayout.LayoutParams.WRAP_CONTENT;

          private final int FP=LinearLayout.LayoutParams.FILL_PARENT;

          public TextViewtv;

    private myThreadt;

   private Buttonbtn, btn2, btn3;

   

   public void onCreate(Bundleicicle) {

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

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

              }

            public void onClick(View v){

                    switch(v.getId()){

                    case 101:

                                t=new myThread();

                        t.start();

                        break;

                    case 102:

               finish();

                               break;

                    }

          }

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

class EHandlerextends Handler {

                 public EHandler(Looperlooper) {

                     super(looper);

                 }

                 @Override

                 public void handleMessage(Messagemsg) {

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

             }

          }

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

class myThreadextends Thread{

           private EHandlermHandler;

           public void 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物件。於是,執行到指令:

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

    指令:mHandler.sendMessage(m);

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

 

 Hander <wbr>Looper <wbr>学习

 

 

4. 結語:

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

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

 

---- END---

创建的工作线程默认是没有消息循环和消息队列的,如果想让该线程具有消息队列和消息循环,需要在线程中首先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环。如下例所示:

  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();
  }
}
HandlerThread 可用于方便的创建一个新线程,然后获得一个looper,以便指定后续的handler在新的线程里执行。 而不用自己再去写一个线程类,然后创建looper等操作。
示例:
HandlerThread thread = new HandlerThread("ServiceStartArguments",                Process.THREAD_PRIORITY_BACKGROUND);
        thread.start();       
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);

转至:http://www.android1.net/Topic.aspx?BoardID=11&TopicID=625

0 0