Android中的消息机制:Handler消息传递机制
參考《瘋狂android講義》第2版3.5 P214
一、背景
出于性能優化考慮,Android的UI操作并不是線程安全的,這意味著如果有多個線程并發操作UI組件,可能導致線程安全問題。為了解決這個問題,Android制定了一條簡單的原則:只允許UI線程(亦即主線程)修改Activity中的UI組件。
當一個程序第一次啟動時,Android會同時啟動一條主線程,主線程主要負責處理與UI相關的事件,如用戶的按鍵事件、用戶接觸屏幕的事件、屏幕繪圖事件,并把相關的事件分發到相應的組件進行處理,所以主線程通常又叫做UI線程。
二、使用Handler的兩種常見原因
1、只能在主UI中修改UI。但實際上,有部分UI需要在子線程中控制其修改邏輯,因此子線程需要通過handler通知主線程修改UI。這在游戲開發中尤其常見,比如需要讓新啟動的線程周期性的改變UI。
2、為避免ANR,應該在子線程中執行耗時較長的操作,而此操作完成后,有可能需要通知主線程修改UI。
三、基本原理及步驟
1、Handler的作用主要有2個:
(1)發送消息。
(2)獲取、處理消息。
2、基本原理:為了讓主線程能及時處理子線程發送的消息,顯然只能通過回調的方法來實現----開發者只要重寫Handler類中的方法,當新啟動的線程發送消息時,消息會發送至與之關聯的MessageQueue,而Handler會不斷的從MessageQuere中獲取并處理消息-----這將導致Handler類中處理消息的方法被回調。
3、在線程中使用Handler的基本步驟如下:
在被調用線程中完成以下內容:
(1)調用 Looper的prepare()方法為當前線程創建Looper對象,創建Looper對象時,它的構造器會創建與之配套的MessageQueue。
(2)有了Looper之后,創建Handler子類的實例,重寫HandlerMessage()方法,該方法負責處理來自其它線程的消息。
(3)調用Looper的loop()方法啟動Looper。
注:若被調用線程是主線程類,由于系統自動為主線程創建了Looper的實例,因此第一、三步驟可省略,而只需要做第2步即可。
在調用線程中完成:
(1)創建nessage,并填充內容。
(2)使用被調用類創建的Handler實例,調用sendMessage(Message msg)方法。
四、實例
1、主線程接收數據,并將之發送至子線程中完成一些耗時操作
package com.ljh.handlerdemo1;import java.util.ArrayList; import java.util.List;import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.app.Activity; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast;public class MainActivity extends Activity {private final String UPPER_NUMBER = "upper";private CalThread calThread;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);calThread = new CalThread();Thread t = new Thread(calThread);t.start();}public void cal(View v) {EditText et_digit = (EditText) findViewById(R.id.et_digit);Message msg = new Message();msg.what = 0x1233;Bundle bundle = new Bundle();bundle.putInt(UPPER_NUMBER,Integer.parseInt(et_digit.getText().toString()));msg.setData(bundle);calThread.handler.sendMessage(msg);}class CalThread implements Runnable {public Handler handler;@Overridepublic void run() {//1、調用 Looper的prepare()方法為當前線程創建Looper對象,創建Looper對象時,它的構造器會創建與之配套的MessageQueueLooper.prepare();handler = new Handler() {// 2、有了Looper之后,創建Handler子類的實例,重寫HandlerMessage()方法,該方法負責處理來自其它線程的消息。@Overridepublic void handleMessage(Message msg){if(msg.what == 0x1233){int upper = msg.getData().getInt(UPPER_NUMBER);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(MainActivity.this , nums.toString(), Toast.LENGTH_LONG).show();}}};//調用Looper的loop()方法啟動Looper。Looper.loop();} } }<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context=".MainActivity" ><EditTextandroid:id="@+id/et_digit"android:layout_width="wrap_content"android:layout_height="wrap_content"android:hint="@string/limit" /><Button android:id="@+id/bt_prime"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/cal"android:onClick="cal"android:layout_below="@id/et_digit" /></RelativeLayout>
參考歸檔代碼HandlerDemo1
總結
以上是生活随笔為你收集整理的Android中的消息机制:Handler消息传递机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于LayoutParams
- 下一篇: Android adb.exe程序启动不