1. 程式人生 > >handler的原始碼分析

handler的原始碼分析

boolean enqueueMessage(Message msg, long when) {
        // 判斷有沒有 target 
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        // 有沒有在使用 
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }
        // 對當前訊息佇列加鎖。
        synchronized (this) {
            // 判斷訊息佇列是否棄用(通常因為執行緒已死)
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }
            // 標記訊息正在使用中
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            // 第一次新增資料到佇列中,或者當前 msg 的時間小於 mMessages 的時間
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                // 把當前 msg 新增到連結串列的第一個
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // 不是第一次新增資料,並且 msg 的時間 大於 mMessages(頭指標) 的時間
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    // 不斷的遍歷找到合適的位置
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                // 把當前 msg 插入到列表中
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }
第一次進來的時候Mseeage  p= null; msg.next = p--->msg.next = null; mMessage = msg; 目前為止沒有看到handler去呼叫handleMessage()的方法,目前只是看到messequeue吧訊息給了mMessage


總結,handler.sendMeassage其實將message加入到訊息佇列,佇列採用連結串列的方式,按照when進行時間排序

為什麼訊息佇列要採用連結串列的方式儲存來儲存message?

連結串列的要實現手拉手的資料結構,那麼連結串列中的每一個元素肯定知道他的上一個節點元素和下一個節點元素分別是誰,在java中,弱化了指標的概念,因此,每一個節點元素持有上一個節點元素和下一個節點元素的物件的引用。也就是說,每一個節點物件應該有3個屬性:1,value值;  2,上一個節點的引用;  3,下一個節點的引用。這三個屬性是連結串列資料結構的核心,有了這三個屬性,基本雛形就已經完成了。接下來,我們在每次新增或者刪除或者插入一個新的節點的時候,只需要做2件事情:1,將前一個節點的next引用改變;2,將後一個節點的last引用改變。所以同陣列相比,連結串列增刪比較快

Loop訊息迴圈

new Thread(){
    @Override
    public void run() {
        Looper.prepare();
        Handler handler = new Handler();
        Looper.loop();
    }
}.start();

子執行緒中使用handler必須先要呼叫Looper.prepare()。不然會報錯,我們在主執行緒中並沒有呼叫Loop.prepare()。為什麼不報錯

因為我們應用啟動的時候,activityThread的入口函式main()方法中已經幫我們寫了這行程式碼 Looper.prepareMainLooper()//準備迴圈
public static void main(String[] args) {
    // ... 省略部分程式碼
    
    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");
}

public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } 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)); } public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
sThreadLocal.set(new Looper(quiteAllowed));
Thread t = Thread.currentThread();
//從執行緒中獲取ThreadLocalMap,一個執行緒一個ThreadLocalMap
ThreadLocalMap map = getMap(t);
if(map != null){
map.set(this,value)
}


 總結其實就是保證Thread執行緒中有且只有一個tlooper物件

這些程式碼相對就比較簡單了,主要還是 ThreadLocal 的 set 方法,用來保證一個執行緒只有一個 Looper 物件,這樣就保證了執行緒的安全。接下來看一下 Looper.loop() 這行:

public static void loop() {
    final Looper me = myLooper();
    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;
        }

        try {
            // 通過 target 去 dispatchMessage 而 target 就是繫結的 Handler
            msg.target.dispatchMessage(msg);
        } finally {
            // 訊息回收迴圈利用
            msg.recycleUnchecked();
        }
    }
}




相關推薦

Handler原始碼分析

1、介紹 Handler是用來結合線程的訊息佇列來發送、處理Message物件和Runnable物件的工具。每一個Handler例項之後會關聯一個執行緒和該執行緒的訊息佇列。當你建立一個Handler的時候,從這時開始,它就會自動關聯到所在的執行緒/訊息佇列,

Android開發Handler原始碼分析

為什麼使用Handler Android中UI控制元件的訪問是執行緒不安全的,加鎖同步訪問會影響效能,因此設定只能一個執行緒更新UI,就是主執行緒,或者說是UI執行緒。在UI執行緒中不能進行耗時的操作,耗時操作需要開啟一個新的工作執行緒,工作執行緒不能更新UI

原始碼分析Handler機制

看下面例子: 在子執行緒傳送一個訊息,然後在主執行緒街道這個訊息處理,這個訊息是如何從子執行緒切換到主執行緒的呢?首先跟蹤一下handler.sendMessage(new Message())如下: 從上面兩圖看輾轉來到sendMessageAtTime方法,看到A處,此處mQu

安卓進階(3)之Handler/Looper/MessageQueue原始碼分析以及原理理解

前言 安卓系統是訊息驅動的,所以深刻了解Handler整個訊息分發機制,對於我們瞭解安卓系統,是一個必不可少的知識點。整個過程中,我們需要重點關注的類是: 1. Handler 2. Looper 3. MessageQueue 4. Meesage 5. Th

