深入理解Android訊息處理系統——Looper、Handler、Thread

來源:互聯網
上載者:User

    (自) Activity,Service屬於主線程,在主線程中才能更新UI,如toast等。其他線程中不能直接使用,這時可以使用Handler來處理,Handler可以在Activity和Service中。

  關於在非UI線程中進行UI操作會出現問題: Can't create handler inside thread that has not called Looper.prepare()

這時有兩種方式來解決:

(一)在該非UI線程中建立訊息佇列(因為建立的背景工作執行緒預設是沒有訊息迴圈和訊息佇列的),Looper.prepare();.....;Looper.loop(); 

 newThread() { 

public void run() {

 Looper.prepare(); //建立訊息佇列

 todo(); 

 Looper.loop();//進入訊息迴圈

}}.start();

(二)運用Handler機制:

package com.simon;

import android.app.Activity;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.os.Handler;

public class MyHandler extends Activity {
    static final String TAG = "Handler";
    Handler h = new Handler(){
        public void handleMessage (Message msg)
        {
            switch(msg.what)
            {
            case HANDLER_TEST:
                Log.d(TAG, "The handler thread id = " + Thread.currentThread().getId() + "\n");
                break;
            }
        }
    };

    static final int HANDLER_TEST = 1;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "The main thread id = " + Thread.currentThread().getId() + "\n");

        new myThread().start();
        setContentView(R.layout.main);
    }

    class myThread extends Thread
    {
        public void run()
        {
            Message msg = new Message();
            msg.what = HANDLER_TEST;
            h.sendMessage(msg);
            Log.d(TAG, "The worker thread id = " + Thread.currentThread().getId() + "\n");
        }
    }
}

***********************************************分割線************************************************

      熟悉Windows編程的朋友可能知道Windows程式是訊息驅動的,並且有全域的訊息迴圈系統。而Android應用程式也是訊息驅動的,按道
理來說也應該提供訊息迴圈機制。實際上Google參考了Windows的訊息迴圈機制,也在Android系統中實現了訊息迴圈機制。Android通過
Looper、Handler來實現訊息迴圈機制,Android訊息迴圈是針對線程的(每個線程都可以有自己的訊息佇列和訊息迴圈)。本文深入介紹一下
Android訊息處理系統原理。

    Android系統中Looper負責管理線程的訊息佇列和訊息迴圈,具體實現請參考Looper的源碼。
可以通過Loop.myLooper()得到當前線程的Looper對象,通過Loop.getMainLooper()可以獲得當前進程的主線程的
Looper對象。

   
前面提到Android系統的訊息佇列和訊息迴圈都是針對具體線程的,一個線程可以存在(當然也可以不存在)一個訊息佇列和一個訊息迴圈
(Looper),特定線程的訊息只能分發給本線程,不能進行跨線程,跨進程通訊。但是建立的背景工作執行緒預設是沒有訊息迴圈和訊息佇列的,如果想讓該線程具
有訊息佇列和訊息迴圈,需要線上程中首先調用Looper.prepare()來建立訊息佇列,然後調用Looper.loop()進入訊息迴圈。如下例
所示:

  class LooperThread extends Thread {
      public Handler mHandler;

      public void run() {
          Looper.prepare();

          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          Looper.loop();
      }
  }這樣你的線程就具有了訊息處理機制了,在Handler中進行訊息處理。

     Activity是一個UI線程,運行於主線程中,Android系統在啟動的時候會為Activity建立一個訊息佇列和訊息迴圈(Looper)。詳細實現請參考ActivityThread.java檔案。

     Handler的作用是把訊息加入特定的(Looper)訊息佇列中,並分發和處理該訊息佇列中的訊息。構造Handler的時候可以指定一個Looper對象,如果不指定則利用當前線程的Looper建立。詳細實現請參考Looper的源碼。

     Activity、Looper、Handler的關係如所示:

    
