Handler訊息傳遞機制(一)

來源:互聯網
上載者:User

Handler訊息傳遞機制(一)

為什麼要用Handler:

出於效能最佳化考慮,Android的UI操作並不是安全執行緒的,這意味著如果有多個線程並行作業UI組件,可能導致安全執行緒問題。為瞭解決這個問題,Android制定了一條簡單的原則:只允許UI線程(亦即主線程)修改Activity中的UI組件。
當一個程式第一次啟動時,Android會同時啟動一條主線程,主線程主要負責處理與UI相關的事件,如使用者的按鍵事件、使用者接觸螢幕的事件、螢幕繪圖事件,並把相關的事件分發到相應的組件進行處理,所以主線程通常又叫做UI線程。

Handler的概念:

1)執行計畫任務,可以在預定的時間執行某些任務,可以類比定時器
2)線程間通訊。在Android的應用啟動時,會建立一個主線程,主線程會建立一個

訊息佇列來處理各種訊息。當你建立子線程時,你可以在你的子線程中拿到父線程中
建立的Handler 對象,就可以通過該對象向父線程的訊息佇列發送訊息了
。由於Android要求在UI線程中更新介面,因此,可以通過該方法在其它線程中更新介面。

Handler類包含如下方法用於發送、處理訊息:

? void handlerMessage(Message msg):處理訊息的方法,該方法通常用於被重寫。
   ? final boolean hasMessage(int what):檢查訊息佇列中是否包含what屬性為指定值的訊息。
? sendEmptyMessage(int what):發送空訊息
? final boolean sendMessage(Message msg):立即發送訊息,注意這塊傳回值,如果message成功的被放到message queue裡面則返回true,反之,返回false;(個人建議:對於這類問題不必主觀去記它,當實際使用時,直接查看源碼即可,源碼中有詳細的注釋)

Handler的作用:
(1)在一個線程中發送訊息。
(2)在另一個線程中擷取、處理訊息。
Handler處理的基本原理:

為了讓主線程能及時處理子線程發送的訊息,顯然只能通過回調的方法來實現----開發人員只要重寫Handler類中的方法,當新啟動的線程發送訊息時,訊息會發送至與之關聯的MessageQueue,而Handler會不斷的從MessageQuere中擷取並處理訊息-----這將導致Handler類中處理訊息的方法被回調。
線上程中使用Handler的基本步驟如下:
在被調用線程中完成以下內容:
(1)調用 Looper的prepare()方法為當前線程建立Looper對象,建立Looper對象時,它的構造器會建立與之配套的MessageQueue。
(2)有了Looper之後,建立Handler子類的執行個體,重寫HandlerMessage()方法,該方法負責處理來自其它線程的訊息。
(3)調用Looper的loop()方法啟動Looper。

註:若被調用線程是主線程類,由於系統自動為主線程建立了Looper的執行個體,因此第一、三步驟可省略,而只需要做第2步即可。
在調用線程中完成:
(1)建立message,並填充內容。
(2)使用被調用類建立的Handler執行個體,調用sendMessage(Message msg)方法。

Handler 與線程的關係
Handler 一般運行於主線程內,也可以運行在子線程中,但是一定要建立Looper對象。主線程中Android已經為之建立了Looper對象

 

使用Handler的兩種常見情況:
1、只能在主UI中修改UI。但實際上,有部分UI需要在子線程中控制其修改邏輯,因此子線程需要通過handler通知主線程修改UI。這在遊戲開發中尤其常見,比如需要讓新啟動的線程周期性的改變UI。、

子線程通知主UI線程修改UI組件的例子,新線程周期性的修改ImageView所顯示的圖片:

這個例子是Handler在主線程中擷取,處理訊息,在子線程中發送訊息

 

public class HandlerTest extends Activity{// 定義周期性顯示的圖片的IDint[] imageIds = new int[]{R.drawable.java,R.drawable.ee,R.drawable.ajax,R.drawable.xml,R.drawable.classic};int currentImageId = 0;@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);final ImageView show = (ImageView) findViewById(R.id.show);final Handler myHandler = new Handler()//在主線程中,擷取,處理訊息,更新UI組件,可以修改UI組件{@Overridepublic void handleMessage(Message msg){// 如果該訊息是本程式所發送的if (msg.what == 0x1233){// 動態地修改所顯示的圖片show.setImageResource(imageIds[currentImageId++% imageIds.length]);}}};// 定義一個計時器,讓該計時器周期性地執行指定任務。子線程通知主線程修改UI組件,實現處理序間通訊new Timer().schedule(new TimerTask(){@Overridepublic void run(){// 發送空訊息myHandler.sendEmptyMessage(0x1233);線上程中發送訊息}}, 0, 1200);}}

2、為避免ANR, 應該在子線程中執行耗時較長的操作,而此操作完成後,有可能需要通知主線程修改UI

 

在子線程中執行耗時任務後,通知主線程修改UI組件的例子:使用新進程計算質數,並用Toast顯示

這個例子是在主線程中發送訊息,在子線程中擷取,處理訊息

 

public class CalPrime extends Activity{static final String UPPER_NUM = "upper";EditText etNum;CalThread calThread;// 定義一個線程類class CalThread extends Thread{public Handler mHandler;public void run(){Looper.prepare();//建立Looper對象,每個線程使用Handler時都要有一個Looper對象mHandler = new Handler()//在子線程中用handler擷取,處理訊息{// 定義處理訊息的方法@Overridepublic void handleMessage(Message msg){if(msg.what == 0x123){int upper = msg.getData().getInt(UPPER_NUM);List<integer> nums = new ArrayList<integer>();// 計算從2開始、到upper的所有質數outer:for (int i = 2 ; i <= upper ; i++){// 用i處於從2開始、到i的平方根的所有數for (int j = 2 ; j <= Math.sqrt(i) ; j++){// 如果可以整除,表明這個數不是質數if(i != 2 && i % j == 0){continue outer;}}nums.add(i);}// 使用Toast顯示統計出來的所有質數Toast.makeText(CalPrime.this , nums.toString(), Toast.LENGTH_LONG).show();}}};Looper.loop();//啟動Looper}}@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);etNum = (EditText)findViewById(R.id.etNum);calThread = new CalThread();// 啟動新線程calThread.start();}// 為按鈕的點擊事件提供事件處理函數public void cal(View source){// 建立訊息Message msg = new Message();msg.what = 0x123;Bundle bundle = new Bundle();bundle.putInt(UPPER_NUM ,Integer.parseInt(etNum.getText().toString()));msg.setData(bundle);// 在主線程中向新線程中的Handler發送訊息calThread.mHandler.sendMessage(msg);//在主線程中發送訊息}}</integer></integer>

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.