每個 Android 開發者必須知道的訊息機制問題總結
Android的訊息機制幾乎是面試必問的話題,當然也並不是因為面試,而去學習,更重要的是它在Android的開發中是必不可少的,佔著舉足輕重的地位,所以弄懂它是很有必要的。下面就來說說最基本的東西。
Looper
作用:
- 關聯起Thread
- 迴圈取出訊息
1、Looper是否可以直接例項化?
Looper構造方法是私有的,其中做了兩件事
- 建立一個MessageQueue
- 得到與之對應的Thread
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
2、一個執行緒能對應多個Lopper?
不能,一個執行緒對應一個Looper物件,通過ThreadLocal保證一個執行緒只有一個Looper與之對應,如果多次呼叫Looper.prepare()
;則會丟擲執行時異常。
private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { // 檢視是否有looper與當前執行緒對應 throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
3、Looper是無限迴圈,會阻塞嗎?
是,當開啟一個loop後是一個死迴圈,從MessageQueue中取出訊息,處理訊息,但是也有可能退出,在沒有訊息後退出迴圈。
public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; // 略 for (;;) { Message msg = queue.next(); // might block if (msg == null) { // 當沒有訊息的時候,退出 // No message indicates that the message queue is quitting. return; } // 略 msg.target.dispatchMessage(msg); }
4、可以再次呼叫Looper.prepareMainLooper嗎?
不可以,Looper.prepareMainLooper最終也是呼叫prepare(),同2.
public static void prepareMainLooper() { prepare(false); // 建立一個Looper synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
5、MainLooper什麼時候建立的?
MainLooper是啟動Activity建立ActivityThread(並不是一個Thread)時候建立,所以不能多次建立。
public static void main(String[] args) { // 略 Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); // 略 ActivityThread thread = new ActivityThread(); thread.attach(false); // 略 if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } // 略 Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } }
Handler
作用:
- 傳送訊息到MessageQueue
- 處理訊息
1、Handler如何與Looper、MessageQueue關聯起來?
我們知道一個Looper對應一個Thread,一個Looper包含一個MessageQueue。當我們建立Handler時就會從當前執行緒中取出與之對應的Looper,讓後在從Looper中取出MessageQueue。
// 1、自動獲取 public Handler(Callback callback, boolean async) { // 略 mLooper = Looper.myLooper(); // 取出當前執行緒中的Looper if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; // 取出MessageQueue mCallback = callback; mAsynchronous = async; } // 2、傳遞一個Looper進來 public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }
Message
單項鍊表結構。
作用:
- 資料的載體
1、訊息如何複用的?
從全域性訊息池(連結串列結構)中
public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }
2、Message為什麼能傳遞?
Android中想要傳遞物件要麼實現Serializable要麼Parcelable,在這裡是實現了Parcelable介面。
public final class Message implements Parcelable { // 略 }
3、如何與Handler關聯?
我們知道在訊息傳機制中Handler充當著“快遞員”的角色,那麼他又是如何與“貨物”--Message發生關係呢?實際上Message有一個成員變數target他的型別正是Handler,
/*package*/ Runnable callback; public int arg1; public int arg2; public Object obj; /*package*/ Handler target; // 關鍵點
當我們通過Handler去send一個Message時候最終都會為target賦值為this,即當前的Handler。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; // 賦值語句 if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
另為如果是通過Message.Obtain(),獲取的複用Message也會為其賦值。
多說一句,Handler.obtainMessage()呼叫的就是Message.Obtain()。
public final Message obtainMessage(){ return Message.obtain(this); }
總結:
通過一系列的包涵關係,最終Looper、Handler、Message、MessageQueue即發生關聯,從而形成一個閉合,開啟訊息迴圈。
困惑
最近一直在看這方面的知識,但是能力有限,還是有不少困惑,如果有錯誤,或你理解下面的問題請聯絡我fvaryu@qq.com,願與君交流學習,謝謝
1、Message中的sPool,哪裡初始化的?為什麼Message.obtain()中不會拋異常?
2、ActivityThread並不是執行緒,為什麼可以建立一個Looper,Main Thread什麼時候建立?
3、為什麼序列化了的物件就可以傳遞?與Binder有關?
4、MessageQueue對應的是NativeMessageQueue,具體實現需要學習?
5、Loop.loop(),會退出嗎?退出時機是什麼?如果會退出,那麼主執行緒同樣會退出嗎?
相關文章
- 每個 Android 開發者必須知道的資源集錦Android
- 每個Android開發者必須知道的記憶體管理知識Android記憶體
- 高效Android開發者必須知道的4個工具Android
- 每一個C#開發者必須知道的13件事情C#
- 15個必須知道的chrome開發者技巧Chrome
- 06.Android之訊息機制問題Android
- 作為Android開發你必須知道的Java反射機制AndroidJava反射
- Android的訊息機制Android
- 敢在簡歷上寫訊息佇列,這幾個問題必須拿下!佇列
- PDB檔案:每個開發人員都必須知道的
- 獨立遊戲想要生存 開發者必須要問自己這個問題遊戲
- 3分鐘看懂Python後端必須知道的Django的訊號機制!Python後端Django
- Android訊息機制Message訊息池Android
- android訊息機制—HandlerAndroid
- 理解 Android 訊息機制Android
- Android訊息機制HandlerAndroid
- Android 之訊息機制Android
- JS 開發者必須知道的十個 ES6 新特性JS
- android之 Android訊息機制Android
- Android的Handler訊息機制 解析Android
- C陷阱和缺陷,必須知道的495個C語言問題C語言
- 每個前端開發者必會的 20 個 JavaScript 面試題前端JavaScript面試題
- Android訊息傳遞之Handler訊息機制Android
- 學習 Android Handler 訊息機制需要注意這些問題!Android
- Android非同步訊息機制Android非同步
- Android訊息機制Handler用法Android
- Android 訊息機制詳解Android
- Android訊息機制(七) RxjavaAndroidRxJava
- 每個Android開發者應該知道的6個SDK和APIAndroidAPI
- 開發者測試:你必須知道 7 件事
- 不想被面試官虐?Android知識彙總,你必須知道的Handler八大問題!面試Android
- OC訊息機制,訊息轉發機制
- [Android進階]Android訊息機制Android
- IT人必須思考的14個問題
- 淺析Android中的訊息機制Android
- Java開發者必須掌握的15個框架(20k是小問題)Java框架
- New的幾個問題 詳解 --讀你必須知道的.NET筆記筆記
- 每個Java程式設計師必須知道的5個JVM命令列標誌Java程式設計師JVM命令列