編輯:關於android開發
為什麼要用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 { // 定義周期性顯示的圖片的ID int[] imageIds = new int[] { R.drawable.java, R.drawable.ee, R.drawable.ajax, R.drawable.xml, R.drawable.classic }; int currentImageId = 0; @Override public 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組件 { @Override public void handleMessage(Message msg) { // 如果該消息是本程序所發送的 if (msg.what == 0x1233) { // 動態地修改所顯示的圖片 show.setImageResource(imageIds[currentImageId++ % imageIds.length]); } } }; // 定義一個計時器,讓該計時器周期性地執行指定任務。子線程通知主線程修改UI組件,實現進程間通信 new Timer().schedule(new TimerTask() { @Override public void run() { // 發送空消息 myHandler.sendEmptyMessage(0x1233);在線程中發送消息 } }, 0, 1200); } }
在子線程中執行耗時任務後,通知主線程修改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獲取,處理消息 { // 定義處理消息的方法 @Override public 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 } } @Override public 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>
Android重構與設計之路,從整理提示對話框彈窗開始,android彈窗 封裝一個獨立彈窗Module,這裡的彈窗包括普通的Dialog方式彈框和WindowMana
解析網絡json數據,模擬美團界面顯示。,json 1 <?xml version=1.0 encoding=UTF-8?> 2 <RelativeL
Android WebView和JavaScript交互,androidwebview JavaScript在現在的網頁設計中用得很多,Android 的WebView
Pulltorefresh使用中碰到的問題,pulltorefresh碰到第一 在使用XScrollView布局是,無法在該布局.xml文件,放置內容布局控件,假如放置了