日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Android异步消息处理机制完全解析,带你从源码的角度彻底理解

發(fā)布時(shí)間:2025/6/15 Android 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android异步消息处理机制完全解析,带你从源码的角度彻底理解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/guolin_blog/article/details/9991569

之前也是由于周末通宵看TI3比賽,一直沒(méi)找到時(shí)間寫(xiě)博客,導(dǎo)致已經(jīng)有好久沒(méi)更新了。慚愧!后面還會(huì)恢復(fù)進(jìn)度,盡量保證每周都寫(xiě)吧。這里也是先恭喜一下來(lái)自瑞典的Alliance戰(zhàn)隊(duì)奪得了TI3的冠軍,希望明年中國(guó)戰(zhàn)隊(duì)能夠虎起!

開(kāi)始進(jìn)入正題,我們都知道,Android UI是線程不安全的,如果在子線程中嘗試進(jìn)行UI操作,程序就有可能會(huì)崩潰。相信大家在日常的工作當(dāng)中都會(huì)經(jīng)常遇到這個(gè)問(wèn)題,解決的方案應(yīng)該也是早已爛熟于心,即創(chuàng)建一個(gè)Message對(duì)象,然后借助Handler發(fā)送出去,之后在Handler的handleMessage()方法中獲得剛才發(fā)送的Message對(duì)象,然后在這里進(jìn)行UI操作就不會(huì)再出現(xiàn)崩潰了。

這種處理方式被稱為異步消息處理線程,雖然我相信大家都會(huì)用,可是你知道它背后的原理是什么樣的嗎?今天我們就來(lái)一起深入探究一下Handler和Message背后的秘密。

首先來(lái)看一下如何創(chuàng)建Handler對(duì)象。你可能會(huì)覺(jué)得挺納悶的,創(chuàng)建Handler有什么好看的呢,直接new一下不就行了?確實(shí),不過(guò)即使只是簡(jiǎn)單new一下,還是有不少地方需要注意的,我們嘗試在程序中創(chuàng)建兩個(gè)Handler對(duì)象,一個(gè)在主線程中創(chuàng)建,一個(gè)在子線程中創(chuàng)建,代碼如下所示:

[java] view plaincopy
  • public?class?MainActivity?extends?Activity?{??
  • ??????
  • ????private?Handler?handler1;??
  • ??????
  • ????private?Handler?handler2;??
  • ??
  • ????@Override??
  • ????protected?void?onCreate(Bundle?savedInstanceState)?{??
  • ????????super.onCreate(savedInstanceState);??
  • ????????setContentView(R.layout.activity_main);??
  • ????????handler1?=?new?Handler();??
  • ????????new?Thread(new?Runnable()?{??
  • ????????????@Override??
  • ????????????public?void?run()?{??
  • ????????????????handler2?=?new?Handler();??
  • ????????????}??
  • ????????}).start();??
  • ????}??
  • ??
  • }??
  • 如果現(xiàn)在運(yùn)行一下程序,你會(huì)發(fā)現(xiàn),在子線程中創(chuàng)建的Handler是會(huì)導(dǎo)致程序崩潰的,提示的錯(cuò)誤信息為?Can't create handler inside thread that has not called Looper.prepare() 。說(shuō)是不能在沒(méi)有調(diào)用Looper.prepare() 的線程中創(chuàng)建Handler,那我們嘗試在子線程中先調(diào)用一下Looper.prepare()呢,代碼如下所示: [java] view plaincopy
  • new?Thread(new?Runnable()?{??
  • ????@Override??
  • ????public?void?run()?{??
  • ????????Looper.prepare();??
  • ????????handler2?=?new?Handler();??
  • ????}??
  • }).start();??
  • 果然這樣就不會(huì)崩潰了,不過(guò)只滿足于此顯然是不夠的,我們來(lái)看下Handler的源碼,搞清楚為什么不調(diào)用Looper.prepare()就不行呢。Handler的無(wú)參構(gòu)造函數(shù)如下所示: [java] view plaincopy
  • public?Handler()?{??
  • ????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?=?null;??
  • }??
  • 可以看到,在第10行調(diào)用了Looper.myLooper()方法獲取了一個(gè)Looper對(duì)象,如果Looper對(duì)象為空,則會(huì)拋出一個(gè)運(yùn)行時(shí)異常,提示的錯(cuò)誤正是?Can't create handler inside thread that has not called Looper.prepare()!那什么時(shí)候Looper對(duì)象才可能為空呢?這就要看看Looper.myLooper()中的代碼了,如下所示: [java] view plaincopy
  • public?static?final?Looper?myLooper()?{??
  • ????return?(Looper)sThreadLocal.get();??
  • }??
  • 這個(gè)方法非常簡(jiǎn)單,就是從sThreadLocal對(duì)象中取出Looper。如果sThreadLocal中有Looper存在就返回Looper,如果沒(méi)有Looper存在自然就返回空了。因此你可以想象得到是在哪里給sThreadLocal設(shè)置Looper了吧,當(dāng)然是Looper.prepare()方法!我們來(lái)看下它的源碼: [java] view plaincopy
  • public?static?final?void?prepare()?{??
  • ????if?(sThreadLocal.get()?!=?null)?{??
  • ????????throw?new?RuntimeException("Only?one?Looper?may?be?created?per?thread");??
  • ????}??
  • ????sThreadLocal.set(new?Looper());??
  • }??
  • 可以看到,首先判斷sThreadLocal中是否已經(jīng)存在Looper了,如果還沒(méi)有則創(chuàng)建一個(gè)新的Looper設(shè)置進(jìn)去。這樣也就完全解釋了為什么我們要先調(diào)用Looper.prepare()方法,才能創(chuàng)建Handler對(duì)象。同時(shí)也可以看出每個(gè)線程中最多只會(huì)有一個(gè)Looper對(duì)象。

    咦?不對(duì)呀!主線程中的Handler也沒(méi)有調(diào)用Looper.prepare()方法,為什么就沒(méi)有崩潰呢?細(xì)心的朋友我相信都已經(jīng)發(fā)現(xiàn)了這一點(diǎn),這是由于在程序啟動(dòng)的時(shí)候,系統(tǒng)已經(jīng)幫我們自動(dòng)調(diào)用了Looper.prepare()方法。查看ActivityThread中的main()方法,代碼如下所示:

    [java] view plaincopy
  • public?static?void?main(String[]?args)?{??
  • ????SamplingProfilerIntegration.start();??
  • ????CloseGuard.setEnabled(false);??
  • ????Environment.initForCurrentUser();??
  • ????EventLogger.setReporter(new?EventLoggingReporter());??
  • ????Process.setArgV0("<pre-initialized>");??
  • ????Looper.prepareMainLooper();??
  • ????ActivityThread?thread?=?new?ActivityThread();??
  • ????thread.attach(false);??
  • ????if?(sMainThreadHandler?==?null)?{??
  • ????????sMainThreadHandler?=?thread.getHandler();??
  • ????}??
  • ????AsyncTask.init();??
  • ????if?(false)?{??
  • ????????Looper.myLooper().setMessageLogging(new?LogPrinter(Log.DEBUG,?"ActivityThread"));??
  • ????}??
  • ????Looper.loop();??
  • ????throw?new?RuntimeException("Main?thread?loop?unexpectedly?exited");??
  • }??
  • 可以看到,在第7行調(diào)用了Looper.prepareMainLooper()方法,而這個(gè)方法又會(huì)再去調(diào)用Looper.prepare()方法,代碼如下所示: [java] view plaincopy
  • public?static?final?void?prepareMainLooper()?{??
  • ????prepare();??
  • ????setMainLooper(myLooper());??
  • ????if?(Process.supportsProcesses())?{??
  • ????????myLooper().mQueue.mQuitAllowed?=?false;??
  • ????}??
  • }??
  • 因此我們應(yīng)用程序的主線程中會(huì)始終存在一個(gè)Looper對(duì)象,從而不需要再手動(dòng)去調(diào)用Looper.prepare()方法了。

    這樣基本就將Handler的創(chuàng)建過(guò)程完全搞明白了,總結(jié)一下就是在主線程中可以直接創(chuàng)建Handler對(duì)象,而在子線程中需要先調(diào)用Looper.prepare()才能創(chuàng)建Handler對(duì)象。

    看完了如何創(chuàng)建Handler之后,接下來(lái)我們看一下如何發(fā)送消息,這個(gè)流程相信大家也已經(jīng)非常熟悉了,new出一個(gè)Message對(duì)象,然后可以使用setData()方法或arg參數(shù)等方式為消息攜帶一些數(shù)據(jù),再借助Handler將消息發(fā)送出去就可以了,示例代碼如下:

    [java] view plaincopy
  • new?Thread(new?Runnable()?{??
  • ????@Override??
  • ????public?void?run()?{??
  • ????????Message?message?=?new?Message();??
  • ????????message.arg1?=?1;??
  • ????????Bundle?bundle?=?new?Bundle();??
  • ????????bundle.putString("data",?"data");??
  • ????????message.setData(bundle);??
  • ????????handler.sendMessage(message);??
  • ????}??
  • }).start();??
  • 可是這里Handler到底是把Message發(fā)送到哪里去了呢?為什么之后又可以在Handler的handleMessage()方法中重新得到這條Message呢?看來(lái)又需要通過(guò)閱讀源碼才能解除我們心中的疑惑了,Handler中提供了很多個(gè)發(fā)送消息的方法,其中除了sendMessageAtFrontOfQueue()方法之外,其它的發(fā)送消息方法最終都會(huì)輾轉(zhuǎn)調(diào)用到sendMessageAtTime()方法中,這個(gè)方法的源碼如下所示:

    [java] view plaincopy
  • public?boolean?sendMessageAtTime(Message?msg,?long?uptimeMillis)??
  • {??
  • ????boolean?sent?=?false;??
  • ????MessageQueue?queue?=?mQueue;??
  • ????if?(queue?!=?null)?{??
  • ????????msg.target?=?this;??
  • ????????sent?=?queue.enqueueMessage(msg,?uptimeMillis);??
  • ????}??
  • ????else?{??
  • ????????RuntimeException?e?=?new?RuntimeException(??
  • ????????????this?+?"?sendMessageAtTime()?called?with?no?mQueue");??
  • ????????Log.w("Looper",?e.getMessage(),?e);??
  • ????}??
  • ????return?sent;??
  • }??
  • sendMessageAtTime()方法接收兩個(gè)參數(shù),其中msg參數(shù)就是我們發(fā)送的Message對(duì)象,而uptimeMillis參數(shù)則表示發(fā)送消息的時(shí)間,它的值等于自系統(tǒng)開(kāi)機(jī)到當(dāng)前時(shí)間的毫秒數(shù)再加上延遲時(shí)間,如果你調(diào)用的不是sendMessageDelayed()方法,延遲時(shí)間就為0,然后將這兩個(gè)參數(shù)都傳遞到MessageQueue的enqueueMessage()方法中。這個(gè)MessageQueue又是什么東西呢?其實(shí)從名字上就可以看出了,它是一個(gè)消息隊(duì)列,用于將所有收到的消息以隊(duì)列的形式進(jìn)行排列,并提供入隊(duì)和出隊(duì)的方法。這個(gè)類是在Looper的構(gòu)造函數(shù)中創(chuàng)建的,因此一個(gè)Looper也就對(duì)應(yīng)了一個(gè)MessageQueue。

    那么enqueueMessage()方法毫無(wú)疑問(wèn)就是入隊(duì)的方法了,我們來(lái)看下這個(gè)方法的源碼:

    [java] view plaincopy
  • final?boolean?enqueueMessage(Message?msg,?long?when)?{??
  • ????if?(msg.when?!=?0)?{??
  • ????????throw?new?AndroidRuntimeException(msg?+?"?This?message?is?already?in?use.");??
  • ????}??
  • ????if?(msg.target?==?null?&&?!mQuitAllowed)?{??
  • ????????throw?new?RuntimeException("Main?thread?not?allowed?to?quit");??
  • ????}??
  • ????synchronized?(this)?{??
  • ????????if?(mQuiting)?{??
  • ????????????RuntimeException?e?=?new?RuntimeException(msg.target?+?"?sending?message?to?a?Handler?on?a?dead?thread");??
  • ????????????Log.w("MessageQueue",?e.getMessage(),?e);??
  • ????????????return?false;??
  • ????????}?else?if?(msg.target?==?null)?{??
  • ????????????mQuiting?=?true;??
  • ????????}??
  • ????????msg.when?=?when;??
  • ????????Message?p?=?mMessages;??
  • ????????if?(p?==?null?||?when?==?0?||?when?<?p.when)?{??
  • ????????????msg.next?=?p;??
  • ????????????mMessages?=?msg;??
  • ????????????this.notify();??
  • ????????}?else?{??
  • ????????????Message?prev?=?null;??
  • ????????????while?(p?!=?null?&&?p.when?<=?when)?{??
  • ????????????????prev?=?p;??
  • ????????????????p?=?p.next;??
  • ????????????}??
  • ????????????msg.next?=?prev.next;??
  • ????????????prev.next?=?msg;??
  • ????????????this.notify();??
  • ????????}??
  • ????}??
  • ????return?true;??
  • }??
  • 首先你要知道,MessageQueue并沒(méi)有使用一個(gè)集合把所有的消息都保存起來(lái),它只使用了一個(gè)mMessages對(duì)象表示當(dāng)前待處理的消息。然后觀察上面的代碼的16~31行我們就可以看出,所謂的入隊(duì)其實(shí)就是將所有的消息按時(shí)間來(lái)進(jìn)行排序,這個(gè)時(shí)間當(dāng)然就是我們剛才介紹的uptimeMillis參數(shù)。具體的操作方法就根據(jù)時(shí)間的順序調(diào)用msg.next,從而為每一個(gè)消息指定它的下一個(gè)消息是什么。當(dāng)然如果你是通過(guò)sendMessageAtFrontOfQueue()方法來(lái)發(fā)送消息的,它也會(huì)調(diào)用enqueueMessage()來(lái)讓消息入隊(duì),只不過(guò)時(shí)間為0,這時(shí)會(huì)把mMessages賦值為新入隊(duì)的這條消息,然后將這條消息的next指定為剛才的mMessages,這樣也就完成了添加消息到隊(duì)列頭部的操作。
    現(xiàn)在入隊(duì)操作我們就已經(jīng)看明白了,那出隊(duì)操作是在哪里進(jìn)行的呢?這個(gè)就需要看一看Looper.loop()方法的源碼了,如下所示: [java] view plaincopy
  • public?static?final?void?loop()?{??
  • ????Looper?me?=?myLooper();??
  • ????MessageQueue?queue?=?me.mQueue;??
  • ????while?(true)?{??
  • ????????Message?msg?=?queue.next();?//?might?block??
  • ????????if?(msg?!=?null)?{??
  • ????????????if?(msg.target?==?null)?{??
  • ????????????????return;??
  • ????????????}??
  • ????????????if?(me.mLogging!=?null)?me.mLogging.println(??
  • ????????????????????">>>>>?Dispatching?to?"?+?msg.target?+?"?"??
  • ????????????????????+?msg.callback?+?":?"?+?msg.what??
  • ????????????????????);??
  • ????????????msg.target.dispatchMessage(msg);??
  • ????????????if?(me.mLogging!=?null)?me.mLogging.println(??
  • ????????????????????"<<<<<?Finished?to????"?+?msg.target?+?"?"??
  • ????????????????????+?msg.callback);??
  • ????????????msg.recycle();??
  • ????????}??
  • ????}??
  • }??
  • 可以看到,這個(gè)方法從第4行開(kāi)始,進(jìn)入了一個(gè)死循環(huán),然后不斷地調(diào)用的MessageQueue的next()方法,我想你已經(jīng)猜到了,這個(gè)next()方法就是消息隊(duì)列的出隊(duì)方法。不過(guò)由于這個(gè)方法的代碼稍微有點(diǎn)長(zhǎng),我就不貼出來(lái)了,它的簡(jiǎn)單邏輯就是如果當(dāng)前MessageQueue中存在mMessages(即待處理消息),就將這個(gè)消息出隊(duì),然后讓下一條消息成為mMessages,否則就進(jìn)入一個(gè)阻塞狀態(tài),一直等到有新的消息入隊(duì)。繼續(xù)看loop()方法的第14行,每當(dāng)有一個(gè)消息出隊(duì),就將它傳遞到msg.target的dispatchMessage()方法中,那這里msg.target又是什么呢?其實(shí)就是Handler啦,你觀察一下上面sendMessageAtTime()方法的第6行就可以看出來(lái)了。接下來(lái)當(dāng)然就要看一看Handler中dispatchMessage()方法的源碼了,如下所示: [java] view plaincopy
  • public?void?dispatchMessage(Message?msg)?{??
  • ????if?(msg.callback?!=?null)?{??
  • ????????handleCallback(msg);??
  • ????}?else?{??
  • ????????if?(mCallback?!=?null)?{??
  • ????????????if?(mCallback.handleMessage(msg))?{??
  • ????????????????return;??
  • ????????????}??
  • ????????}??
  • ????????handleMessage(msg);??
  • ????}??
  • }??
  • 在第5行進(jìn)行判斷,如果mCallback不為空,則調(diào)用mCallback的handleMessage()方法,否則直接調(diào)用Handler的handleMessage()方法,并將消息對(duì)象作為參數(shù)傳遞過(guò)去。這樣我相信大家就都明白了為什么handleMessage()方法中可以獲取到之前發(fā)送的消息了吧!

    因此,一個(gè)最標(biāo)準(zhǔn)的異步消息處理線程的寫(xiě)法應(yīng)該是這樣:

    [java] view plaincopy
  • class?LooperThread?extends?Thread?{??
  • ??????public?Handler?mHandler;??
  • ??
  • ??????public?void?run()?{??
  • ??????????Looper.prepare();??
  • ??
  • ??????????mHandler?=?new?Handler()?{??
  • ??????????????public?void?handleMessage(Message?msg)?{??
  • ??????????????????//?process?incoming?messages?here??
  • ??????????????}??
  • ??????????};??
  • ??
  • ??????????Looper.loop();??
  • ??????}??
  • ??}??
  • 當(dāng)然,這段代碼是從Android官方文檔上復(fù)制的,不過(guò)大家現(xiàn)在再來(lái)看這段代碼,是不是理解的更加深刻了?

    那么我們還是要來(lái)繼續(xù)分析一下,為什么使用異步消息處理的方式就可以對(duì)UI進(jìn)行操作了呢?這是由于Handler總是依附于創(chuàng)建時(shí)所在的線程,比如我們的Handler是在主線程中創(chuàng)建的,而在子線程中又無(wú)法直接對(duì)UI進(jìn)行操作,于是我們就通過(guò)一系列的發(fā)送消息、入隊(duì)、出隊(duì)等環(huán)節(jié),最后調(diào)用到了Handler的handleMessage()方法中,這時(shí)的handleMessage()方法已經(jīng)是在主線程中運(yùn)行的,因而我們當(dāng)然可以在這里進(jìn)行UI操作了。整個(gè)異步消息處理流程的示意圖如下圖所示:


    另外除了發(fā)送消息之外,我們還有以下幾種方法可以在子線程中進(jìn)行UI操作:

    1. Handler的post()方法

    2. View的post()方法

    3. Activity的runOnUiThread()方法

    我們先來(lái)看下Handler中的post()方法,代碼如下所示:

    [java] view plaincopy
  • public?final?boolean?post(Runnable?r)??
  • {??
  • ???return??sendMessageDelayed(getPostMessage(r),?0);??
  • }??
  • 原來(lái)這里還是調(diào)用了sendMessageDelayed()方法去發(fā)送一條消息啊,并且還使用了getPostMessage()方法將Runnable對(duì)象轉(zhuǎn)換成了一條消息,我們來(lái)看下這個(gè)方法的源碼: [java] view plaincopy
  • private?final?Message?getPostMessage(Runnable?r)?{??
  • ????Message?m?=?Message.obtain();??
  • ????m.callback?=?r;??
  • ????return?m;??
  • }??
  • 在這個(gè)方法中將消息的callback字段的值指定為傳入的Runnable對(duì)象。咦?這個(gè)callback字段看起來(lái)有些眼熟啊,喔!在Handler的dispatchMessage()方法中原來(lái)有做一個(gè)檢查,如果Message的callback等于null才會(huì)去調(diào)用handleMessage()方法,否則就調(diào)用handleCallback()方法。那我們快來(lái)看下handleCallback()方法中的代碼吧: [java] view plaincopy
  • private?final?void?handleCallback(Message?message)?{??
  • ????message.callback.run();??
  • }??
  • 也太簡(jiǎn)單了!竟然就是直接調(diào)用了一開(kāi)始傳入的Runnable對(duì)象的run()方法。因此在子線程中通過(guò)Handler的post()方法進(jìn)行UI操作就可以這么寫(xiě): [java] view plaincopy
  • public?class?MainActivity?extends?Activity?{??
  • ??
  • ????private?Handler?handler;??
  • ??
  • ????@Override??
  • ????protected?void?onCreate(Bundle?savedInstanceState)?{??
  • ????????super.onCreate(savedInstanceState);??
  • ????????setContentView(R.layout.activity_main);??
  • ????????handler?=?new?Handler();??
  • ????????new?Thread(new?Runnable()?{??
  • ????????????@Override??
  • ????????????public?void?run()?{??
  • ????????????????handler.post(new?Runnable()?{??
  • ????????????????????@Override??
  • ????????????????????public?void?run()?{??
  • ????????????????????????//?在這里進(jìn)行UI操作??
  • ????????????????????}??
  • ????????????????});??
  • ????????????}??
  • ????????}).start();??
  • ????}??
  • }??
  • 雖然寫(xiě)法上相差很多,但是原理是完全一樣的,我們?cè)赗unnable對(duì)象的run()方法里更新UI,效果完全等同于在handleMessage()方法中更新UI。

    然后再來(lái)看一下View中的post()方法,代碼如下所示:

    [java] view plaincopy
  • public?boolean?post(Runnable?action)?{??
  • ????Handler?handler;??
  • ????if?(mAttachInfo?!=?null)?{??
  • ????????handler?=?mAttachInfo.mHandler;??
  • ????}?else?{??
  • ????????ViewRoot.getRunQueue().post(action);??
  • ????????return?true;??
  • ????}??
  • ????return?handler.post(action);??
  • }??
  • 原來(lái)就是調(diào)用了Handler中的post()方法,我相信已經(jīng)沒(méi)有什么必要再做解釋了。

    最后再來(lái)看一下Activity中的runOnUiThread()方法,代碼如下所示:

    [java] view plaincopy
  • public?final?void?runOnUiThread(Runnable?action)?{??
  • ????if?(Thread.currentThread()?!=?mUiThread)?{??
  • ????????mHandler.post(action);??
  • ????}?else?{??
  • ????????action.run();??
  • ????}??
  • }??
  • 如果當(dāng)前的線程不等于UI線程(主線程),就去調(diào)用Handler的post()方法,否則就直接調(diào)用Runnable對(duì)象的run()方法。還有什么會(huì)比這更清晰明了的嗎?

    通過(guò)以上所有源碼的分析,我們已經(jīng)發(fā)現(xiàn)了,不管是使用哪種方法在子線程中更新UI,其實(shí)背后的原理都是相同的,必須都要借助異步消息處理的機(jī)制來(lái)實(shí)現(xiàn),而我們又已經(jīng)將這個(gè)機(jī)制的流程完全搞明白了,真是一件一本萬(wàn)利的事情啊。

    第一時(shí)間獲得博客更新提醒,以及更多技術(shù)信息分享,歡迎關(guān)注我的微信公眾號(hào),掃一掃下方二維碼或搜索微信號(hào)guolin_blog,即可關(guān)注。

    總結(jié)

    以上是生活随笔為你收集整理的Android异步消息处理机制完全解析,带你从源码的角度彻底理解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。