andriod提供了Handler來滿足線程間的通信,上次在更新UI的時候也提到過Handler的使用,關於Handler的基本使用,參見博客(android基礎---->子線程更新UI).今天我們深入Handler的源碼,了解一個Handler的內部執行原理。
目錄導航
Handler簡單說明
一、 在Handler的原理說明之前,我們列出相關的重要的類:
- Message:消息,其中包含了消息ID,消息處理對象以及處理的數據等,由MessageQueue統一列隊,終由Handler處理。
- Handler:處理者,負責Message的發送及處理。使用Handler時,需要實現handleMessage(Message msg)方法來對特定的Message進行處理,例如更新UI等。
- MessageQueue:消息隊列,用來存放Handler發送過來的消息,並按照FIFO規則執行。當然,存放Message並非實際意義的保存,而是將Message以鏈表的方式串聯起來的,等待Looper的抽取。
- Looper:消息泵,不斷地從MessageQueue中抽取Message執行。因此,一個MessageQueue需要一個Looper。
- Thread:線程,負責調度整個消息循環,即消息循環的執行場所。
二、 Handler主要有兩種用途:
- 合理調度安排消息和runnable對象,使它們在將來的某個點被執行。
- 將一個動作入隊安排在非當前線程執行。
三、 Handler創建消息
每一個消息都需要被指定的Handler處理,通過Handler創建消息便可以完成此功能。Android消息機制中引入了消息池。Handler創建消息時首先查詢消息池中是否有消息存在,如果有直接從消息池中取得,如果沒有則重新初始化一個消息實例。使用消息池的好處是:消息不被使用時,並不作為垃圾回收,而是放入消息池,可供下次Handler創建消息時使用。消息池提高了消息對象的復用,減少系統垃圾回收的次數。
四、 Handler發送消息
UI主線程初始化第一個Handler時會通過ThreadLocal創建一個Looper,該Looper與UI主線程一一對應。使用ThreadLocal的目的是保證每一個線程只創建唯一一個Looper。之后其他Handler初始化的時候直接獲取第一個Handler創建的Looper。Looper初始化的時候會創建一個消息隊列MessageQueue。至此,主線程、消息循環、消息隊列之間的關系是1:1:1。
五、 Handler處理消息
UI主線程通過Looper循環查詢消息隊列UI_MQ,當發現有消息存在時會將消息從消息隊列中取出。首先分析消息,通過消息的參數判斷該消息對應的Handler,然后將消息分發到指定的Handler進行處理。注意handler是主線程中的類。
ActivityThread的說明
一、 Android的一個apk在打開時,使用到的第一個類就是這個類。
這里我們不深入Android應用程序的啟動原理了,ActivityThread是一個final類,不是一個線程類:
public final class ActivityThread
二、 ActivityThread在創建的時候同時也啟動了一個線程,這個線程就是一個異步線程。
他創建出了MessageQueue,並同時進行消息的輪 詢,因此當這個應用程序在運行時,這個線程是一直都在的。這個線程就是應用程序的主線程,UI的處理等都是在這個線程處理的。在AcitivityThread這個類的是有一個main方法的。我們知道java應用程序的入口就是main方法。這就是程序的入口。我們來看ActivityThread的源代碼:
public static void main(String[] args) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Environment.initForCurrentUser(); // Set the reporter for event logging in libcore EventLogger.setReporter(new EventLoggingReporter()); AndroidKeyStoreProvider.install(); // Make sure TrustedCertificateStore looks in the right place for CA certificates final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
這里我們重點關注兩點,這個在Handler的原理分析中會做詳細的說明:
- Looper.prepareMainLooper();
- Looper.loop();
Handler的預備分析
一、 首先程序在啟動的時候,會執行ActivityThread類的main方法,如上我們提到兩個重要的代碼: Looper.prepareMainLooper();
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
在他的prepare方法中,創建了一個Looper,並把它放在了ThreadLocal中:
private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
二、 ActivityThread中的Looper.loop();
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; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) {
// 從隊列中取出消息 Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); }
// 分發消息 msg.target.dispatchMessage(msg); if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycleUnchecked(); } }
在msg.target.dispatchMessage(msg);方法中msg.target這是分發消息的Handler
public void dispatchMessage(Message msg) { if (msg.callback != null) {
// 首先,處理Message自己的callback,調用其run方法 handleCallback(msg); } else { if (mCallback != null) {
// 其次,調用Handler自留的接口對象 if (mCallback.handleMessage(msg)) { return; } }
// 最后,調用handleMessage方法處理消息,Handler類中這個方法為空,子類可以重寫這個方法 handleMessage(msg); } }
Handler的原理分析
我們仍舊用一個例子來加以說明Handler的原理,例子代碼具體可以參見我的博客:(android基礎---->子線程更新UI)。以下的分析我會帖出有關例子的重要代碼:
一、 創建一個Handler,處理消息:
public static final int UPDATE_TEXT = 1; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case UPDATE_TEXT: textView.setText("I Love you."); break; default: break; } } }
二、 發送消息:
// 用handler處理上述問題 public void handlerUpdate(View view) { new Thread(new Runnable() { @Override public void run() { Message message = new Message(); message.what = UPDATE_TEXT; handler.sendMessage(message); // 將Message對象發送出去 } }).start(); }
三、 首先我們要創建一個handler,具體構造方法代碼如下,這里由於是new Handler():callback=null,async=false
public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
四、 接下來進行了我們消息的發送:handler.sendMessage(message),源代碼如下:(中間我們省略了一些過程)
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }
enqueueMessage(queue, msg, uptimeMillis)的代碼如下:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
- 所謂發送消息就是把消息放入消息隊列中的合適位置,並且把消息的target設置為本Handler對象。
五、 在上述Handler的預備分析當中,我們提到過Looper的loop方法,它負責從隊列中取出消息,並且分發消息。
而且我們在Handler的dispatchMessage方法也了解到,分發的消息會由Handler的handleMessage方法處理:也就是我們創建的Handler的重寫方法:
public void handleMessage(Message msg) { switch (msg.what) { case UPDATE_TEXT: textView.setText("I Love you."); break; default: break; } }
- 當隊列中的消息處理的時候,也會找到當時送它來的Handler對象,
- 調用其相應的dispatchMessage()方法
- 調用其中的handleMessage()方法或者mCallback成員的handleMessage()方法來進行處理。
友情鏈接