一個Activity中可以建立多個背景工作執行緒或者其他的組件,如果這些線程或者組件把他們的訊息放入Activity的主線程訊息佇列,那麼該訊息就會在
主線程中處理了。因為主線程一般負責介面的更新操作,並且Android系統中的weget不是安全執行緒的,所以這種方式可以很好的實現Android界
面更新。在Android系統中這種方式有著廣泛的運用。

    
那麼另外一個線程怎樣把訊息放入主線程的訊息佇列呢?答案是通過Handle對象,只要Handler對象以主線程的Looper建立,那麼調用
Handler的sendMessage等介面,將會把訊息放入隊列都將是放入主線程的訊息佇列。並且將會在Handler主線程中調用該handler
的handleMessage介面來處理訊息。

     這裡面涉及到線程同步問題,請先參考如下例子來理解Handler對象的執行緒模式:

1、首先建立MyHandler工程。

2、在MyHandler.java中加入如下的代碼:

package com.simon;

import android.app.Activity;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.os.Handler;

public class MyHandler extends Activity {
    static final String TAG = "Handler";
    Handler h = new Handler(){
        public void handleMessage (Message msg)
        {
            switch(msg.what)
            {
            case HANDLER_TEST:
                Log.d(TAG, "The handler thread id = " + Thread.currentThread().getId() + "\n");
                break;
            }
        }
    };

    static final int HANDLER_TEST = 1;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "The main thread id = " + Thread.currentThread().getId() + "\n");

        new myThread().start();
        setContentView(R.layout.main);
    }

    class myThread extends Thread
    {
        public void run()
        {
            Message msg = new Message();
            msg.what = HANDLER_TEST;
            h.sendMessage(msg);
            Log.d(TAG, "The worker thread id = " + Thread.currentThread().getId() + "\n");
        }
    }
}在這個例子中我們主要是列印,這種處理機制各個模組的所處的線程情況。如下是我的機器運行結果:

09-10 23:40:51.478: DEBUG/Handler(302): The main thread id = 1
09-10 23:40:51.569: DEBUG/Handler(302): The worker thread id = 8
09-10
23:40:52.128: DEBUG/Handler(302): The handler thread id =
1我們可以看出訊息處理是在主線程中處理的,在訊息處理函數中可以安全的調用主線程中的任何資源,包括重新整理介面。背景工作執行緒和主線程運行在不同的線程中,所
以必須要注意這兩個線程間的競爭關係。

    
上例中,你可能注意到在背景工作執行緒中訪問了主線程handler對象,並在調用handler的對象向訊息佇列加入了一個訊息。這個過程中會不會出現訊息隊
列資料不一致問題呢?答案是handler對象不會出問題,因為handler對象管理的Looper對象是安全執行緒的,不管是加入訊息到訊息佇列和從隊
列讀出訊息都是有同步對象保護的,具體請參考Looper.java檔案。上例中沒有修改handler對象,所以handler對象不可能會出現資料不
一致的問題。

     通過上面的分析,我們可以得出如下結論:

1、如果通過背景工作執行緒重新整理介面,推薦使用handler對象來實現。

2、注意背景工作執行緒和主線程之間的競爭關係。推薦handler對象在主線程中構造完成(並且啟動背景工作執行緒之後不要再修改之,否則會出現資料不一致),然後在背景工作執行緒中可以放心的調用發送訊息SendMessage等介面。

3、除了2所述的hanlder對象之外的任何主線程的成員變數如果在背景工作執行緒中調用,仔細考慮線程同步問題。如果有必要需要加入同步對象保護該變數。

4、handler對象的handleMessage介面將會在主線程中調用。在這個函數可以放心的調用主線程中任何變數和函數,進而完成更新UI的任務。

5、Android很多API也利用Handler這種線程特性,作為一種回呼函數的變種,來通知調用者。這樣Android架構就可以在其線程中將訊息發送到調用者的線程訊息佇列之中,不用擔心線程同步的問題。

     深入理解Android訊息處理機制對於應用程式開發非常重要,也可以讓你對線程同步有更加深刻的認識。以上是最近Simon學習Android訊息處理機制的一點兒總結,如有錯誤之處請不吝指教。

轉自:http://blog.csdn.net/dywe_ddm/archive/2010/10/10/5930948.aspx

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.