最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android Handle原理(Looper,Handler和Message)三者關(guān)系案例詳解

 更新時(shí)間:2021年08月27日 21:58:46   作者:安輝就是我  
這篇文章主要介紹了Android Handle原理(Looper,Handler和Message三者關(guān)系案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下

介紹

前面的內(nèi)容對(duì)Handler做了介紹,也講解了如何使用handler,但是我們并不知道他的實(shí)現(xiàn)原理。本文從源碼的角度來分析如何實(shí)現(xiàn)的。

首先我們得知道Handler,Looper,Message Queue三者之間的關(guān)系

- Handler封裝了消息的發(fā)送,也負(fù)責(zé)接收消。內(nèi)部會(huì)跟Looper關(guān)聯(lián)。
- Looper 消息封裝的載,內(nèi)部包含了MessageQueue,負(fù)責(zé)從MessageQueue取出消息,然后交給Handler處理
- MessageQueue 就是一個(gè)消息隊(duì)列,負(fù)責(zé)存儲(chǔ)消息,有消息過來就存儲(chǔ)起來,Looper會(huì)循環(huán)的從MessageQueue讀取消息。

源碼分析

當(dāng)我們new一個(gè)Handler對(duì)象的時(shí)候,看看他的構(gòu)造方法里面做了什么.

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;
}

從源碼中我們看到他會(huì)調(diào)用Looper.myLooper方法獲取一個(gè)Looper對(duì)象,然后從Looper對(duì)象獲取到MessageQueue對(duì)象。

Looper myLooper()

跟進(jìn)去看看Looper.myLooper()方法做了什么。這是一個(gè)靜態(tài)方法,可以類名.方法名直接調(diào)用。

public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

這個(gè)方法里面就一行代碼,從sThreadLocal中獲取一個(gè)Looper對(duì)象,sThreadLocal是一個(gè)ThreadLocal對(duì)象,可以在一個(gè)線程中存儲(chǔ)變量。底層是ThreadLocalMap,既然是Map類型那肯定得先set一個(gè)Looper對(duì)象,然后我們才能從sThreadLocal對(duì)象里面get一個(gè)Looper對(duì)象。

ActivityThread main()

說到這里得給大家介紹一個(gè)新的類ActivityThread,ActivityThread類是Android APP進(jìn)程的初始類,它的main函數(shù)是這個(gè)APP進(jìn)程的入口。我們看看這個(gè)main函數(shù)干了什么事情。

public static final void main(String[] args) {
        ------
        Looper.prepareMainLooper();
        if (sMainThreadHandler == null) {
            sMainThreadHandler = new Handler();
        }

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

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

        Looper.loop();
        -----
}

在第二行代碼調(diào)用Looper.prepareMainLooper()方法,第13行調(diào)用了Looper.loop()方法。

Looper prepareMainLooper()

繼續(xù)跟進(jìn)Looper.prepareMainLooper()方法,在這個(gè)方法中第一行代碼調(diào)用了內(nèi)部的prepare方法。prepareMainLooper有點(diǎn)像單例模式中的getInstance方法,只不過getInstance會(huì)當(dāng)時(shí)返回一個(gè)對(duì)象,而prepareMainLooper會(huì)新建一個(gè)Looper對(duì)象,存儲(chǔ)在sThreadLocal中。

public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

Looper prepare()

繼續(xù)跟進(jìn)prepare方法,看第5行代碼,新建了一個(gè)Looper對(duì)象,調(diào)用sThreadLocal.set方法把Looper對(duì)象保存起來。看到這里我想聰明的你們肯定明白了為什么new Handler對(duì)象的時(shí)候調(diào)用Looper.myLooper()方法能從sThreadLocal對(duì)象中取到Looper對(duì)象。

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));
}

Looper 構(gòu)造方法

文章開頭我們就講到Looper內(nèi)部包含了MessageQueue,其實(shí)就是在new Looper對(duì)象的時(shí)候就new了一個(gè)MessageQueue對(duì)象。

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

