Android 非UI線程中是不能更新UI的,Handler是Android 提供的一套更新UI的機制,也是用來發送消息和處理消息的一套機制。java
之前剛接觸的Handler的時候,感受老是很困惑,對Handler原理也是隻知其一;不知其二,如今對Handler常見用法,知識點總結一下。app
先看一下谷歌Android官方文檔對Handler的描述:ide
Class Overview
A Handler allows you to send and process Message
and Runnable objects associated with a thread'sMessageQueue
. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue. 函數
它容許用戶發送、處理消息和與線程的消息隊列相關聯的 runnable 對象。每個 handler 實例都與一個單獨的線程相關聯。每次建立一個新的 hander 對象時,它都與建立該對象的線程或者該線程中的消息隊列綁定在一塊兒,這樣handler 就能夠發送消息和 runable 對象到消息隊列中,並在從消息隊列中取出的時候處理它們。oop
1. Handler的構造函數
- Handler() Default constructor associates this handler with the
Looper for the current thread.
|
- Handler(Handler.Callback callback) Constructor associates this handler with the
Looper for the current thread and takes a callback interface in which you can handle messages.
|
|
|
|
|
|
說明: Handler()是最經常使用的一種post
Handler(Handler.Callback callback)能夠截獲消息,this
Handler(Looper looper)指定了Looper對象,在實際開發中經常使用HandlerThread.getLooper()。spa
2. 關於Message
Handler若是使用sendMessage的方式把消息入隊到消息隊列中,須要傳遞一個Message對象,而在Handler中,須要重 寫handleMessage()方法,用於獲取工做線程傳遞過來的消息。.net
發送消息常見的方式以下,用法大同小異。線程
Message的參數:
- int what:定義的消息碼,通常用於設定消息的標誌。
- int arg1:簡單參數
- int arg2:簡單參數
- Object obj:傳遞一個任意的對象。
移除Message:
3. 關於Post
Post 會傳遞一個Runnable對象到消息隊列中
Post常見方法:
- post(Runnable r) Causes the Runnable r to be added to the message queue.
- postDelayed(Runnable r, long delayMillis) Causes the Runnable r to be added to the message queue, to be run after the specified amount of time elapses.
- postAtTime(Runnable r,Object token, long uptimeMillis) Causes the Runnable r to be added to the message queue, to be run at a specific time given byuptimeMillis.
從消息隊列中移除一個Runnable對象
removeCallbacks(Runnable r)Remove any pending posts of Runnable r that are in the message queue.
4. 關於MessageQueue
MessageQueue 是消息隊列,在MainThread建立的時候會建立一個Looper,在建立Looper的時候,會建立MessageQueue();
5. 關於Looper
Looper.loop()是一個死循環,用來循環查詢消息隊列,並把消息回傳給handler。
6. Demo說明
1.1 發送空消息和移除消息,這裏以sendEmptyMessageDelayed()爲例
[java] view plain copy
- public class Test1 extends Activity implements OnClickListener {
-
- private TextView tv;
- private Button btn;
- private int i = 0;
-
- Handler handler = new Handler() {
- public void handleMessage(Message msg) {
- tv.setText("Hello 改變了"+i++);
- handler.sendEmptyMessageDelayed(0, 1 * 1000); //延遲一秒發送
-
- };
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.test1);
- setView();
- test1();
-
- }
-
- private void setView() {
- tv = (TextView) this.findViewById(R.id.tv);
- btn = (Button) this.findViewById(R.id.btn);
- btn.setOnClickListener(this);
- }
-
- private void test1() {
-
- new Thread() {
- public void run() {
-
- handler.sendEmptyMessageDelayed(0, 1 * 1000); //延遲一秒發送
- };
- }.start();
- }
-
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
-
- case R.id.btn:
- handler.removeMessages(0);//移除消息
- break;
-
- default:
- break;
- }
-
- }
-
- }
效果圖,數字每隔一秒,自增1,點擊,數字會中止自增:
1.2 使用new Message(),並給Message賦值,使用handler.sendMessage(msg)發送
[java] view plain copy
- public class Test2 extends Activity implements OnClickListener {
-
- private TextView tv;
-
-
- Handler handler = new Handler() {
- public void handleMessage(Message msg) {
-
- tv.setText("msg.what=" + msg.what + ", msg.arg1=" + msg.arg1
- + ", msg.arg2=" + msg.arg2 + ", msg.obj=" + msg.obj);
-
- };
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.test2);
- setView();
- test();
-
- }
-
- private void setView() {
- tv = (TextView) this.findViewById(R.id.tv);
-
- }
-
- private void test() {
-
- new Thread() {
- public void run() {
-
- Message msg = new Message();
- UserBean userBean = new UserBean();
- userBean.setName("Jim");
- userBean.setPwd("123456");
- msg.what = 1;
- msg.arg1 = 2;
- msg.arg2 = 3;
- msg.obj = userBean;
- handler.sendMessage(msg);
- };
- }.start();
- }
-
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- //
- // case R.id.btn:
- // handler.removeMessages(0);//移除消息
- // break;
-
- default:
- break;
- }
-
- }
-
- }
實體類
[java] view plain copy
- public class UserBean {
-
- public String name;
-
- public String pwd;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getPwd() {
- return pwd;
- }
-
- public void setPwd(String pwd) {
- this.pwd = pwd;
- }
-
- @Override
- public String toString() {
- return "UserBean [name=" + name + ", pwd=" + pwd + "]";
- }
-
-
- }
效果圖以下,能夠看到消息成功傳遞和接收。
1.3 使用obtainMessage()獲取已綁定的消息,並給Message賦值,使用msg.sendToTarget()發送
[java] view plain copy
- public class Test3 extends Activity implements OnClickListener {
-
- private TextView tv;
-
- Handler handler = new Handler() {
- public void handleMessage(Message msg) {
-
- tv.setText("msg.what=" + msg.what + ", msg.arg1=" + msg.arg1
- + ", msg.arg2=" + msg.arg2 + ", msg.obj=" + msg.obj);
-
- };
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.test3);
- setView();
- test();
-
- }
-
- private void setView() {
- tv = (TextView) this.findViewById(R.id.tv);
-
- }
-
- private void test() {
-
- new Thread() {
- public void run() {
-
- // Message msg = new Message();
- Message msg = handler.obtainMessage();
- UserBean userBean = new UserBean();
- userBean.setName("Jim");
- userBean.setPwd("123456");
- msg.what = 1;
- msg.arg1 = 2;
- msg.arg2 = 3;
- msg.obj = userBean;
- // handler.sendMessage(msg);n
- msg.sendToTarget();
- };
- }.start();
- }
-
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- //
- // case R.id.btn:
- // handler.removeMessages(0);//移除消息
- // break;
-
- default:
- break;
- }
-
- }
-
- }
效果和上圖同樣
2 Post 會傳遞一個Runnable對象到消息隊列中
2.1 使用Post方式傳遞一個Runnable對象到消息隊列和移除
[java] view plain copy
- public class Test4 extends Activity implements OnClickListener {
-
- private TextView tv;
- private Button btn;
- private int i = 0;
-
- Handler handlerPost = new Handler();
- // 線程中運行該接口的run函數
- Runnable update_thread = new Runnable() {
- public void run() {
- // System.out.println("activity_id---->"+Thread.currentThread().getId());
- // System.out.println("activity_name---->"+Thread.currentThread().getName());
- tv.setText("handlerPost:"+i++);
- // 延時1s後又將線程加入到線程隊列中
- handlerPost.postDelayed(update_thread, 1000);
-
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.test4);
- setView();
- System.out
- .println("activity_id0---->" + Thread.currentThread().getId());
- System.out.println("activity_name0---->"
- + Thread.currentThread().getName());
- test();
-
- }
-
- private void setView() {
- tv = (TextView) this.findViewById(R.id.tv);
- btn = (Button) this.findViewById(R.id.btn);
- btn.setOnClickListener(this);
- }
-
- private void test() {
-
- // 將線程接口馬上送到線程隊列中
- handlerPost.post(update_thread); // handler使用了post方法啓動了runnbale,其實啓動的線程和activity主線程是同一個線程
- // Thread t = new Thread(update_thread);
- // //這樣綁定的線程與它所在的activity線程就不是同一個線程了
- // t.start();
- }
-
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
-
- case R.id.btn:
- handlerPost.removeCallbacks(update_thread);// 將接口從線程隊列中移除
- break;
-
- default:
- break;
- }
-
- }
-
- }
說明:
handler使用了post方法啓動了runnbale,其實啓動的線程和activity主線程是同一個線程
若是使用
Thread t = new Thread(update_thread);
t.start();
這樣綁定的線程與它所在的activity線程就不是同一個線程了
效果圖:
3 Handler(Looper looper)的使用,使用handThread.getLooper()做爲參數。
注意:若是 thread.getLooper()中的thread爲子線程,則會報空指針異常,由於當主線程執行Handler(Looper looper)
的時候,子線程的Looper對象還未創立。
[java] view plain copy
- public class Test5 extends Activity implements OnClickListener {
-
- private TextView tv;
- HandlerThread handThread;
- Handler handler;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.test5);
- setView();
- test();
-
- }
-
- private void setView() {
- tv = (TextView) this.findViewById(R.id.tv);
-
- }
-
- private void test() {
-
- // HandlerThread
- handThread = new HandlerThread("handThread");
- handThread.start();
- handler = new Handler(handThread.getLooper()) {
- public void handleMessage(Message msg) {
-
- tv.setText("HandlerThread");
-
- };
- };
- handler.sendEmptyMessage(0);
- }
-
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- //
- // case R.id.btn:
- // handler.removeMessages(0);//移除消息
- // break;
-
- default:
- break;
- }
-
- }
-
- }
效果圖:
Demo下載地址:http://download.csdn.net/detail/yalinfendou/8477587