Handler機制原始碼分析

經常使用Handler進行子執行緒和UI執行緒的通訊。例如:子執行緒處理資料,通過Handler切換到UI執行緒更新對應UI。 出於對Handler的好奇和知識的渴望,所以研究了一下Handler相關的原始碼。 在講解原始碼之前,應該先了解一下:Handler、

【轉】從原始碼分析Handler的postDelayed為什麼可以延時?

版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/aliankg/article/details/70842494Thread/Hander/Looper是Android在Java執行緒基礎之上提供的執行緒通訊/訊息處理機制,這個眾所周知,不再細說。Handle

Handler原始碼詳解及導致記憶體洩漏的分析

[TOC] 簡介 android的訊息處理有三個核心類:Looper,Handler和Message, 主要接受子執行緒傳送的資料, 並用此資料配合主執行緒更新UI。 部分圖片來至CodingMyWorld部落格,3Q 使用方法 pu

Netty原始碼分析第4章(pipeline)---->第2節: Handler的新增

  Netty原始碼分析第四章: pipeline   第二節: Handler的新增     新增handler, 我們以使用者程式碼為例進行剖析: .childHandler(new ChannelInitializer<SocketCha

Netty原始碼分析第4章(pipeline)---->第3節: handler的刪除

  Netty原始碼分析第四章: pipeline   第三節: handler的刪除     上一小節我們學習了新增handler的邏輯操作, 這一小節我們學習刪除handler的相關邏輯   如果使用者在業務邏輯中進行ctx.pipelin

Android訊息機制分析Handler、Looper、MessageQueue原始碼分析

1.前言 關於Handler訊息機制的部落格實際上是非常多的了。 之前也是看別人的部落格過來的,但是過了一段時間之後,一些細節也就忘了。 所以,就自己擼一篇,權當筆記,方便以後翻閱。 這篇文章主要是分析Handler訊息機制原理以及收集一些面試題來講解,

Handler Looper Message的原始碼分析

Handler Handler是用來分發和處理訊息的,通常我們建立Handler都是使用其無引數的構造方法 public Handler() { this(null, false); } 其內部呼叫的是2個引數的構造方法 public Handler(Ca

Android原始碼分析之訊息機制——Handler原始碼解析

 Android的訊息機制主要是指Handler的執行機制,Handler是Android訊息機制上層介面的實現,它的執行需要Message、MessageQueue和Looper的支撐,下面就來分別介紹它們的實現原理。 1、Message原始碼解析  首先來了解一下Messag

Android 屬性動畫原始碼分析 && Handler Epoll

根據屬性和Value 設定關鍵幀,然後通過AnimationHandler 呼叫 Chroeographor 去監聽VSYNC 訊號,收到Vsync訊號後,呼叫doFrame,最終回撥到AnimationHandler 設定當前時間 對應的 value。 https://www.jianshu.

Android原始碼分析——Looper,Messagequeue,Message,handler初始化及handler機制簡介

private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }直接上原始碼可見是個private的構造

Android訊息處理機制——Looper、Handler、Message 原始碼分析

原文地址:http://blog.csdn.net/wzy_1988/article/details/38346637 前言     雖然一直在做應用層開發,但是我們組是核心系統BSP,瞭解底層瞭解Android的執行機制還是很有必要的。就應用程式而言,Android系

handler原始碼分析

boolean enqueueMessage(Message msg, long when) { // 判斷有沒有 target if (msg.target == null) { throw new IllegalArgumentException

Handler機制之MessageQueue原始碼分析

介紹: 一個用於儲存(被Looper分發的)Message列表的低階類。與Native world的MessageQueue由緊密聯絡 MessageQueue類內部實現了兩個Interface,一個靜態內部類。 介面IdleHandler在訊息佇列沒有

Android Handler機制原始碼分析

1)Looper: 一個執行緒可以產生一個Looper物件,由它來管理此執行緒裡的MessageQueue(訊息佇列)。 2)Handler: 你可以構造Handler物件來與Looper溝通,以便push新訊息到MessageQueue裡;或者接收Looper從Messa

Handler訊息機制原始碼分析

public static final Looper myLooper() { return (Looper)sThreadLocal.get(); } 先來個Handler執行過程的總結:     1、 Looper.prepare()方法

Handler非同步訊息處理機制的原始碼分析

1. Handler非同步訊息處理機制 主執行緒不能進行耗時操作 (會發生ANR異常) 子執行緒不能更新UI的操作 (因為會報異常——>只有產生該控制元件的執行緒才能操作該控制元件。) 那麼 , 要在子執行緒請求資料,然後將資料傳送到主執行緒中更新