android項目實例源碼「android源碼怎麼運行」

Android消息機制其實指的就是Handler的消息機制。

Android消息機制,以及handler源碼分析

以上模型的解釋:

1.以Handler的sendMessage方法為例,當發送一個消息後,會將此消息加入消息隊列MessageQueue中。

2.Looper負責去遍歷消息隊列並且將隊列中的消息分發給對應的Handler進行處理。

3.在Handler的handleMessage方法中處理該消息,這就完成了一個消息的發送和處理過程。 這裡從圖中可以看到參與消息處理有四個對象,它們分別是 Handler, Message, MessageQueue,Looper。

ThreadLocal 是一個線程內部的數據存儲類,通過它可以在指定的線程中存儲數據,數據存儲以後,只有再指定線程中可以獲取到存儲的數據,對於其他線程來說則無法獲取到數據。

我們看下ThreadLocal是如何存儲數據的:

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
在源碼裡面我們可以看出  ThreadLocal在存儲數據的時候,會先拿到當前線程,然後根據當前線程會拿到一個叫做ThreadLocalMap 的Map數組;

那麼ThreadLocalMap 又是什麼呢?

我們可以看到在CreateMap 裡面是創建了ThreadLocalMap ,並且把我們當前線程當作Key,傳遞過去的 Value就是我們在調用ThreadLocal.set(T)傳過來的值

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

Android消息機制,以及handler源碼分析

ThreadLocal是如何獲取數據的

   public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
//會先根據當前線程找到對應的ThreadLocalMap,如果沒有就創建
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
//如果ThreadLocalMap 就會去創建ThreadLocalMap
   private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }
Android消息機制,以及handler源碼分析

通過以上代碼我們可以看出ThreadLocal是如何保證數據存儲以後,只有再指定線程中可以獲取到存儲的數據,對於其他線程來說則無法獲取到數據的了。

我們如何保證Acticity的默認線程是主線程的呢

在Acticity 中我們用到的線程是ActivityThread這個線程,在這個線程的

main(String[] args)方法裡面我們可以看到下面代碼
  public static void main(String[] args) {

        Looper.prepareMainLooper();


        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
Android消息機制,以及handler源碼分析

//上面的代碼裡面我們可以看到創建 ActivityThread的 Looper.prepareMainLooper(); Looper.loop(); 保證了 ActivityThread為主線程。

創建全局唯一Looper對象和全局唯一MessageQueue消息對象

Android消息機制,以及handler源碼分析

Activity中創建Handler

Android消息機制,以及handler源碼分析

Android消息機制,以及handler源碼分析

消息發送

Android消息機制,以及handler源碼分析
Android消息機制,以及handler源碼分析

消息處理

Android消息機制,以及handler源碼分析
Android消息機制,以及handler源碼分析

消息阻塞和延時

Looper 的阻塞主要是靠 MessageQueue 來實現的,在next()@MessageQuese 進行阻塞,在 enqueueMessage()@MessageQueue 進行喚醒。主要依賴 native 層的 Looper 依靠 epoll 機制進行的。

  Message next() {
     
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
//阻塞和延時,主要是next()中nativePollOnce(ptr, nextPollTimeoutMillis)調用naive方法操作管道
            nativePollOnce(ptr, nextPollTimeoutMillis);

        }
 }
Android消息機制,以及handler源碼分析

阻塞和延時,主要是next()中nativePollOnce(ptr, nextPollTimeoutMillis)調用naive方法操作管道,由nextPollTimeoutMillis決定是否需要阻塞nextPollTimeoutMillis為0的時候表示不阻塞,為-1的時候表示一直阻塞直到被喚醒,其他時間表示延時。

喚醒

主要是指enqueueMessage()@MessageQueue 進行喚醒。

    boolean enqueueMessage(Message msg, long when) {
  //在這裡喚醒阻塞的方法
            if (needWake) {
                nativeWake(mPtr);
            }
        
    }
Android消息機制,以及handler源碼分析

簡單理解阻塞和喚醒 就是在主線程的MessageQueue沒有消息時,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此時主線程會釋放CPU資源進入休眠狀態,直到下個消息到達或者有事務發生,通過往pipe管道寫端寫入數據來喚醒主線程工作。 這裡採用的epoll機制,是一種IO多路復用機制,可以同時監控多個描述符,當某個描述符就緒(讀或寫就緒),則立刻通知相應程序進行讀或寫操作,本質同步I/O,即讀寫是阻塞的。 所以說,主線程大多數時候都是處於休眠狀態,並不會消耗大量CPU資源。 從阻塞到喚醒,消息切換

Android消息機制,以及handler源碼分析

延時入隊

Android消息機制,以及handler源碼分析

主要指enqueueMessage()消息入列是,上圖代碼對message對象池的重新排序,遵循規則(when從小到大)。 此處for死循環退出情況分兩種 第一種:p==null表示對象池中已經運行到了最後一個,無需再循環。 第二種:碰到下一個消息when小於前一個,立馬推出循環(不管對象池中所有message是否遍歷完),進行重新排序。

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/208790.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
投稿專員的頭像投稿專員
上一篇 2024-12-08 15:20
下一篇 2024-12-08 15:20

相關推薦

發表回復

登錄後才能評論