Android線程與異步消息處理機制


在程序開發時,對於一些比較耗時的操作,我們通常會為其開辟一個單獨的線程來執行,這樣可以盡可能的減少用戶等待的時間。在Android中,默認情況下,所有的操作都是在主線程中進行的,這個主線程負責管理與UI相關的事件,而在我們自己創建的子線程中,又不能對UI組件進行操作,因此,Android提供了消息處理傳遞機制來解決這一個問題。

1、多線程的常見操作

  1、創建線程。

  在Android中,提供了兩種創建線程的方法。(一種是通過Thread類的構造方法創建線程對象,並重寫run()方法實現,另一種是通過實現Runnable接口來實現。)

  第一種方法:

  Thread thread=new Thread(new Runnable(){

    @Override

    public void run(){

    //要執行的操作

    }

  });

  thread.start();

  第二種方法:

  public class MainActivity extends Activity implement Runnable{

  @Override

  public void run(){

    //要執行的操作

    }

  }

  2、開啟線程

  3、線程休眠

  4、中斷線程

下面用一個實例來實現上述的這些操作

首先是布局文件:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="fill_parent"
 4     android:layout_height="fill_parent" >
 5 
 6     <Button
 7         android:id="@+id/button1"
 8         android:layout_width="wrap_content"
 9         android:layout_height="wrap_content"
10         android:text="@string/start" />
11 
12     <Button
13         android:id="@+id/button2"
14         android:layout_width="wrap_content"
15         android:layout_height="wrap_content"
16         android:text="@string/stop" />    
17 
18 </LinearLayout>
View Code

然后修改默認的Activity:

 1 public class MainActivity extends Activity implements Runnable {
 2     private Thread thread;    //聲明線程對象
 3     int i;    //循環變量
 4     
 5     @Override
 6     public void onCreate(Bundle savedInstanceState) {
 7         super.onCreate(savedInstanceState);
 8         setContentView(R.layout.main);
 9         Button startButton=(Button)findViewById(R.id.button1);    //獲取“開始”按鈕
10         startButton.setOnClickListener(new OnClickListener() {
11             
12             @Override
13             public void onClick(View v) {
14                 i=0;
15                 thread=new Thread(MainActivity.this);    //創建一個線程
16                 thread.start();    //開啟線程
17                 
18             }
19         });
20         Button stopButton=(Button)findViewById(R.id.button2);    //獲取“停止”按鈕
21         stopButton.setOnClickListener(new OnClickListener() {
22             
23             @Override
24             public void onClick(View v) {
25                 if(thread!=null){
26                     thread.interrupt();    //中斷線程
27                     thread=null;
28                 }
29                 Log.i("提示:","中斷線程");
30                 
31             }
32         });
33     }
34 
35     @Override
36     protected void onDestroy() {
37 
38         if(thread!=null){
39             thread.interrupt();    //中斷線程
40             thread=null;
41         }
42         super.onDestroy();
43     }
44     @Override
45     public void run() {
46         while(!Thread.currentThread().isInterrupted()){
47             i++;
48             Log.i("循環變量:",String.valueOf(i));
49         }
50         
51     }
52 }
View Code

接下來運行即可。

 

上面只是線程的簡單操作。這里推薦一篇寫得比較詳細的文章:《java中的多線程

 

2、異步消息處理機制

在上面我們已經介紹了線程相關的知識點,不過此時還沒有在新創建的子線程中對UI界面上的內容進行操作,如果用上面的方法進行操作,將會拋出異常。為此,Android中引入了異步消息處理機制,來實現在新創建的線程中操作UI界面。

 

首先,我們來了解一些概念。

什么是異步?

簡單來說,就是A和B兩個人可以同時做兩種事,也就是分別做自己的事。(而不是A做完事后B才開始做事)

什么是消息處理機制?

就應用程序而言,Android系統中JAVA的應用程序和其他系統上相同,都是靠消息驅動來工作的,他們大致的工作原理如下:

1、有一個消息隊列,可以往這個消息隊列中投遞消息。

2、有一個消息循環,不斷從消息隊列中取出消息,然后處理。

在Android中,一個線程對應一個Looper對象,而一個Looper對象又對應一個MessageQueue(用於存放message)。

接下來,我們來了解幾個類:循環者Looper類,消息處理類Handler,消息類Message。

Looper對象用來為一個線程開啟一個消息循環,用來操作MessgeQueue。默認情況下,Android中新創建的線程是沒有開啟消息循環的。(主線程除外)

 

消息處理類(Handler)允許發送和處理Message和Rannable對象到其所在線程的MessageQueue中。(它主要有兩個作用:1、將Message或Runnable應用post()方法或sendMessage()方法發送到MessageQueue中,在發送時可以指定延時時間、發送時間或者要攜帶的bundle數據。當MessageQueue循環到該Message時,調用相應的Handler對象的handlerMessage()方法對其進行處理。2、在子線程中與主線程進行通信,也就是在工作線程中與UI線程進行通信。)另外,在一個線程中只能有一個Looper和MessageQueue,但是可以有多個Handler,而且這些Handler可以共享一個Looper和MessageQueue。

 

消息類(Message)被存放在MessageQueue中,一個MessageQueue中可以包含多個Message對象。每個Message對象可以通過Messhe.obtain()方法或者Handler.obtainMessage()方法獲得。

關系如下圖:

(圖片來源於網絡)

下面我們做一個簡單的實例。(從子線程獲取的數據更新到UI)

布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="點擊改變下方界面"/>
    <TextView 
        android:id="@+id/tv"
        android:layout_marginTop="50dp"
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="數據沒改變前"/>

</LinearLayout>

java代碼如下:

public class MainActivity extends Activity {
    
    private TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button btn=(Button) findViewById(R.id.btn);
        tv = (TextView) findViewById(R.id.tv);
        btn.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    
                    @Override
                    public void run() {
                        Message msg=new Message();
                        msg.obj="您已點擊按鈕,數據發生改變";//message的內容
                        msg.what=1;//指定message
                        handler.sendMessage(msg);//handler發送message
                        
                    }
                }).start();
                
            }
        });
    }
    
    private Handler handler=new Handler(){
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case 1://獲取到what屬性為1的message
                tv.setText((String)msg.obj);//將message的內容填充到TextView中
                break;

            default:
                break;
            }
        };
    };
    

}

 

運行程序,結果如下圖:

 

此外,關於異步消息處理機制。除了handler外,常用的還有AsyncTask。關於AsyncTask請看另一篇博文《Android AsyncTask 初探》。

 

在子線程中更改UI,更多內容請參考我的另一篇博文《Android 在子線程中更新UI》。

 

以上三個類關系密切並且方法較多,建議大家參考開發文檔詳細了解:

Looper:http://developer.android.com/intl/zh-cn/reference/android/os/Looper.html

Handler:http://developer.android.com/intl/zh-cn/reference/android/os/Handler.html

message:http://developer.android.com/intl/zh-cn/reference/android/os/Message.html

此外,還有對其三者進行源碼分析的一些相關的博客:

http://www.cnblogs.com/zhaoxiaowei/category/568256.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM