1. 程式人生 > >Android--多線程之Handler

Android--多線程之Handler

start ref star andro 關於 listen 改變 toolbar 對象

前言

  Android的消息傳遞機制是另外一種形式的“事件處理”,這種機制主要是為了解決Android應用中多線程的問題,在Android中不允許Activity新啟動的線程訪問該Activity裏的UI組件,這樣會導致新啟動的線程無法改變UI組件的屬性值。但實際開發中,很多地方需要在工作線程中改變UI組件的屬性值,比如下載網絡圖片、動畫等等。本篇博客主要介紹Handler是如何發送與處理線程上傳遞來的消息,並講解Message的幾種傳遞數據的方式,最後均會以小Demo來演示。

Handler

  Handler,它直接繼承自Object,一個Handler允許發送和處理Message或者Runnable對象,並且會關聯到主線程的MessageQueue中。每個Handler具有一個單獨的線程,並且關聯到一個消息隊列的線程,就是說一個Handler有一個固有的消息隊列。當實例化一個Handler的時候,它就承載在一個線程和消息隊列的線程,這個Handler可以把Message或Runnable壓入到消息隊列,並且從消息隊列中取出Message或Runnable,進而操作它們。

  Handler主要有兩個作用:

  • 在工作線程中發送消息。
  • 在UI線程中獲取、處理消息。

  上面介紹到Handler可以把一個Message對象或者Runnable對象壓入到消息隊列中,進而在UI線程中獲取Message或者執行Runnable對象,所以Handler把壓入消息隊列有兩大體系,Post和sendMessage:

  • Post:Post允許把一個Runnable對象入隊到消息隊列中。它的方法有:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。
  • sendMessage:sendMessage允許把一個包含消息數據的Message對象壓入到消息隊列中。它的方法有:sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message,long)、sendMessageDelayed(Message,long)。

  從上面的各種方法可以看出,不管是post還是sendMessage都具有多種方法,它們可以設定Runnable對象和Message對象被入隊到消息隊列中,是立即執行還是延遲執行。

  

Post

  對於Handler的Post方式來說,它會傳遞一個Runnable對象到消息隊列中,在這個Runnable對象中,重寫run()方法。一般在這個run()方法中寫入需要在UI線程上的操作。

  在Handler中,關於Post方式的方法有:

  • boolean post(Runnable r):把一個Runnable入隊到消息隊列中,UI線程從消息隊列中取出這個對象後,立即執行。
  • boolean postAtTime(Runnable r,long uptimeMillis):把一個Runnable入隊到消息隊列中,UI線程從消息隊列中取出這個對象後,在特定的時間執行。
  • boolean postDelayed(Runnable r,long delayMillis):把一個Runnable入隊到消息隊列中,UI線程從消息隊列中取出這個對象後,延遲delayMills秒執行
  • void removeCallbacks(Runnable r):從消息隊列中移除一個Runnable對象。

  下面通過一個Demo,講解如何通過Handler的post方式在新啟動的線程中修改UI組件的屬性:

技術分享
 1 package com.bgxt.datatimepickerdemo;
 2 
 3 import android.app.Activity;
 4 import android.os.Bundle;
 5 import android.os.Handler;
 6 import android.view.View;
 7 import android.widget.Button;
 8 import android.widget.TextView;
 9 
10 public class HandlerPostActivity1 extends Activity {
11     private Button btnMes1,btnMes2;
12     private TextView tvMessage;
13     // 聲明一個Handler對象
14     private static Handler handler=new Handler();
15     
16     @Override
17     protected void onCreate(Bundle savedInstanceState) {
18         super.onCreate(savedInstanceState);
19         setContentView(R.layout.message_activity);        
20         
21         btnMes1=(Button)findViewById(R.id.btnMes1);
22         btnMes2=(Button)findViewById(R.id.btnMes2);
23         tvMessage=(TextView)findViewById(R.id.tvMessage);
24         btnMes1.setOnClickListener(new View.OnClickListener() {
25             
26             @Override
27             public void onClick(View v) {
28                 // 新啟動一個子線程
29                 new Thread(new Runnable() {                    
30                     @Override
31                     public void run() {
32                         // tvMessage.setText("...");
33                         // 以上操作會報錯,無法再子線程中訪問UI組件,UI組件的屬性必須在UI線程中訪問
34                         // 使用post方式修改UI組件tvMessage的Text屬性
35                         handler.post(new Runnable() {                    
36                             @Override
37                             public void run() {
38                                 tvMessage.setText("使用Handler.post在工作線程中發送一段執行到消息隊列中,在主線程中執行。");                        
39                             }
40                         });                                
41                     }
42                 }).start();
43             }
44         });
45         
46         btnMes2.setOnClickListener(new View.OnClickListener() {
47             
48             @Override
49             public void onClick(View v) {
50                 new Thread(new Runnable() {                    
51                     @Override
52                     public void run() {
53                         // 使用postDelayed方式修改UI組件tvMessage的Text屬性值
54                         // 並且延遲3S執行
55                         handler.postDelayed(new Runnable() {
56                             
57                             @Override
58                             public void run() {
59                                 tvMessage.setText("使用Handler.postDelayed在工作線程中發送一段執行到消息隊列中,在主線程中延遲3S執行。");    
60                                 
61                             }
62                         }, 3000);                        
63                     }
64                 }).start();
65                 
66             }
67         });
68     }
69 }
技術分享

Android--多線程之Handler