在Android中表示一種消息處理機制或者叫消息處理方法,用來循環處理應用程序主線程各類消息,好比UI的更新,按鍵、觸摸消息事件等。android
Android應用程序啓動時,系統會建立一個主線程,負責與UI組件(widget、view)進行交互,好比控制UI界面界面顯示、更新等;分發事件給UI界面處理,好比按鍵事件、觸摸事件、屏幕繪圖事件等,所以,Android主線程也稱爲UI線程。
由此可知,UI線程只能處理一些簡單的、短暫的操做,若是要執行繁重的任務或者耗時很長的操做,好比訪問網絡、數據庫、下載等,這種單線程模型會致使線程運行性能大大下降,甚至阻塞UI線程,若是被阻塞超過5秒,系統會提示應用程序無相應對話框,縮寫爲ANR,致使退出整個應用程序或者短暫殺死應用程序。數據庫
除此以外,單線程模型的UI主線程也是不安全的,會形成不可肯定的結果。線程不安全簡單理解爲:多線程訪問資源時,有可能出現多個線程前後更改數據形成數據不一致。好比,A工做線程(也稱爲子線程)訪問某個公共UI資源,B工做線程在某個時候也訪問了該公共資源,當B線程正訪問時,公共資源的屬性已經被A改變了,這樣B獲得的結果不是所須要的的,形成了數據不一致的混亂狀況。
線程安全簡單理解爲:當一個線程訪問功能資源時,對該資源進程了保護,好比加了鎖機制,當前線程在沒有訪問結束釋放鎖以前,其餘線程只能等待直到釋放鎖才能訪問,這樣的線程就是安全的。安全
基於以上緣由,Android的單線程模型必須遵照兩個規則:
1. 不要阻塞UI線程;
2. 不要在UI線程以外訪問UI組件,即不能在子線程訪問UI組件,只能在UI線程訪問。網絡
所以,Android系統將大部分耗時、繁重任務交給子線程完成,不會在主線程中完成,解決了第一個難題;同時,Android只容許主線程更新UI界面,子線程處理後的結果沒法和主線程交互,即沒法直接訪問主線程,這就要用到Handler機制來解決此問題。基於Handler機制,在子線程先得到Handler對象,該對象將數據發送到主線程消息隊列,主線程經過Loop循環獲取消息交給Handler處理。多線程
下面兩個案例都實現一個定時器,每隔一秒顯示數字0-9app
案例1:sendMenssage方法更新UI界面ide
1 package com.example.testhandler; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.os.Handler; 6 import android.os.Message; 7 import android.view.View; 8 import android.view.View.OnClickListener; 9 import android.widget.Button; 10 import android.widget.TextView; 11 12 public class TestHandlerActivity extends Activity { 13 14 protected static final String TAG = "TestHandlerActivity"; 15 private Button sendButton; 16 private TextView displayText; 17 18 Handler mHandler = new Handler() { 19 20 @Override 21 public void handleMessage(Message msg) { 22 // TODO Auto-generated method stub 23 if (msg.what == 99) { 24 int i = msg.getData().getInt("displayKey"); 25 displayText.setText(i + ""); 26 } 27 super.handleMessage(msg); 28 } 29 30 }; 31 private Button exitButton; 32 33 @Override 34 protected void onCreate(Bundle savedInstanceState) { 35 super.onCreate(savedInstanceState); 36 setContentView(R.layout.activity_main); 37 initViews(); 38 } 39 40 private void initViews() { 41 42 displayText = (TextView) findViewById(R.id.display_text); 43 sendButton = (Button) findViewById(R.id.send_button); 44 sendButton.setOnClickListener(buttonOnClickListener); 45 exitButton = (Button) findViewById(R.id.exit_button); 46 exitButton.setOnClickListener(buttonOnClickListener); 47 } 48 49 OnClickListener buttonOnClickListener = new OnClickListener() { 50 51 @Override 52 public void onClick(View v) { 53 // TODO Auto-generated method stub 54 if (v.getId() == R.id.send_button) { 55 new Thread(new WorkRunnable()).start(); 56 } else if (v.getId() == R.id.exit_button) { 57 finish(); 58 } 59 } 60 61 }; 62 63 class WorkRunnable implements Runnable { 64 @Override 65 public void run() { 66 // TODO Auto-generated method stub 67 int i = 0; 68 while (i < 10) { 69 Message msg = mHandler.obtainMessage(99); 70 Bundle bundle = new Bundle(); 71 bundle.putInt("displayKey", i); 72 msg.setData(bundle); 73 mHandler.sendMessage(msg); 74 try { 75 Thread.sleep(1000); 76 } catch (InterruptedException e) { 77 // TODO Auto-generated catch block 78 e.printStackTrace(); 79 } 80 i++; 81 } 82 } 83 } 84 85 @Override 86 protected void onDestroy() { 87 // TODO Auto-generated method stub 88 if (mHandler != null) { 89 if (mHandler.hasMessages(99)) { 90 mHandler.removeMessages(99); 91 } 92 mHandler = null; 93 } 94 super.onDestroy(); 95 } 96 }
WorkRunnable的run方法中進行了耗時操做,要把結果反饋給UI,須要Handler發送消息給UI線程,在Handler的handleMessage對消息進行處理oop
案例2: postDelayed更新UIpost
1 package com.example.postdelaydemo; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.os.Handler; 6 import android.util.Log; 7 import android.view.View; 8 import android.view.View.OnClickListener; 9 import android.widget.Button; 10 import android.widget.TextView; 11 12 public class PostDelayActivity extends Activity { 13 protected static final String TAG = "PostDelayActivity"; 14 private Button sendButton; 15 private TextView displayText; 16 private Button exitButton; 17 Handler mHandler = new Handler(); 18 19 @Override 20 protected void onCreate(Bundle savedInstanceState) { 21 super.onCreate(savedInstanceState); 22 setContentView(R.layout.activity_main); 23 initViews(); 24 } 25 26 private void initViews() { 27 displayText = (TextView) findViewById(R.id.display_text); 28 sendButton = (Button) findViewById(R.id.send_button); 29 sendButton.setOnClickListener(buttonOnClickListener); 30 exitButton = (Button) findViewById(R.id.exit_button); 31 exitButton.setOnClickListener(buttonOnClickListener); 32 } 33 34 OnClickListener buttonOnClickListener = new OnClickListener() { 35 @Override 36 public void onClick(View v) { 37 // TODO Auto-generated method stub 38 if (v.getId() == R.id.send_button) { 39 mHandler.postDelayed(new PostDelayRunnable(), 1000); 40 } else if (v.getId() == R.id.exit_button) { 41 finish(); 42 } 43 } 44 }; 45 46 class PostDelayRunnable implements Runnable { 47 int i = 0; 48 49 @Override 50 public void run() { 51 // TODO Auto-generated method stub 52 if (i >= 10) { 53 mHandler.removeCallbacks(this); 54 } else { 55 displayText.setText(getResources().getString( 56 R.string.display_label) 57 + i); 58 mHandler.postDelayed(this, 1000); 59 } 60 i++; 61 } 62 } 63 64 @Override 65 protected void onDestroy() { 66 // TODO Auto-generated method stub 67 if (mHandler != null) { 68 mHandler = null; 69 } 70 super.onDestroy(); 71 } 72 }
postDelayed方法把runnable對象做爲消息放到隊列中等待執行,run方法中就是具體執行過程。性能
msg.target是Handler的一個對象引用,handler對象發送消息暫存到消息隊列,Looper取出消息分發給相應的handler處理。
(1) 都是把消息放到消息隊列等待執行,前者放的是一個runnable對象,後者是一個message對象;
(2) 前者最終仍是會轉化成sendMessage,只不過最終的處理方式不同,前者會執行runnable的run方法;後者能夠被安排到線程中執行。
(3) 二者本質沒有區別,均可以更新UI,區別在因而否易於維護等。
HandlerThread繼承了Thread,是一個包含有looper的線程類。正常狀況下,除了主線程,工做線程是沒有looper的,可是爲了像主線程那樣也能循環處理消息,Android也自定義一個包含looper的工做線程——HandlerThread類。
啊啊啊啊啊啊啊啊西吧太菜了,源碼看不懂