Android開發——Android的消息機制詳解

1. 咱們爲何須要Android的消息機制java

 咱們知道,Android規定訪問UI只能在主線程中進行。若在子線程中訪問UI,就會拋出異常。這個驗證由ViewRootImplcheckThread方法來完成。安全

爲何不容許在非主線程訪問UI,這是由於AndroidUI控件不是線程安全的。併發訪問會致使控件處於不可預期的狀態。數據結構

那爲何不對UI訪問加上鎖機制呢,緣由以下:併發

1)這顯然會讓UI訪問的邏輯變得極其複雜;ide

2)除了效率問題,鎖機制還會阻塞某些進程的執行。oop

 可是Android又不建議在主線程進行耗時操做,由於這可能會引發ANR。所以,便出現了Android的消息機制。post

本文原創,轉載請註明出處:http://blog.csdn.net/seu_calvin/article/details/52120086ui

 

2. Android的消息機制結構this

 Android的消息機制主要是指Handler的運行機制。Handler的運行須要底層MessageQueueLooper的支撐。spa

 

2.1  MessageQueue

MessageQueue採用單鏈表的數據結構存儲消息列表對外提供插入(enqueueMessage)和讀取(next)工做。讀取自己附帶刪除操做。單鏈表在插入和刪除上比較有優點。

enqueueMessage方法根據消息的延遲時間來進行的單鏈表的插入操做,next方法是一個無限循環,若是消息隊列中沒有消息,就會阻塞,當有新消息到來時,next方法就返回這條消息並將其從單鏈表中刪除。

 

2.2  Looper

Looper以無限循環的形式去消息隊列查找是否有新消息,若是有,就處理消息,不然就一直阻塞等待。

須要注意的是,Handler在建立時會採用當前線程的Looper來構造消息循環系統Handler內部是經過ThreadLocal來實現的。

有一種狀況是HandlerThread,HandlerThread 繼承自Thread內部已經封裝了Looper。並對外提供本身這個Looper對象的get方法,這就是它和普通Thread惟一不一樣的地方。具體關於HandlerThread的使用以及特性介紹請查看Android開發——HandlerThread以及IntentService詳解

ThreadLocal適用於某些數據以線程爲做用域而且不一樣線程具備不一樣數據副本的場景。

ThreadLocal能夠在不一樣線程中互不干擾地存儲並提供數據,經過它能夠獲取每一個線程的Looper

ThreadLocal的神奇功能介紹請看以前寫過的一篇博文,Android開發——ThreadLocal功能介紹

1UI線程,即ActivityThread被建立時會初始化Looper,所以在主線程默承認以使用Handler

2)子線程默認是沒有Looper的,Handler建立前,必須手動建立,不然會報錯。經過Looper.prepare()便可爲當前線程建立一個Looper,並經過Looper.loop()來開啓消息循環。以下所示。

new Thread(){
    @Override
    public void run() {
        Looper.prepare();
        Handler handler = new Handler();
        Looper.loop();
    }
}.start();

Looperloop()方法極其重要。由於它消息循環系統才真正起做用。

loop方法就是一個死循環,跳出死循環的惟一條件是MessageQueuenext返回了null。當Looperquit方法被調用時,MessageQueuenext就會返回了null

loop方法會調用MessageQueuenext方法,next是一個阻塞操做,前面也講過了。只有當next返回了新消息,Looper纔會處理這條消息。這樣Handler發送的消息最終又交給它的dispatchMessage方法來處理可是HandlerdispatchMessage方法是在建立Handler時所使用的Looper中執行的。這樣就將邏輯切換到指定線程中去執行了。

 

Looper也是能夠退出的Looper提供quitquitSafely來退出一個Looper。惟一的區別是,後者會處理完消息隊列中已有的消息後才安全退出,前者直接退出。Looper退出後,經過Handler發送消息會失敗,send方法返回false。在子線程中,手動建立的Looper在不須要時應quit退出,不然會此線程會一直處於等待狀態。

 

2.3  Handler

Handler主要工做是消息的發送和接收

消息的發送能夠使用Handlerpost的方法(最終仍是經過send方法完成)將一個Runnable投遞到Looper中去處理send方法發送一個消息也是同理。

這裏咱們有必要對這兩種方式進行說明。

handler.post(new Runnable(){
@Override
public void run() {
//do something
}});

或者這種用法的變形,用途很廣,功能是延遲3秒後從歡迎界面進入主界面。這裏並非開啓了一個新的線程

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        Intent intent = new Intent(SplashActivity.this, MainActivity.class);
        startActivity(intent);
        finish();
    }
}, 3000);

post方法的使用如上所示,咱們還知道Hanlder中也有一個handler.sendMessage(Messagemsg)方法,這兩個方法有什麼區別呢?

看一下handler.post(Runnable callback)方法的源碼,很明顯最終仍是經過send方法完成的。

public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}

再看一下sendMessageDelayed的源碼

public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

這裏面有個關鍵就是方法getPostMessage(r)這個方法,他將Runnable轉成一個Message,他內部到底幹了什麼呢?看一下他的源碼:

private final Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}

這裏面就是將Runnable轉化成一個Message,其餘看他的代碼很簡單,就是先獲取一個空消息Message.obtain(),而後Message中私有變量callback的值設置成Runnable


send方法被調用時,會調用MQenqueueMessage方法將這個消息放入消息隊列中,MQnext方法會返回這條消息給LooperLooper發現新消息到來會處理之,最終消息交給Handler處理。dispatchMessage方法被調用,過程以下。

public void dispatchMessage(Message msg){
    if(msg.callback!=null){
        handleCallback(msg);
    }else{
        if(mCallback!=null){
            if(mCallback.handleMessge(msg)){
                return;
            }
        }
        handleMessage(msg);
    }
}

首先檢查Messagecallback不爲null不爲null就意味着,callback是一個Runnable對象(實際上就是Handlerpost方法所傳遞的Runnable參數),這就是從post方法來實現的。就經過handleCallback來處理消息。handleCallback邏輯很簡單,直接就是msg.callback.run(),執行咱們在Runnable方法裏重寫的run方法。

其次檢查mCallback不爲空,調用mCallbackhandleMessage方法來處理消息。

這是爲了處理如下這種Handler的使用狀況CallBack能夠用來建立一個Handler的實例但並不須要派生Handler的子類。

Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            return false;
        }
    });

若咱們直接返回了true,就不用再處理消息了。返回false,或者mCallback爲空,會在最後執行HandlerhandleMessage(msg)方法來處理消息。

這樣咱們就分析完了Android消息機制的整個流程。

相關文章
相關標籤/搜索