Handler訊息傳遞機制淺析


本節引言

前兩節中我們對Android中的兩種事件處理機制進行了學習,關於回應的事件回應就這兩種;本節告訴大家的 是Activity中UI元件中的訊息傳遞Handler,相信很多朋友都知道,Android為了執行緒安全,並不允許我們在UI執行緒外操作UI;很多時候我們做介面刷新都需要透過Handler來通知UI元件更新!除了用Handler完成介面更新外,還可以使用runOnUiThread()來更新,甚至更高級的事務總線,當然,這裡我們只講解Handler,什麼是Handler,執行流程,相關方法,子線程與主線程中使用Handler的區別等!


學習路線圖:

1.jpg


#2.Handler類別的引入:

2.jpg


#3.Handler的執行流程圖:

3.jpg

#流程圖解析:相關名詞

  • UI執行緒:就是我們的主執行緒,系統在建立UI執行緒的時候會初始化一個Looper物件,同時也會建立一個與其關聯的MessageQueue;
  • Handler:作用就是傳送與處理訊息,如果希望Handler正常運作,在目前執行緒中要有一個Looper物件
  • Message: Handler接收與處理的訊息物件
  • MessageQueue:訊息佇列,先進先出管理Message,在初始化Looper物件時會建立一個與之關聯的MessageQueue;
  • Looper:每個執行緒只能夠有一個Looper,管理MessageQueue,不斷地從中取出Message分發給對應的Handler處理!

簡單說:

#當我們的子執行緒想要修改Activity中的UI元件時,我們可以新建一個Handler物件,透過這個物件傳送訊息給主執行緒;而我們傳送的訊息會先到主執行緒的MessageQueue進行等待,由Looper按先入先出順序取出,再根據message物件的what屬性分發給對應的Handler進行處理!


4.Handler的相關方法:

  • void handleMessage(Message msg):處理訊息的方法,通常是用於被重寫!
  • sendEmptyMessage(int what):發送空訊息
  • sendEmptyMessageDelayed(int what,long delayMillis):指定延時多少毫秒後傳送空白訊息
  • sendMessage(Message msg):立即傳送訊息
  • sendMessageDelayed(Message msg):指定延時多少毫秒後傳送訊息
  • final boolean hasMessage(int what):檢查訊息佇列中是否包含what屬性為指定值的訊息 如果是參數為(int what,Object object):除了判斷what屬性,還需要判斷Object屬性是否為指定物件的訊息

5.Handler的使用範例:

1)Handler寫在主執行緒中

在主執行緒中,因為系統已經初始化了一個Looper物件,所以我們直接建立Handler物件,就可以進行訊息的傳送與處理了!

程式碼範例:簡單的一個定時切換圖片的程式,透過Timer定時器,定時修改ImageView顯示的內容,從而形成幀動畫

#執行效果圖:

4.gif

#實作程式碼:

< RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  ##oroidand : @+id/RelativeLayout1"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
  android:layout_height="match_parent"  
  android:layout_height="match_parent"  
 jay.example. handlerdemo1.MainActivity" >  
#  
    <ImageView  
        android 
        android:layout_height="wrap_content"  
        and?

MainActivity.java:

public class MainActivity extends Activity {  
  
    //已定義切換的圖片的陣列id  
    able.s_1, R .drawable.s_2,R.drawable.s_3,  
       R.drawable.s_4,R.drawable.s_5,R.draw     R.drawable.s_4,R.drawable.s_5,R.draw      } ;  
    int imgstart = 0;  
      
final Handler myHandler = new Han     //重寫handleMessage方法,根據msg中what的值判斷是否執行後續操作  
      public void handleMessage(Message msg) {  
        ##            imgchange.setImageResource(imgids[imgstart++ % 8]);  
       ##        }  
    };  

#   
    @Override  1     super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main );  
        final ImageView imgchange = (ImageView) findViewById(R.id.imgchange);     00毫秒讓handler發送一個空訊息  
        new Timer() .schedule(new TimerTask() {            
             ##myHandler.sendEmptyMessage(0x123);  
                  
    00);  
    }  
  
}

#2)Handler寫在子執行緒中

如果是Handler寫在了子執行緒中的話,我們就需要自己建立一個Looper物件了!建立的流程如下:

##1 )

直接呼叫Looper.prepare()方法即可為目前執行緒建立Looper物件,而它的建構器會建立配套的MessageQueue;2 )建立Handler物件,重寫handleMessage( )方法就可以處理來自於其他執行緒的資訊了!3 )呼叫Looper.loop()方法啟動Looper

使用範例: 輸入一個數,計算後透過Toast輸出在這個範圍內的所有質數

#實作程式碼:

main.xml:

<LinearLayout  
xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    and ">  
    <EditText  
        android:id="@+id/etNum"  
  _width="match_parent"  
        android:layout_height= 「wrap_content"  
        android:hint="請輸入上限」/>  
    <Button  
    android:layout_height="wrap_content"  
        android:onClick ="cal"  
        android:text="計算"/>    
</LinearLayout>

#

MainActivity.java:

public class CalPrime extends Activity  
{  
    static final String UPPER_NUM = "upper  
    // 定義一個執行緒類別  
# #    class CalThread extends Thread  
名詞   {  
        public #        {  
#            Looper.prepare();  
     ##            {  
                // 
                public void handleMessage(Message msg)  
              if(msg.what == 0x123)  
               #                        int upper = msg.getData().getInt(UP)     List<Integer> nums = new ArrayList<Integer>eger();  
          outer:  
for (int i = 2 ; i <= upper ; i++)  
             我int j = 2 ; j < ;= Math.sqrt(i) ; j++)  
                                        //  != 2 && i % j == 0)  
                   
                                    continue outer;  
                                }  
                            }  
                            nums.add(i);  
                        }  
// 使用Toast顯示統計出來的所有質數  
                        Toast.make                 , Toast.LENGTH_LONG).show ();  
               }  
## };  
            Looper.loop();  
        }  #1 onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState); #        setContentView(R.layout.main);  
        etNum = (EditText)findViewById   
        // 啟動新執行緒  
        calThread. start();  
    }  
    // 為按鈕的點選事件提供事件處理函數  
    public void 訊息  
        Message msg = new Message();  
        msg.what = 0x123;  
        Bundle NUM ,  
            Integer.parseInt(etNum.getText().toString()) );  
        msg.setData(bundle);  
##// 傳送訊息給新執行緒中的Handler  
        calThread.mHandler.sendMessage(msg);  
    }  

##1 ~


本節小結

本節對Android中的Handler事件傳遞進行了簡單的分析,要分清楚Handler,Message,MessageQueue, Loop的概念,以及Handler寫在主線程中以及子線程​​中的區別!


#