Looper loop()

ActivityThread類main方法中調(diào)用了Looper的兩個(gè)方法,前面我們解釋了prepareMainLooper(),現(xiàn)在來看第二個(gè)方法loop()。

public static void loop() {
    final Looper me = myLooper();//獲取Looper對(duì)象
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;//從Looper對(duì)象獲取MessageQueue對(duì)象

    // 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 (;;) {//死循環(huán)  一直從MessageQueue中遍歷消息
        Message msg = queue.next(); // might block
        if (msg == null) {
            return;
        }

        // This must be in a local variable, in case a UI event sets the logger
        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 {
            //調(diào)用handler的dispatchMessage方法,把消息交給handler處理
            msg.target.dispatchMessage(msg);
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }

        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();
    }
}

這個(gè)方法的代碼呢比較多。我都給代碼加上了注釋。其實(shí)就是一個(gè)死循環(huán),一直會(huì)從MessageQueue中取消息,如果取到了消息呢,會(huì)執(zhí)行msg.target.dispatchMessage(msg)這行代碼,msg.target就是handler,其實(shí)就是調(diào)用handler的dispatchMessage方法,然后把從MessageQueue中取到的message傳入進(jìn)去。

Handler dispatchMessage()

public void dispatchMessage(Message msg) {
    //如果callback不為空,說明發(fā)送消息的時(shí)候是post一個(gè)Runnable對(duì)象
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {//這個(gè)是用來攔截消息的
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);//最終調(diào)用我們重寫的handleMessage方法
    }
}

這個(gè)方法對(duì)消息做最后處理,如果是post類型調(diào)用handleCallback方法處理,如果是sendMessage發(fā)送的消息。看我們有沒有攔截消息,如果沒有最終調(diào)用handleMessage方法處理。

Handler handleCallback()

看到這里我們知道為什么post一個(gè)Runnable對(duì)象,run方法執(zhí)行的代碼在主線程了吧,因?yàn)榈讓痈揪蜎]有開啟線程,就只是調(diào)用了run方法而已。

private static void handleCallback(Message message) {
    message.callback.run();
}

前面我們從創(chuàng)建handler對(duì)象開始,以及創(chuàng)建Looper,創(chuàng)建MessageQueue的整個(gè)流程,現(xiàn)在來分析下,當(dāng)我們調(diào)用post以及sendMessage方法時(shí),怎么把Message添加到MessageQueue。

Handler post()

調(diào)用了getPostMessage方法,把Runnable傳遞進(jìn)去。

public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

Handler getPostMessage()

首先調(diào)用Message.obtain()方法,取出一個(gè)Message對(duì)象,這個(gè)方法之前有講過,然后把Runnable對(duì)象賦值了Message對(duì)象的callback屬性??吹竭@里我們也明白了dispatchMessage方法為什么要先判斷callback是否為空了吧。

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

Handler enqueueMessage()

在post方法里面調(diào)用了sendMessageDelayed方法,其實(shí)最終調(diào)用的是enqueueMessage方法,所以我這里就直接看enqueueMessage方法源碼。第一行代碼就把handler自己賦值給messgae對(duì)象的target屬性。然后調(diào)用MessageQueue的enqueueMessage方法把當(dāng)前的Messgae添加進(jìn)去。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

總結(jié)

總結(jié):handler負(fù)責(zé)發(fā)送消息,Looper負(fù)責(zé)接收Handler發(fā)送的消息,并直接把消息回傳給Handler自己。MessageQueue就是一個(gè)存儲(chǔ)消息的容器。

