Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 的消息機制(Handler消息傳遞機制)

Android 的消息機制(Handler消息傳遞機制)

編輯:關於Android編程

出於性能優化考慮,android的UI操作並不是線程安全的,這意味著意味著如果有多個線程並發操作UI組件,可能導致線程安全問題,未解決此問題,

從開發的角度來說, Handler 是 Android 消息機制的上層接口, 這使得在開發過程中只需要和 Handler 交互即可。
Handler 的使用過程很簡單,通過它可以輕松地將一個任務切換到 Handler 所在的線程中去執行。很多人認為
Handler的作用是更新 UI, 這的確沒錯,但是更新 UI 僅僅是 Handler 的一個特殊的使用場景.具體來說是這樣的:
有時候需要在子線程中進行耗時的 I/O 操作,可能是讀取文件或者訪問網絡等, 當耗時操作完成以後可能需要在 UI 上做一些改變, 由於
Android 開發規范的限制,我們並不能在子線程中訪問 UI 控件,否則就會觸發程序異常, 這個時候通過Handler 就可 以將更新
UI 的操作切換到主線程中執行。 因此,本質上來說, Handler 並是專門用於更新 UI 的,它只是常被開發者用來更新 UI。

Android 的消息機制主要是指 Handler 的運行機制, Handler 的運行需要底層的MessageQueue 和
Looper 的支撐。 MessageQueue 的中文翻譯是消息隊列,顧名思義,
它的內部存儲了一組消息,以隊列的形式對外提供插入和刪除的工作。 雖然叫消息隊列,但是它的內部存儲結構並不是真正的隊列,
而是采用單鏈表的數據結構來存儲消息列表。 Looper的中文翻譯為循環, 在這裡可以理解為消息循環。由於 MessageQueue
只是一個消息的存儲單元,它不能去處理消息,而 Looper 就填補了這個功能, Looper
會以無限循環的形式去查找是否有新消息,如果有的話就處理消息,否則就一直等待著。 Looper 中還有一個特殊的概念,那就是
ThreadLocal, ThreadLocal 並不是線程,它的作用是可以在每個線程中存儲數據。我們知道, Handler
創建的時候會采用當前線程的 Looper 來構造消息循環系統,那麼 Handler 內部如何獲取到當前線程的 Looper 呢?
這就要使用 ThreadLocal 了,ThreadLocal可以在不同的線程中互不干擾地存儲並提供數據,通過 ThreadLocal
可以輕松獲取每個線程的 Looper。當然需要注意的是,線程是默認沒有 Looper 的,如果需要使用 Handler 就必須為線程創建
Looper。我們經常提到的主線程,也叫 UI 線程,它就是ActivityThread,ActivityThread被創建時就會初始化
Looper,這也是在主線程中默認可以使用 Handler 的原因。 上面這段話是任玉剛老師書中對於android消息傳遞機制的描述我覺得描述的非常清晰。

android定下規則:只允許UI線程(主線程)修改Activity裡的UI組件

但是應用中有時需要操作UI如獲取短信驗證碼,有個倒計時,為此需要借助Handler消息傳遞機制

Handler類簡介

【1】作用:
1在新啟動的線程中發送消息
2在主線程中獲取處理消息
主要方法
方法簽名
public void handleMessage (Message msg)

子類對象通過該方法接收信息

public final boolean sendEmptyMessage (int what)

發送一個只含有what值的消息

public final boolean sendMessage (Message msg)

發送消息到Handler,通過handleMessage方法接收

public final boolean hasMessages (int what)

監測消息隊列中是否還有what值的消息
public final boolean hasMessages (int what,Objectobject)

監測消息隊列中是否還有what值的消息且object屬性為制定對象的消息

public final boolean post (Runnable r)
將一個線程添加到消息隊列

這裡寫圖片描述

下面一個倒計時例子

public class MainActivity extends Activity  {
    private Button button;
    private  int count;
    private  Message message;
    private static final int  TIME_DESC=0;

    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        switch (message.what){
            case TIME_DESC:
                String time= (String) message.obj;
                button.setText(time);
                break;
        }


        }
    } ;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        button= (Button) findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
              count=60;
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        while(count>0){
                            count--;
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }

                            message=new Message();
                            message.obj=count+秒;
                            message.what=TIME_DESC;
                            handler.sendMessage(message);

                        }

                    }
                }).start();


            }
        });

    }
}

精簡一下上面的代碼如下

public class MainActivity2 extends Activity  {
    private Button button;
    private  int count;
    private  Message message;
    private static final int  TIME_DESC=0;

    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (message.what){
                case TIME_DESC:
                    count--;
                    button.setText(count+秒);
                   if(count>0){
                       handler.sendEmptyMessage(TIME_DESC);
                       try {
                           Thread.sleep(1000);
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
                    break;
            }


        }
    } ;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        button= (Button) findViewById(R.id.button);
         //message初始化
        message=new Message();
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                count=60;
               handler.sendEmptyMessage(TIME_DESC);
            }
        });

    }
}

Looper簡介

Android中的Looper類,是用來封裝消息循環和消息隊列的一個類,用於在android線程中進行消息處理。handler其實可以看做是一個工具類,用來向消息隊列中插入消息的。

(1) Looper類用來為一個線程開啟一個消息循環。
默認情況下android中新誕生的線程是沒有開啟消息循環的。(主線程除外,主線程系統會自動為其創建Looper對象,開啟消息循環。)
Looper對象通過MessageQueue來存放消息和事件。一個線程只能有一個Looper,對應一個MessageQueue。

(2) 通常是通過Handler對象來與Looper進行交互的。Handler可看做是Looper的一個接口,用來向指定的Looper發送消息及定義處理方法。
默認情況下Handler會與其被定義時所在線程的Looper綁定,比如,Handler在主線程中定義,那麼它是與主線程的Looper綁定。
mainHandler = new Handler() 等價於new Handler(Looper.myLooper()).
Looper.myLooper():獲取當前進程的looper對象,類似的 Looper.getMainLooper() 用於獲取主線程的Looper對象。

(3) 在非主線程中直接new Handler() 會報如下的錯誤:
E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception
E/AndroidRuntime( 6173): java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()
原因是非主線程中默認沒有創建Looper對象,需要先調用Looper.prepare()啟用Looper。

(4) Looper.loop(); 讓Looper開始工作,從消息隊列裡取消息,處理消息。

注意:寫在Looper.loop()之後的代碼不會被執行,這個函數內部應該是一個循環,當調用mHandler.getLooper().quit()後,loop才會中止,其後的代碼才能得以運行。

(5) 基於以上知識,可實現主線程給子線程(非主線程)發送消息。

public class MainActivity3 extends Activity {
    private Button button_send;
    private Handler handler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mainthreadsend);
        handler=new Handler();

        button_send = (Button) findViewById(R.id.button_send);
        button_send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MyThread thread = new MyThread();
                thread.start();
                handler.sendEmptyMessage(0);
            }
        });
    }
    class MyThread extends Thread {

        @Override
        public void run() {
            Looper.prepare();
            handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    Log.d(handle, 收到主線程發送的消息);
                }
            };
            Looper.loop();
        }
    }
}

結果這裡寫圖片描述

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved