android高級---->Handler的原理


  andriod提供了Handler來滿足線程間的通信,上次在更新UI的時候也提到過Handler的使用,關於Handler的基本使用,參見博客(android基礎---->子線程更新UI).今天我們深入Handler的源碼,了解一個Handler的內部執行原理。

 

目錄導航

  1.   Handler簡單說明
  2.   ActivityThread的說明
  3.   Handler的預備分析
  4.   Handler的原理分析
  5.   友情鏈接

 

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()方法來進行處理。

 

友情鏈接

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM