Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> android的消息機制

android的消息機制

編輯:關於android開發

android的消息機制


很多以前掌握的知識,總是慢慢的再忘記,看來還是自己理解的不夠透徹,希望用博客的形式記錄下來。

說起android的消息機制,那不得不提Handler,它的中文含義就是控制者,處理者。
安卓上的關於Handler的文檔是這麼寫的:
Handler可以發送和處理Message,Runnable對象,並且與一個線程的MessageQueue關聯。
當創建了Handler實例,它就會綁定在創建它線程的消息隊列上。

這裡寫圖片描述

首先在主線程中創建Handler的實例,與主線程的MessageQueue綁定,MessageQueue裡有一個輪詢器Looper,它會不斷的查看消息隊列是否有消息。如果有消息,就會把這個消息扔給Handler的handleMessage去處理。
這時,子線程拿到Handler對象,往主線程的MessageQueue發消息,消息隊列就有了消息,就會把消息扔給handleMessage去處理消息。
上面的過程,聽起來十分繞耳。為什麼要這麼做?在子線程中去處理不行嗎?
我們知道子線程一般是用於處理耗時的操作,是不可以更新UI的。
因為多線程同時去draw,去操作UI界面,UI界面實在不好控制。操作UI的動作必須要由主線程去做。

所以在子線程中碰見需要更新UI,我們可以使用android為我們提供的Handler。它的出現主要就是為了解決在子線程中無法訪問UI的矛盾。
而如果強行的在子線程去操作UI,可能會出現 “ android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.”的異常。

1,new Handler的時候,Handler究竟做了什麼?
這裡寫圖片描述

Looper.mylooper()
這裡寫圖片描述
這裡寫圖片描述
Looper對象是從ThreadLocal集合中get得到的。那什麼時候,ThreadLocal把Looper對象set進去的呢?
這裡寫圖片描述
在prepare方法中,創建了LoZ喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcGVyttTP86OssqLM7bzTtb3By7TmtKLXxUxvb3BlcrbUz/O1xFRocmVhZExvY2Fs1tChozxiciAvPg0KPGltZyBhbHQ9"這裡寫圖片描述" src="http://www.bkjia.com/uploads/allimg/160407/04145QQ6-5.png" title="\" />
而在new Looper的同時,同樣也創建了MessageQueue的實例。

而調用prepare方法的是prepareMainLooper。
在應用運行時,主線程ActivityThread產生並執行,而在主線程的main方法中,就會調用prepareMainLooper。
也就是說,在應用一啟動,就會去創建Looper,MessageQueue對象。而在Handler的構造方法中,是拿到已經創建好的Looper和MessageQueue。

2,Message消息對象
new Message可以直接創建消息對象。
通過handler.obtainMessage(有許多重載的方法)可以創建消息,翻看源碼可以得知,消息的創建全都是由obtain方法去處理。
這裡寫圖片描述
這裡的sPool表示的是消息池中的第一條消息,當消息池中沒有消息時,就會new一個Message返回。
如果消息池中有的話,就廢物利用,把消息池中的消息返回。
而消息池中的消息是由Message本身來維護的,而不是MessageQueue。
消息池中的消息是這樣擺放的:
這裡寫圖片描述
這裡寫圖片描述
sPool表示是第一條消息,它指向著a。
Message m=sPool;
這時m也指向了a
sPool=m.next
sPool這時不再指向a,而是指向了下一個消息b。
m.next=null
sPoolSize--
a的next成員變量不再指向b,置為null。消息隊列的長度減減,返回消息池中的消息。

3,Looper處理消息的過程
子線程發送消息後,主線程的MessageQueue就有了消息。而消息的扔給Handler去處理,是需要Looper來輪詢的。
定位到Looper的輪詢消息的loop方法。

 Message msg = queue.next(); // might block
 ..........
 ..........
 ..........           
 msg.target.dispatchMessage(msg);

從消息隊列中取出的消息交由了msg.target這個成員變量的dispatchMessage方法。
而msg.target是Handler類型的。那msg.target是怎麼傳遞進來的:

public static Message obtain(Handler h) {
        Message m = obtain();
        m.target = h;

        return m;
    }

該handler在創建Message時,賦予給Handler類型的target。
而在dispatchMessage中,會調用handleMessage。
而在主線程中,我們定義的handleMessage就會覆蓋該方法。
所以,Message對象就這樣一步一步的傳遞到了主線程Handler的handleMessage中。
結論就是:消息是由哪個Handler發送的,就由哪個Handler去處理。

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