Android 高級進階之深刻剖析消息機制

Android 高級進階之深刻剖析消息機制

閱讀時間:8 分鐘編程

坐穩了沒?要開車了哦安全


寫在前邊
服務器

今天分享的內容是深刻剖析 Android 的消息機制,有些人問了,一些功能會用不就好了嗎?爲何還要分析底層源碼呢?今天小鹿告訴你的是不少開源的項目都已經不須要咱們造輪子了,重複造輪子是多麼愚蠢的一件事。可是,Android 的底層源碼和一些功能的實現讓咱們學習到底層的模式和邏輯實現。數據結構

學編程什麼最重要,固然是邏輯思惟了,即便你什麼功能都能實現,邏輯思惟能力差照樣啥都幹不了。你的思惟邏輯能力差,在技術路線上已經決定了你的高度。多線程

Android 的消息機制併發

Android 的消息機制主要是指 Handlerr 的運行須要底層的 MessageQueue 和 Looper 的支撐。ide

(1)MessageQueue 的中文翻譯是消息隊列。以隊列的形式對外提供插入和刪除工做。雖然叫作消息隊列,可是內部存儲結構並非真正的隊列,而是以單鏈表的數據結構來存儲消息列表。oop

(2)Looper 的中文翻譯爲循環,咱們叫它消息循環。因爲 MessageQueue 只是一個存儲單元,不會去處理消息。而 Looper 確彌補了這個功能,Looper 會以無限無限循環的形式去查找是否有新的消息,有的話就去處理消息,不然就一直等待。源碼分析

學習思惟導圖:post

之後文章中的思惟導圖是小鹿給你們精心整理的,這樣對每篇分享的文章都有一個清晰地結構,有利於複習和整理。

Android 高級進階之深刻剖析消息機制

1、Android 消息機制概述

Android 消息機制主要是指 Handler 的運行機制以及 Handler 所附帶的 MessageQueue 和 Looper 的工做過程。Handler 的主要做用就是將一個任務切換到某個指定的線程中去執行。

概述

(1)思考:爲何 Android 要提供這個功能呢?

答:由於 Android 規定訪問 UI 線程只能在主線程中進行的,若是在子線程中訪問 UI ,那麼程序就會拋出異常。

(2)源碼:通過查看看源碼的 checkThread()方法對更新 UI 是否在主線程中更新,進行拋出異常信息提示開發者(相信在開發中都遇到過這個種狀況)。

(3)過程:因爲以上限制,這就要求開發者必須在主線程中更新 UI,可是 Android 又建議不要在主線程中進行過於耗時的工做,不然會產生應用程序無響應 ANR。考慮到這種狀況,當咱們在服務器拉去一些信息並顯示到 UI 上時,拉去工做咱們將在子線程中進行,拉取完畢以後不能再子線程中直接更新 UI ,沒有 Handler ,那咱們的確沒有辦法將訪問 UI 的工做切換到主線程去執行。所以,系統之因此給咱們提供 Handler,主要緣由是爲了解決在子線程中沒法訪問 UI 的矛盾。

(4)問題:

① 爲何不能再子線程中更新 UI? 
答 : 由於 Android 的 UI 控件不是線性安全的。若是在多線程中併發的訪問可能會致使 UI 控件處於不可預期的狀態。

② 爲何不對 UI 控件的訪問加上鎖機制呢? 

答 :首先,加上鎖機制會讓訪問 UI 變的複雜,其次鎖機制會下降 UI 的訪問效率,由於鎖機制會阻塞某些線程的執行。

最簡單最高效的就是採用單線程模型來處理 UI 操做,只需經過 Handlerr 切換一下 UI 訪問的執行線程便可。

Handler 的工做原理

Handler 建立時就會採用當前的 Looper 來構建內部的消息循環系統,若是當前沒有 Looper ,那麼就會報錯。

怎麼解決上述問題?兩個方法:

① 爲當前線程建立 Looper 便可。
② 在 Looper 的線程中建立 Handler 也能夠。

工做原理

(1)Handler 建立過程: Handler 被建立以後,內部的 MessageQueue 和 Looper 就與 Handler 一塊兒工做協同工做了, 而後經過 Handler 的 post 方法將一個 Runnable 投遞給 Handler 內部的 Looper 去處理;也能夠經過 Handler 的 send 方法發送一個消息,也是經過 Looper 去處理的,其實 Post 方法最終也是經過 send 方法來完成的..

(2)send 方法的工做過程:當 Handler 的 send 方法被調用時,它會調用 MessageQueue 的 enqueueMessage 方法將這個消息放到消息隊列中,而後 Looper 發現新消息,就會處理這個消息,最終消息的 Runnable 或者 Handler 的 handlerMessage 方法就會被調用。

Android 高級進階之深刻剖析消息機制

2、 Android 的消息機制分析

消息隊列的工做原理

消息隊列在 Android 主要是指 MessageQueue ,MessageQueue 主要包括兩個操做:插入和刪除。消息隊列的內部實現並非隊列,實際上經過一條單鏈表的數據結構來維護消息隊列,單鏈表在插入刪除上頗有優點。

① 插入(enqueueMessage):往消息隊列中插入一條消息。(源碼實現就是單鏈表的插入)

② 刪除(next):從消息隊列中取出一條消息並將其從消息隊列中移除。(next 是一個無限循環的方法,消息隊列沒有信息就處於阻塞狀態,有新消息到來就執行單鏈表的刪除)

Lopper 的工做原理

Looper 在 Android 消息機制中扮演着消息循環的角色,做用:不停地從 MessageQueue 中查看是否有新的消息,若是有消息就會馬上處理,若是沒有消息就會處於阻塞狀態。

