Android中的handler源碼解析(超詳細(xì))

Handler是什么?
Android中的異步消息處理機(jī)制,使用者可以在不阻塞UI線程的前提下輕松的實現(xiàn)消息管理和發(fā)送。

原理:

handler機(jī)制中包含4個關(guān)鍵類(下面對源碼的解析也是從這4個類入手),Message(消息),MessageQueue(消息隊列),Looper(輪詢器),Handler(消息發(fā)送和接收并處理),簡單一句話概括就是:handler負(fù)責(zé)發(fā)送message,將其加入到MessageQueue中,Looper不間斷的從MessageQueue中取出消息,并發(fā)送給對應(yīng)的handler實例去處理。

重點:源碼解析

有些同學(xué)不知道如何去看源碼,這就很尷尬了,往往想知道系統(tǒng)里面的源碼或者牛逼的開源項目是如何設(shè)計的,但是就是不知道如何入手,還有些同學(xué)覺得看源碼沒用,懂得怎么用不就行了嗎,非也,懂得如何用那只是招式,可能換個地方換種形式你就不認(rèn)識了,懂源碼,那是心法,知其所以然,才能千變?nèi)f化!

首先,我們使用的時候是這樣的:

Handler handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                 //消息處理
                  ·········
                }
            };
Message msg = Message.obtain();
handler.sendMessage(Message msg);

定義一個handler,并重寫了他的handleMessage()方法;我們來看看它的構(gòu)造方法:

public Handler() {
    this(null, false);
 }

public Handler(Callback callback) {
    this(callback, false);
}
 
 public Handler(Looper looper) {
    this(looper, null, false);
}

public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}

public Handler(Looper looper, Callback callback) {
     this(looper, callback, false);
 }

@hide
public Handler(boolean async) {
     this(null, async);
}

@hide
public Handler(Callback callback, boolean async) {
    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;
 }

@hide
public Handler(Looper looper, Callback callback, boolean async) {
     mLooper = looper;
     mQueue = looper.mQueue;
     mCallback = callback;
     mAsynchronous = async;
 }

蒙蔽了,這么多!但是注意,后面三個你都是沒法使用的,因為有@hide;
先看空參構(gòu)造,他直接調(diào)用了Handler(Callback callback, boolean async);看看里面做了什么:

  1. 獲取looper對象:Looper.myLooper(); 進(jìn)去可以看到 返回了,sThreadLocal.get();這個是什么玩意?ThreadLocal,他是一個容器,里面封裝了一個map,以當(dāng)前線程的ThreadLocal作為key,以你要存的值作為value,我們這里value就是looper對象,這個容器是專門用來保存線程所特有的變量的,起到了線程間隔離的作用,如果有人想知道,我專門開一篇博客來講。至于looper是怎么初始化的,客官莫急,下面會講。
  2. mQueue = mLooper.mQueue;拿到消息隊列,這是一個鏈表結(jié)構(gòu),注:一個線程對應(yīng)一個looper,一個looper同樣也只有一個queue;
  3. callback這個是handler里面的一個接口,在消息分發(fā)的時候會講到,默認(rèn)是null,mAsynchronous這個參數(shù)表示消息是否是異步消息,默認(rèn)是false;

接下來看Message.obtain():

public static Message obtain() {
        synchronized (sPoolSync) { //同步代碼塊
            if (sPool != null) {
                Message m = sPool;    //sPool是一個靜態(tài)的Message 引用
                sPool = m.next;       //next也是Message,但是他不是靜態(tài)的;
                m.next = null;
                m.flags = 0; 
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

obtain()的實現(xiàn)非常有意思,我們知道m(xù)essage其實是復(fù)用的,message中有一個方法:recycle(),大家可以去看一下,消息被處理完畢后會調(diào)用recycle()方法,將message還原,并將sPool這個賦值為this,也就是當(dāng)前自己的實例對象,如果sPool是null那么當(dāng)前沒有消息可以復(fù)用,直接new出來并返回,如果不是null,那么將當(dāng)前的sPool返回,那么這個next又是干什么的呢?代碼可見,sPool =m.next;將sPool重新賦值,這個m.next就是一條將要處理的消息,也就是說每一個msg里面都有對下一個將要處理的消息的引用,這樣,sPool被賦值了,下次再執(zhí)行obtain()的時候,sPool指向的其實是另外一個Message實例了,至于next如何賦值,稍后在MessageQueue中詳細(xì)解析。

Message拿到了,開始發(fā)消息吧,sendMessage(Message msg);

public final boolean sendMessage(Message msg){
    return sendMessageDelayed(msg, 0);   //直接調(diào)用sendMessageDelayed方法
}

通過源碼,一層一層往下找,發(fā)現(xiàn):sendMessage ——> sendMessageDelayed ——>sendMessageAtTime

  public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
  //此方法才是真正發(fā)消息
        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);
    }

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;      //重點:this表示的是當(dāng)前的handler實例,每個message都會記錄發(fā)送它的那個handler
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);      //這里調(diào)用了messageQueue的方法;
    }