到此這篇關(guān)于Android Handle原理(Looper,Handler和Message三者關(guān)系案例詳解的文章就介紹到這了,更多相關(guān)Android Handle原理(Looper,Handler和Message三者關(guān)系內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android 調(diào)用發(fā)送短信的方法

    Android 調(diào)用發(fā)送短信的方法

    這篇文章主要介紹了Android 調(diào)用發(fā)送短信的方法的相關(guān)資料,主要實(shí)現(xiàn)Android 調(diào)用短信的使用,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • Flutter開發(fā)之Widget自定義總結(jié)

    Flutter開發(fā)之Widget自定義總結(jié)

    這篇文章主要給大家介紹了關(guān)于Flutter開發(fā)中Widget自定義的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Flutter具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • Android?貝塞爾曲線繪制一個(gè)波浪球

    Android?貝塞爾曲線繪制一個(gè)波浪球

    當(dāng)?flutter?的現(xiàn)有組件無法滿足產(chǎn)品要求的UI效果時(shí),我們就需要通過自繪組件的方式來進(jìn)行實(shí)現(xiàn)了。本文章就來介紹如何用貝塞爾曲線實(shí)現(xiàn)一個(gè)帶文本的波浪球,需要的可以參考一下
    2022-05-05
  • android 修改launcher行數(shù)和列數(shù)的方法

    android 修改launcher行數(shù)和列數(shù)的方法

    這篇文章主要介紹了android 修改launcher行數(shù)和列數(shù)的方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-07-07
  • Android?Jetpack庫(kù)剖析之LiveData組件篇

    Android?Jetpack庫(kù)剖析之LiveData組件篇

    LiveData是Jetpack組件的一部分,更多的時(shí)候是搭配ViewModel來使用,相對(duì)于Observable,LiveData的最大優(yōu)勢(shì)是其具有生命感知的,換句話說,LiveData可以保證只有在組件( Activity、Fragment、Service)處于活動(dòng)生命周期狀態(tài)的時(shí)候才會(huì)更新數(shù)據(jù)
    2022-07-07
  • Android下的CMD命令之關(guān)機(jī)重啟及重啟recovery

    Android下的CMD命令之關(guān)機(jī)重啟及重啟recovery

    這篇文章主要介紹了Android下的CMD命令之關(guān)機(jī)重啟及重啟recovery,本文涉及到cmd命令知識(shí)點(diǎn),通過了解cmd命令就可以很容易的實(shí)現(xiàn)此功能了,需要的朋友一起看看吧
    2016-08-08
  • Android 實(shí)現(xiàn)數(shù)字九宮格軟鍵盤

    Android 實(shí)現(xiàn)數(shù)字九宮格軟鍵盤

    最近項(xiàng)目在對(duì)接美團(tuán)外賣功能,實(shí)現(xiàn)外面小哥憑取貨碼取貨,對(duì)接完功能后用戶反饋彈出的軟鍵盤很難輸入,數(shù)字太小了,于是便著手優(yōu)化一下
    2021-05-05
  • viewPager+fragment刷新緩存fragment的方法

    viewPager+fragment刷新緩存fragment的方法

    這篇文章主要介紹了viewPager+fragment刷新緩存fragment的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-03-03
  • Android實(shí)現(xiàn)讀寫SD卡

    Android實(shí)現(xiàn)讀寫SD卡

    本文給大家分享的是Android實(shí)現(xiàn)讀寫SD卡的代碼以及使用的時(shí)候的注意事項(xiàng),非常的實(shí)用,有需要的小伙伴可以參考下。
    2016-05-05
  • Android自定義圓角柱狀圖

    Android自定義圓角柱狀圖

    這篇文章主要為大家詳細(xì)介紹了Android自定義圓角柱狀圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02

最新評(píng)論

班戈县| 潞西市| 定日县| 日土县| 绵阳市| 英吉沙县| 永嘉县| 湖南省| 灯塔市| 赤城县| 博罗县| 射洪县| 沾化县| 外汇| 教育| 微博| 雅江县| 遂宁市| 马龙县| 鹿邑县| 略阳县| 宕昌县| 嘉鱼县| 海晏县| 平度市| 宜君县| 吉木萨尔县| 定襄县| 墨竹工卡县| 弥勒县| 凭祥市| 郸城县| 望江县| 临汾市| 乌鲁木齐县| 黄山市| 大宁县| 太仆寺旗| 通道| 巴青县| 金阳县|