(1) Looper 的構造方法

① 建立一個 MessageQueue 消息隊列。

② 將當前線程的對象保存起來。

(2)如何爲一個線程建立 Looper

(Handle 的工做須要 Looper,沒有 Looper 就會報錯)

① 經過 Looper.prepare() 方法爲線程建立一個 Looper 。

 ② 經過 Looper.loop() 方法來開啓消息循環。

(3)建立線程的另外一種方法

① 主線程 Looper 的獲取。 Looper 這個方法主要給線程也就是 ActivityThread 建立 Looper 使用的,本質也是經過 prepare 來實現的,因爲主線程的 Looper 比較特殊,因此 Looper 提供了一個 getMainLopper 的方法獲取主線程的 Looper。

② Looper 的退出。****Looper 提供了兩個方法:quit 方法和 quitSafely 方法。

二者區別:quite 直接退出 Looper。

而 quitSafely 只是設定一個退出標記,先把消息隊列中的消息處理完以後再退出

(4)Looper.loop() 方法實現原理

loop 是一個死循環,惟一能跳出循環的方法就是 MessageQueue 的 next 方法返回了 null。當 Looper 的 quit 方法被調用時,MessageQueue 的 quit 方法或者 quitSafely 方法就會通知消息隊列退出,當消息隊列被標記爲退出狀態時,next 就會返回一個 null。Looper 是必須退出的,不然 loop 會永遠循環下去。

loop 方法會調用 MessageQueue 的 next 方法獲取消息,若是 MessageQueue 沒有消息,next 就會處於阻塞狀態,loop 方法也會處於阻塞狀態。

詳解 Handler 的工做原理

Handler 的主要工做就是發送和接收消息。消息的發送能夠經過 post 一系列方法以及 send 的一系列方法來實現,post 的一系列方法最終都是經過 send 一系列方法來實現的。

代碼實現:

1public class HandlerActivity extends Activity {
 2
 3    @Override
 4    protected void onCreate(@Nullable Bundle savedInstanceState) {
 5        super.onCreate(savedInstanceState);
 6        setContentView(R.layout.activity_main);
 7
 8        //開啓線程
 9        handler();
10    }
11    //主線程
12    Handler handler = new Handler(){
13
14        @Override
15        public void handleMessage(Message msg) {
16            super.handleMessage(msg);
17            switch (msg.what) {
18                case 1:
19                    // 獲取Message裏面的複雜數據
20                    Bundle date = new Bundle();
21                    date = msg.getData();
22                    String name = date.getString("name");
23                    int age = date.getInt("age");
24                    String sex = date.getString("sex");
25                    //這裏是主線程,可進行對UI的更新
26                    textView.setText(name)
27            }
28        }
29    };
30
31    //子線程
32    public void handler(){
33        new Thread(new Runnable() {
34            @Override
35            public void run() {
36                Message message = new Message();
37                message.what = 1;
38
39                // Message對象保存的數據是Bundle類型的
40                Bundle data = new Bundle();
41                data.putString("name", "李文志");
42                data.putInt("age", 18);
43                data.putString("sex", "男");
44                // 把數據保存到Message對象中
45                message.setData(data);
46                // 使用Handler對象發送消息
47                handler.sendMessage(message);
48            }
49        }).start();
50    }
51}

發送消息

經過對源碼分析,Handler 發送消息的過程僅僅是向消息隊列中插入一條信息,MessageQueue 的 next 方法就會返回這條信息給 Looper ,Looper 接收到消息以後就當即處理,由 Looper 交給 Handler 去處理消息,Handler 的 dispatchMessage 方法就會被調用,這時候 Handler 就進入了消息處理階段。

消息處理

Android 高級進階之深刻剖析消息機制

深刻 dispatchMessage 的源代碼進行分析,Handler 處理消息以下:

① 首先檢查 Message 的 callback 是否爲 null, 不爲 null 就經過 handlerCallback 來處理消息。(Message的 callback 是一個 Runnable d 對象,實際上就是 post 方法所遞的 Runnable 參數)

② 其次檢查 mCallback 是否爲 null,不爲 null 就調用 mCallback 的 handlerMessage 方法來處理消息。Callback 是個接口。

③ 咱們經過 Callback 能夠採用以下的方式來建立 Handle 對象。

1Handler handler = new Handler(callback);

這樣建立的意義就是建立一個實例可是並不須要派生 Handler 的子類。

④ 可是,在咱們的平常開發中,常常派生一個 Handler 的子類並重寫其 handleMessage 方法來處理具體的消息,若是不想建立派生子類,就能夠經過 Callback 來實現。

主線程的消息循環

Android 的主線程就是 ActivityThread,主線程的入口方法爲 main ,在 main 方法中系統會經過 Looper.prepareMainLooper();來建立主線程的 Looper 以及 MessageQueue ,並經過 Looper.loop() 來開啓主線程的消息循環。

主線程的消息循環開始了之後,ActivityThread 還須要一個 Handler 來和消息隊列進行交互,這個 Handler 就是 ActivityThread.H 。ActivityThread 經過 ApplicationThread 和 AMS 進行進程間通訊,AMS 以進程間通訊的方式完成 ActvityThread 的請求後會回調 ApplicationThread 中的 Binder 方法,而後 ApplicationThread 向 H 發送消息,H 收到消息會將 ApplicationThread 中的邏輯切換到 ActivityThread 中去執行,即切換到主線程中去執行,這個過程就是主線程的消息循環模型。

相關文章
相關標籤/搜索