重點:為什么msg要保存handler的引用呢?

我們都知道,handler機(jī)制消息處理,哪一個handler實例發(fā)出的消息,那么那一個handler就負(fù)責(zé)處理這個消息,這里的msg.target = this; 作用就在這,用來記住誰將msg發(fā)出來,等到處理的時候誰就來處理。

接著分析,handler最后調(diào)用了queue.enqueueMessage(msg, uptimeMillis);
我們來看看這個方法:(比較多,我精簡了一下,留下重要的部分)

    boolean enqueueMessage(Message msg, long when) {
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;//當(dāng)前將要被處理的msg
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                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.next = p; 
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

mMessages是即將要處理的message,先看第一個if最有一個條件,when<p.when,這個when是什么呢,它是一個時間毫秒值,when = 發(fā)送消息的那一刻的時間+delytime(延后的時間);表示這個msg將要在什么時刻可以被處理,when越小,越要被有先處理,所以,if判斷新來的msg是否優(yōu)先級比當(dāng)前即將要被處理的高,如果是,那么將此消息放在第一位(mMessages = msg),并且還做了另外一件事,msg.next = p; p下一個要處理的msg,else里面道理也是一樣的,for循環(huán)比較

重點又來了! Looper!
上面留下了一個問題,Looper是怎么初始化的呢,app中的通信,UI的刷新,都需要依賴handler,那么,我們就猜想,Looper在app啟動的時候就已經(jīng)開始創(chuàng)建并初始化了,那么我們?nèi)ピ创a中找 ActivityThread main()方法 ;

public static void main(String[] args) {
        ````````
        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"));
        }
        Looper.loop();  //還有這里
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

果然,在主線程啟動的時候就已經(jīng)啟動了Looper并調(diào)用了,prepareMainLooper()和loop();接著去looper里面看看:

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) {
  //判斷l(xiāng)ooper是否是null如果是,就創(chuàng)建,并將其存到ThreadLocal中,上面說的handler中的looper就是從ThreadLocal中取出來的;
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

    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;

        Binder.clearCallingIdentity();   //這里大家不用管,我個人理解是對進(jìn)程的校驗,有知道的同學(xué)也可以留言告訴我。
        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;
            }

            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            try {
                msg.target.dispatchMessage(msg);    //分發(fā)消息
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }
            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();      //消息的回收
        }
    }

三個方法,prepareMainLooper()其實內(nèi)部調(diào)用了prepare(false);這個boolean參數(shù)是什么意思呢,意識就是不允許messageQueue退出,這個參數(shù)會在構(gòu)建Queue的時候傳遞進(jìn)去,因為主線程的消息隊列只有在應(yīng)用退出的時候才允許退出,否則······沒有否則,消息機(jī)制都沒了,還怎么玩!
prepare()方法創(chuàng)建了一個looper,但是looper并沒有啟動,啟動的方法是下面的loop();loop()有一個for(;;),死循環(huán),里面做的工作就是一直取消息,并處理,然后recycleUnchecked()復(fù)用。這個時候looper就啟動起來了,只要你的應(yīng)用還在運行,他就會一直在。looper拿到消息后會通過msg.target.dispatchMessage(msg); 將消息發(fā)出來給handler處理,這里的msg.target不就是我們發(fā)消息的時候初始化的handler嗎?(篇幅有點長,不記得可以往上翻)

繼續(xù)看,又到重點了

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

通過一系列判斷,來處理消息,如下:

  1. 判斷msg.callback是不是null,如果不是,那么就給這個callback處理,這個callback是message中的一個Runnable;Message.obtain()其實是有其他參數(shù)的方法的,其中有一個是obtain(Handler h, Runnable callback);如果你用了這個,那么消息就會在你實現(xiàn)的Runnable中接收到處理的回調(diào);
  2. 第二個是判斷handler內(nèi)部的callback是不是null,如果不是null,就讓他去處理,這里的Callback可不是Runnable了,他是一個interface,里面定義了一個handleMessage(Message msg);方法,這個怎么實現(xiàn)呢?handler類里同樣有Handler(Callback callback)構(gòu)造方法
  3. 最后才輪到handler類里的方法handleMessage來處理消息。也就是我們在開始寫的那個簡單的handler使用方法。
結(jié)語:本文從使用過程為主線,來分析Handler原理,文中含有大量篇幅的源碼,也比較詳細(xì),網(wǎng)上其他的博客也很多,但是講的都比較粗糙,講解的流程也不容易理解,無法串聯(lián)起來,希望通過這篇博客能讓大家完全理解Handler機(jī)制,若有錯誤的地方,歡迎指正!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容