Android多線(xiàn)程的四種方式:Handler、AsyncTask、ThreadPoolExector、IntentService

Android多線(xiàn)程的四種方式:Handler、AsyncTask、ThreadPoolExector、IntentService

?異步通信機(jī)制,將工作線(xiàn)程中需更新UI的操作信息 傳遞到 UI主線(xiàn)程,從而實(shí)現(xiàn) 工作線(xiàn)程對(duì)UI的更新處理,最終實(shí)現(xiàn)異步消息的處理。Handler不僅僅能將子線(xiàn)程的數(shù)據(jù)傳遞給主線(xiàn)程,它能實(shí)現(xiàn)任意兩個(gè)線(xiàn)程的數(shù)據(jù)傳遞。

(1)Message Message 可以**程之間傳遞消息。

可以在它的內(nèi)部攜帶少量數(shù)據(jù),用于在不同線(xiàn)程之間進(jìn)行數(shù)據(jù)交換。除了 what 字段,還可以使用 arg1 和 arg2 來(lái)攜帶整型數(shù)據(jù),使用 obj 來(lái)攜帶 Object 數(shù)據(jù)。 (2) Handler Handler 作為處理中心,用于發(fā)送(sendMessage 系列方法)與處理消息(handleMessage 方法)。 (3) MessageQueue MessageQueue 用于存放所有通過(guò) Handler 發(fā)送的消息。

這部分消息會(huì)一直存放在消息隊(duì)列中,直到被處理。每個(gè)線(xiàn)程中只會(huì)有一個(gè) MessageQueue 對(duì)象 (4) Looper Looper 用于管理 MessageQueue 隊(duì)列,Looper對(duì)象通過(guò)loop()方法開(kāi)啟了一個(gè)*循環(huán)——for (;;){},不斷地從looper內(nèi)的MessageQueue中取出Message,并傳遞到 Handler 的 handleMessage() 方法中。每個(gè)線(xiàn)程中只會(huì)有一個(gè) Looper 對(duì)象。

AsyncTask 是一種輕量級(jí)的任務(wù)異步類(lèi),可以在后臺(tái)子線(xiàn)程執(zhí)行任務(wù),且將執(zhí)行進(jìn)度及執(zhí)行結(jié)果傳遞給 UI 線(xiàn)程。 (1)onPreExecute() 在 UI 線(xiàn)程上工作,在任務(wù)執(zhí)行 doInBackground() 之前調(diào)用。此步驟通常用于設(shè)置任務(wù),例如在用戶(hù)界面中顯示進(jìn)度條。

(2)doInBackground(Params… params) 在子線(xiàn)程中工作,在 onPreExecute() 方法結(jié)束后執(zhí)行,這一步被用于在后臺(tái)執(zhí)行長(zhǎng)時(shí)間的任務(wù),Params 參數(shù)通過(guò) execute(Params) 方法被傳遞到此方法中。任務(wù)執(zhí)行結(jié)束后,將結(jié)果傳遞給 onPostExecute(Result) 方法,同時(shí)我們可以通過(guò) publishProgress(Progress) 方法,將執(zhí)行進(jìn)度發(fā)送給 onProgressUpdate(Progress) 方法。 (3)onProgressUpdate(Progress… values) 在 UI 線(xiàn)程上工作,會(huì)在 doInBackground() 中調(diào)用 publishProgress(Progress) 方法后執(zhí)行,此方法用于在后臺(tái)計(jì)算仍在執(zhí)行時(shí)(也就是 doInBackgound() 還在執(zhí)行時(shí))將計(jì)算執(zhí)行進(jìn)度通過(guò) UI 顯示出來(lái)。

例如,可以通過(guò)動(dòng)畫(huà)進(jìn)度條或顯示文本字段中的日志,從而方便用戶(hù)知道后臺(tái)任務(wù)執(zhí)行的進(jìn)度。 (4)onPostExecute(Result result) 在 UI 線(xiàn)程上工作,在任務(wù)執(zhí)行完畢(即 doInBackground(Result) 執(zhí)行完畢)并將執(zhí)行結(jié)果傳過(guò)來(lái)的時(shí)候工作。 使用規(guī)則: (1)AsyncTask 是個(gè)抽象類(lèi),所以要?jiǎng)?chuàng)建它的子類(lèi)實(shí)現(xiàn)抽象方法 (1)AsyncTask 類(lèi)必須是在 UI 線(xiàn)程中被加載,但在Android 4.1(API 16)開(kāi)始,就能被自動(dòng)加載完成。 (2)AsyncTask 類(lèi)的實(shí)例對(duì)象必須在 UI 線(xiàn)程中被創(chuàng)建。

(3)execute() 方法必須是在 UI 線(xiàn)程中被調(diào)用。 (4)不要手動(dòng)調(diào)用方法 onPreExecute()、onPostExecute()、doInBackground()、onProgressUpdate() (5)任務(wù)只能執(zhí)行一次(如果嘗試第二次執(zhí)行,將拋出異常)。即一個(gè)AsyncTask對(duì)象只能調(diào)用一次execute()方法。 原理: 其源碼中原理還是 Thread 與 Handler 的實(shí)現(xiàn),其包含 兩個(gè)線(xiàn)程池,一個(gè) Handler,如下所示: 名稱(chēng)類(lèi)型作用 SERIAL_EXECUTOR線(xiàn)程池分發(fā)任務(wù),串行分發(fā),一次只分發(fā)一個(gè)任務(wù) THREAD_POOL_EXECUTOR線(xiàn)程池執(zhí)行任務(wù),并行執(zhí)行,執(zhí)行的任務(wù)由 SERIAL_EXECUTOR 分發(fā) InternalHandlerHandler負(fù)責(zé)子線(xiàn)程與主線(xiàn)程的溝通,通知主線(xiàn)程做 UI 工作 一方面減少了每個(gè)并行任務(wù)獨(dú)自建立線(xiàn)程的開(kāi)銷(xiāo),另一方面可以管理多個(gè)并發(fā)線(xiàn)程的公共資源,從而提高了多線(xiàn)程的效率。

所以ThreadPoolExecutor比較適合一組任務(wù)的執(zhí)行。Executors利用工廠模式對(duì)ThreadPoolExecutor進(jìn)行了封裝。 Executors提供了四種創(chuàng)建ExecutorService的方法,他們的使用場(chǎng)景如下: 1. Executors.newFixedThreadPool() 創(chuàng)建一個(gè)定長(zhǎng)的線(xiàn)程池,每提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線(xiàn)程,直到達(dá)到池的**長(zhǎng)度,這時(shí)線(xiàn)程池會(huì)保持長(zhǎng)度不再變化。 當(dāng)線(xiàn)程處于空閑狀態(tài)時(shí),它們并不會(huì)被回收,除非線(xiàn)程池被關(guān)閉。

當(dāng)所有的線(xiàn)程都處于活動(dòng)狀態(tài)時(shí),新任務(wù)都會(huì)處于等待狀態(tài),直到有線(xiàn)程空閑出來(lái)。 只有核心線(xiàn)程并且不會(huì)被回收,能夠更加快速的響應(yīng)外界的請(qǐng)求。 2. Executors.newCachedThreadPool() 創(chuàng)建一個(gè)可緩存的線(xiàn)程池,如果當(dāng)前線(xiàn)程池的長(zhǎng)度超過(guò)了處理的需要時(shí),它可以靈活的回收空閑的線(xiàn)程,當(dāng)需要增加時(shí),它可以靈活的添加新的線(xiàn)程,而不會(huì)對(duì)池的長(zhǎng)度作任何限制 線(xiàn)程數(shù)量不定的線(xiàn)程池,只有非核心線(xiàn)程,**線(xiàn)程數(shù)為 Integer.MAX_VALUE。

當(dāng)線(xiàn)程池中的線(xiàn)程都處于活動(dòng)狀態(tài)時(shí),線(xiàn)程池會(huì)創(chuàng)建新的線(xiàn)程來(lái)處理新任務(wù),否則利用空閑的線(xiàn)程來(lái)處理新任務(wù)。線(xiàn)程池中的空閑線(xiàn)程具有超時(shí)機(jī)制,為 60s。 任務(wù)隊(duì)列相當(dāng)于一個(gè)空**,導(dǎo)致任何任務(wù)都會(huì)立即被執(zhí)行,適合執(zhí)行大量耗時(shí)較少的任務(wù)。

當(dāng)整個(gè)線(xiàn)程池都處于限制狀態(tài)時(shí),線(xiàn)程池中的線(xiàn)程都會(huì)超時(shí)而被停止。 3. Executors.newScheduledThreadPool() 創(chuàng)建一個(gè)定長(zhǎng)的線(xiàn)程池,而且支持定時(shí)的以及周期性的任務(wù)執(zhí)行,類(lèi)似于Timer。 非核心線(xiàn)程數(shù)沒(méi)有限制,并且非核心線(xiàn)程閑置的時(shí)候立即回收,主要用于執(zhí)行定時(shí)任務(wù)和具有固定周期的重復(fù)任務(wù)。 4. Executors.newSingleThreadExecutor() 創(chuàng)建一個(gè)單線(xiàn)程化的executor,它只創(chuàng)建**的worker線(xiàn)程來(lái)執(zhí)行任務(wù) 只有一個(gè)核心線(xiàn)程,保證所有的任務(wù)都在一個(gè)線(xiàn)程中順序執(zhí)行,意義在于不需要處理線(xiàn)程同步的問(wèn)題。

一般用于執(zhí)行后臺(tái)耗時(shí)任務(wù),當(dāng)任務(wù)執(zhí)行完成會(huì)自動(dòng)停止;同時(shí)由于它是一個(gè)服務(wù),優(yōu)先級(jí)要遠(yuǎn)遠(yuǎn)高于線(xiàn)程,更不容易被系統(tǒng)殺*,因此比較適合執(zhí)行一些高優(yōu)先級(jí)的后臺(tái)任務(wù)。 使用步驟:創(chuàng)建IntentService的子類(lèi),重寫(xiě)onHandleIntent方法,在onHandleIntent中執(zhí)行耗時(shí)任務(wù) 原理:在源碼實(shí)現(xiàn)上,IntentService封裝了HandlerThread和Handler。onHandleIntent方法結(jié)束后會(huì)調(diào)用IntentService的stopSelf(int startId)方法嘗試停止服務(wù)。

IntentService的內(nèi)部是通過(guò)消息的方式請(qǐng)求HandlerThread執(zhí)行任務(wù),HandlerThread內(nèi)部又是一種使用Handler的Thread,這就意味著IntentService和Looper一樣是順序執(zhí)行后臺(tái)任務(wù)的 (HandlerThread:封裝了Handler + ThreadHandlerThread適合在有需要一個(gè)工作線(xiàn)程(非UI線(xiàn)程)+任務(wù)的等待隊(duì)列的形式,優(yōu)點(diǎn)是不會(huì)有堵塞,減少了對(duì)性能的消耗,缺點(diǎn)是不能同時(shí)進(jìn)行多個(gè)任務(wù)的處理,需要等待進(jìn)行處理。

目標(biāo)和任務(wù)有什么區(qū)別?

目標(biāo)和任務(wù)有什么區(qū)別? 目標(biāo)是具體可量化的,由目的而生,**是達(dá)成目的的籌劃,而任務(wù)就是**中的每個(gè)完成點(diǎn) 一般先有目的,再有**,后有目標(biāo),用任務(wù)完成目標(biāo)。 一個(gè)人要使自己的生活得有意義,就要樹(shù)立遠(yuǎn)大的理想。

當(dāng)然,你如果還沒(méi)有想好應(yīng)該怎么實(shí)行,會(huì)認(rèn)為自己的目標(biāo)定得很大,完成預(yù)定目標(biāo)可能有困難。

你可以將大目標(biāo)化解成幾個(gè)小目標(biāo),再將小目標(biāo)一一完成。用這個(gè)方法能使你克服畏懼心理,(大目標(biāo)不好完成)按照制定的**去做。 你在完成小目標(biāo)時(shí),要有自信心,事情不能半途而廢,要堅(jiān)持做下去,要反復(fù)地認(rèn)真地將一件小事做好。你要調(diào)整自己的心態(tài),你要不斷地鼓勵(lì)自己,相信自己一定能做好一件小事,只要你想認(rèn)真完成的事,堅(jiān)信你就會(huì)做好它。

等你有了完成一件事情的經(jīng)歷以后,及時(shí)總結(jié)經(jīng)驗(yàn),進(jìn)一步增強(qiáng)自信心,向另一個(gè)目標(biāo)進(jìn)發(fā),全力以赴想方設(shè)法去圓滿(mǎn)完成它。 在完成任務(wù)時(shí)你就會(huì)感覺(jué)非??鞓?lè)。你就是一個(gè)充滿(mǎn)自信,最有作為的人!你還年輕,相信自己的能力,自己一定是個(gè)勝利者! 目標(biāo)是主動(dòng)的,任務(wù)是被動(dòng)的。

目標(biāo)是你某項(xiàng)任務(wù)的一個(gè)硬性指標(biāo),但他有長(zhǎng)期和短期之分。任務(wù)是你目前所必需完成的。他們也有共性。

目標(biāo)是你自己定的。任務(wù)可能是你自己定的也可能是別人派給你的。 目標(biāo) 一、拼音: mù biāo 二、釋義: 1、射擊、攻擊或?qū)で蟮奈锛?/p>

2、想要達(dá)到的境界或目的。 三、造句: 1、一旦立下目標(biāo),不達(dá)目標(biāo)絕不罷手,方可成功。 2、偉人之心常存目標(biāo);常人之心常存愿望。 3、目標(biāo)要遠(yuǎn)大,不達(dá)目的決不罷休。

4、進(jìn)步,意味著目標(biāo)不斷前移,階段不斷更新,它的視影不斷變化。 5、一個(gè)人沒(méi)目標(biāo),前途盡費(fèi);一個(gè)人沒(méi)理想,碌碌終生。 任務(wù) 一、拼音: rèn wù 二、釋義: 擔(dān)任的職務(wù)或使命。 三、造句: 1、救援船盡快地駛離軍港去執(zhí)行任務(wù)。

2、巡道工人披星戴月地執(zhí)行任務(wù)。 3、我們應(yīng)抓住有利時(shí)機(jī),趁熱打鐵完成上級(jí)交給的任務(wù)。 4、播種保苗歷來(lái)是棉花生產(chǎn)最為關(guān)鍵的時(shí)期與任務(wù)。 5、毛主席語(yǔ)錄:政治的首要任務(wù)是區(qū)分?jǐn)秤选?/p>

“任務(wù)”和“目標(biāo)”這兩個(gè)詞有什么區(qū)別? 任務(wù)一般做被動(dòng)的,應(yīng)該是別人給你訂任務(wù)。 目標(biāo)一般做主動(dòng)的。自己給自己設(shè)目標(biāo)。

1、目標(biāo)是具體可量化的,由目的而生。 2、任務(wù)就是**中的每個(gè)完成點(diǎn)。 3、一般先有目的,再有**,用任務(wù)完成目標(biāo)。

目標(biāo)是具體可量化的,由目的而生,**是達(dá)成目的的籌劃,而任務(wù)就是**中的每個(gè)完成點(diǎn) 一般先有目的,再有**,后有目標(biāo),用任務(wù)完成目標(biāo)。 主線(xiàn)任務(wù)和支線(xiàn)任務(wù)有什么區(qū)別? 個(gè)人感覺(jué)主線(xiàn)給的東西以經(jīng)驗(yàn),SP居多 直線(xiàn)就是錢(qián)啊,東西的 程序與任務(wù)有什么區(qū)別 程序記錄了你電腦全部執(zhí)行的程式,包括任務(wù),**,系統(tǒng)程式等等。程序隨意結(jié)束會(huì)對(duì)電腦產(chǎn)生影響。ctrl+alt+del可以檢視 任務(wù)是你執(zhí)行電腦后開(kāi)啟的應(yīng)用程式(比如IE,QQ,游戲啊==) 結(jié)束任務(wù)一般不會(huì)對(duì)電腦系統(tǒng)產(chǎn)生影響。

夜場(chǎng)ds做有任務(wù)和沒(méi)任務(wù)有什么區(qū)別 慎重:請(qǐng)所有的人看下 我在 上海做夜場(chǎng)的 上海有很多好的場(chǎng)子的 。但騙子更多 特別是那些什么***的**網(wǎng)站都是中介建立的 ***是不會(huì)自己建立網(wǎng)站的我大概給大家說(shuō)一下情況 以免被騙 我做模特領(lǐng)隊(duì) 期待各位佳麗 **、無(wú)論真假 去面試的時(shí)候身上別帶很多現(xiàn)金。 第二、上海夜場(chǎng)的** 全都是領(lǐng)隊(duì) 自己招的 或者周?chē)呐笥?介紹的。

第三 如果你 去面試 他把你帶到什么**寫(xiě)字樓 說(shuō)是什么人事部的話(huà) ,那么不要考慮 轉(zhuǎn)身就走,因?yàn)樯虾](méi)有一家 ***會(huì)因?yàn)檎腥诉@點(diǎn)小事 而專(zhuān)門(mén)設(shè)立個(gè) 人事部。 一、承諾不收任何押金和費(fèi)用,公司客源穩(wěn)定。 二、宣告本廣告是網(wǎng)上**真正**女的廣告。 三、為了證實(shí)本**的真實(shí)性,你可以檢視網(wǎng)上**的廣告,看有沒(méi)有和我們一樣承諾不收取任何押金和費(fèi)用的內(nèi)容。

說(shuō)的再好不如親眼所見(jiàn),為防止被騙,面試請(qǐng)晚上直接來(lái)場(chǎng)子,不需要帶一分錢(qián),條件合格者,帶你先看看場(chǎng)子工作環(huán)境,和其他同類(lèi)工作人員,然后自己考慮是否在此上班,完全出于自愿,絕不涉及任何違法工作內(nèi)容。 如果你對(duì)目前的工作不滿(mǎn)意,如果你想 *** 多賺一點(diǎn)錢(qián),如果你對(duì)未來(lái)充滿(mǎn)憧憬,如果你喜歡夜生活,這里將給你的將來(lái) 多一個(gè)選擇和把握的機(jī)會(huì)。 非中介,本人承諾不收費(fèi),請(qǐng)記住 《要人的地方不要錢(qián),要錢(qián)的地方不缺人》 android handler和非同步任務(wù)有什么區(qū)別 其實(shí)handler與非同步任務(wù)沒(méi)有可比性,您的基礎(chǔ)還需要加強(qiáng)。

下面這篇csdn的部落格中有handler的詳細(xì)介紹, :blog.csdn./androidwuyou/article/details/52601498 AsyncTask實(shí)現(xiàn)的原理和適用的優(yōu)缺點(diǎn) AsyncTask,是android提供的輕量級(jí)的非同步類(lèi),可以直接繼承AsyncTask,在類(lèi)中實(shí)現(xiàn)非同步操作,并提供介面反饋當(dāng)前非同步執(zhí)行的程度(可以通過(guò)介面實(shí)現(xiàn)UI進(jìn)度更新),**反饋執(zhí)行的結(jié)果給UI主執(zhí)行緒. 使用的優(yōu)點(diǎn): 簡(jiǎn)單,快捷 過(guò)程可控 使用的缺點(diǎn)百科: 在使用多個(gè)非同步操作和并需要進(jìn)行Ui變更時(shí),就變得復(fù)雜起來(lái). Handler非同步實(shí)現(xiàn)的原理和適用的優(yōu)缺點(diǎn) 在Handler 非同步實(shí)現(xiàn)時(shí),涉及到 Handler, Looper, Message,Thread四個(gè)物件,實(shí)現(xiàn)非同步的流程是主執(zhí)行緒啟動(dòng)Thread(子執(zhí)行緒)執(zhí)行并生成Message-Looper獲取Message并傳遞給HandlerHandler逐個(gè)獲取Looper中的Message,并進(jìn)行UI變更。 使用的優(yōu)點(diǎn): 結(jié)構(gòu)清晰,功能定義明確 對(duì)于多個(gè)后臺(tái)任務(wù)時(shí),簡(jiǎn)單,清晰 使用的缺點(diǎn): 在單個(gè)后臺(tái)非同步處理時(shí),顯得程式碼過(guò)多,結(jié)構(gòu)過(guò)于復(fù)雜(相對(duì)性) AsyncTask介紹 Android的AsyncTask比Handler更輕量級(jí)一些(只是程式碼上輕量一些,而實(shí)際上要比handler更耗資源),適用于簡(jiǎn)單的非同步處理。 首先明確Android之所以有Handler和AsyncTask,都是為了不阻塞主執(zhí)行緒(UI執(zhí)行緒),且UI的更新只能在主執(zhí)行緒中完成,因此非同步處理是不可避免的。 Android為了降低這個(gè)開(kāi)發(fā)難度,提供了AsyncTask。AsyncTask就是一個(gè)封裝過(guò)的后臺(tái)任務(wù)類(lèi),顧名思義就是非同步任務(wù)。 AsyncTask直接繼承于Object類(lèi),位置為android.os.AsyncTask。要使用AsyncTask工作我們要提供三個(gè)泛型引數(shù),并重載幾個(gè)方法。

Android中的線(xiàn)程狀態(tài) – AsyncTask詳解

在操作系統(tǒng)中,線(xiàn)程是操作系統(tǒng)調(diào)度的最小單元,同時(shí)線(xiàn)程又是一種受限的系統(tǒng)資源,即線(xiàn)程不可能無(wú)限制地產(chǎn)生,并且 線(xiàn)程的創(chuàng)建和銷(xiāo)毀都會(huì)有相應(yīng)的開(kāi)銷(xiāo)。 當(dāng)系統(tǒng)中存在大量的線(xiàn)程時(shí),系統(tǒng)會(huì)通過(guò)會(huì)時(shí)間片輪轉(zhuǎn)的方式調(diào)度每個(gè)線(xiàn)程,因此線(xiàn)程不可能做到**的并行。

如果在一個(gè)進(jìn)程中頻繁地創(chuàng)建和銷(xiāo)毀線(xiàn)程,顯然不是高效的做法。

正確的做法是采用線(xiàn)程池,一個(gè)線(xiàn)程池中會(huì)緩存一定數(shù)量的線(xiàn)程,通過(guò)線(xiàn)程池就可以避免因?yàn)轭l繁創(chuàng)建和銷(xiāo)毀線(xiàn)程所帶來(lái)的系統(tǒng)開(kāi)銷(xiāo)。 AsyncTask是一個(gè)抽象類(lèi),它是由Android封裝的一個(gè)輕量級(jí)異步類(lèi)(輕量體現(xiàn)在使用方便、代碼簡(jiǎn)潔),它可以**程池中執(zhí)行后臺(tái)任務(wù),然后把執(zhí)行的進(jìn)度和最終結(jié)果傳遞給主線(xiàn)程并在主線(xiàn)程中更新UI。 AsyncTask的內(nèi)部封裝了 兩個(gè)線(xiàn)程池 (SerialExecutor和THREAD_POOL_EXECUTOR)和 一個(gè)Handler (InternalHandler)。 其中 SerialExecutor線(xiàn)程池用于任務(wù)的排隊(duì),讓需要執(zhí)行的多個(gè)耗時(shí)任務(wù),按順序排列 , THREAD_POOL_EXECUTOR線(xiàn)程池才真正地執(zhí)行任務(wù) , InternalHandler用于從工作線(xiàn)程切換到主線(xiàn)程 。

1.AsyncTask的泛型參數(shù) AsyncTask是一個(gè)抽象泛型類(lèi)。 其中,三個(gè)泛型類(lèi)型參數(shù)的含義如下: Params: 開(kāi)始異步任務(wù)執(zhí)行時(shí)傳入的參數(shù)類(lèi)型; Progress: 異步任務(wù)執(zhí)行過(guò)程中,返回下載進(jìn)度值的類(lèi)型; Result: 異步任務(wù)執(zhí)行完成后,返回的結(jié)果類(lèi)型; 如果AsyncTask確定不需要傳遞具體參數(shù),那么這三個(gè)泛型參數(shù)可以用Void來(lái)代替。 有了這三個(gè)參數(shù)類(lèi)型之后,也就控制了這個(gè)AsyncTask子類(lèi)各個(gè)階段的返回類(lèi)型,如果有不同業(yè)務(wù),我們就需要再另寫(xiě)一個(gè)AsyncTask的子類(lèi)進(jìn)行處理。

2.AsyncTask的核心方法 onPreExecute() 這個(gè)方**在 后臺(tái)任務(wù)開(kāi)始執(zhí)行之間調(diào)用,在主線(xiàn)程執(zhí)行。 用于進(jìn)行一些界面上的初始化操作,比如顯示一個(gè)進(jìn)度條對(duì)話(huà)框等。 doInBackground(Params…) 這個(gè)方法中的所有代碼都會(huì) 在子線(xiàn)程中運(yùn)行,我們應(yīng)該在這里去處理所有的耗時(shí)任務(wù)。

任務(wù)一旦完成就可以通過(guò)return語(yǔ)句來(lái)將任務(wù)的執(zhí)行結(jié)果進(jìn)行返回,如果AsyncTask的第三個(gè)泛型參數(shù)指定的是Void,就可以不返回任務(wù)執(zhí)行結(jié)果。 注意,在這個(gè)方法中是不可以進(jìn)行UI操作的,如果需要更新UI元素,比如說(shuō)反饋當(dāng)前任務(wù)的執(zhí)行進(jìn)度,可以調(diào)用publishProgress(Progress…)方法來(lái)完成。 onProgressUpdate(Progress…) 當(dāng)在后臺(tái)任務(wù)中調(diào)用了publishProgress(Progress…)方法后,這個(gè)方法就很快會(huì)被調(diào)用,方法中攜帶的參數(shù)就是在后臺(tái)任務(wù)中傳遞過(guò)來(lái)的。

在這個(gè)方法中可以對(duì)UI進(jìn)行操作,在主線(xiàn)程中進(jìn)行,利用參數(shù)中的數(shù)值就可以對(duì)界面元素進(jìn)行相應(yīng)的更新。 onPostExecute(Result) 當(dāng)doInBackground(Params…)執(zhí)行完畢并通過(guò)return語(yǔ)句進(jìn)行返回時(shí),這個(gè)方法就很快會(huì)被調(diào)用。返回的數(shù)據(jù)會(huì)作為參數(shù)傳遞到此方法中, 可以利用返回的數(shù)據(jù)來(lái)進(jìn)行一些UI操作,在主線(xiàn)程中進(jìn)行,比如說(shuō)提醒任務(wù)執(zhí)行的結(jié)果,以及關(guān)閉掉進(jìn)度條對(duì)話(huà)框等。 上面幾個(gè)方法的調(diào)用順序: onPreExecute() –> doInBackground() –> publishProgress() –> onProgressUpdate() –> onPostExecute() 如果不需要執(zhí)行更新進(jìn)度則為onPreExecute() –> doInBackground() –> onPostExecute(), 除了上面四個(gè)方法,AsyncTask還提供了onCancelled()方法, 它同樣在主線(xiàn)程中執(zhí)行,當(dāng)異步任務(wù)取消時(shí),onCancelled()會(huì)被調(diào)用,這個(gè)時(shí)候onPostExecute()則不會(huì)被調(diào)用 ,但是要注意的是, AsyncTask中的cancel()方法并不是真正去取消任務(wù),只是設(shè)置這個(gè)任務(wù)為取消狀態(tài),我們需要在doInBackground()判斷終止任務(wù)。

就好比想要終止一個(gè)線(xiàn)程,調(diào)用interrupt()方法,只是進(jìn)行標(biāo)記為中斷,需要**程內(nèi)部進(jìn)行標(biāo)記判斷然后中斷線(xiàn)程。 3.AsyncTask的簡(jiǎn)單使用 這里我們模擬了一個(gè)下載任務(wù),在doInBackground()方法中去執(zhí)行具體的下載邏輯,在onProgressUpdate()方法中顯示當(dāng)前的下載進(jìn)度,在onPostExecute()方法中來(lái)提示任務(wù)的執(zhí)行結(jié)果。如果想要啟動(dòng)這個(gè)任務(wù),只需要簡(jiǎn)單地調(diào)用以下代碼即可: 4.使用AsyncTask的注意事項(xiàng) ①異步任務(wù)的實(shí)例必須在UI線(xiàn)程中創(chuàng)建,即AsyncTask對(duì)象必須在UI線(xiàn)程中創(chuàng)建。 ②execute(Params… params)方法必須在UI線(xiàn)程中調(diào)用。

③不要手動(dòng)調(diào)用onPreExecute(),doInBackground(Params… params),onProgressUpdate(Progress… values),onPostExecute(Result result)這幾個(gè)方法。 ④不能在doInBackground(Params… params)中更改UI組件的信息。 ⑤一個(gè)任務(wù)實(shí)例只能執(zhí)行一次,如果執(zhí)行第二次將會(huì)拋出異常。 先從初始化一個(gè)AsyncTask時(shí),調(diào)用的構(gòu)造函數(shù)開(kāi)始分析。

這段代碼雖然看起來(lái)有點(diǎn)長(zhǎng),但實(shí)際上并沒(méi)有任何具體的邏輯會(huì)得到執(zhí)行,只是初始化了兩個(gè)變量,mWorker和mFuture,并在初始化mFuture的時(shí)候?qū)Worker作為參數(shù)傳入。mWorker是一個(gè)Callable對(duì)象,mFuture是一個(gè)FutureTask對(duì)象,這兩個(gè)變量會(huì)暫時(shí)保存在內(nèi)存中,稍后才會(huì)用到它們。 FutureTask實(shí)現(xiàn)了Runnable接口,關(guān)于這部分內(nèi)容可以看這篇文章。

mWorker中的call()方法執(zhí)行了耗時(shí)操作,即result = doInBackground(mParams);,然后把執(zhí)行得到的結(jié)果通過(guò)postResult(result);,傳遞給內(nèi)部的Handler跳轉(zhuǎn)到主線(xiàn)程中。在這里這是實(shí)例化了兩個(gè)變量,并沒(méi)有開(kāi)啟執(zhí)行任務(wù)。 那么mFuture對(duì)象是怎么加載到線(xiàn)程池中,進(jìn)行執(zhí)行的呢? 接著如果想要啟動(dòng)某一個(gè)任務(wù),就需要調(diào)用該任務(wù)的execute()方法,因此現(xiàn)在我們來(lái)看一看execute()方法的源碼,如下所示: 調(diào)用了executeOnExecutor()方法,具體執(zhí)行邏輯在這個(gè)方法里面: 可以 看出,先執(zhí)行了onPreExecute()方法,然后具體執(zhí)行耗時(shí)任務(wù)是在exec.execute(mFuture),把構(gòu)造函數(shù)中實(shí)例化的mFuture傳遞進(jìn)去了。

exec具體是什么? 從上面可以看出具體是sDefaultExecutor,再追溯看到是SerialExecutor類(lèi),具體源碼如下: 終于追溯到了調(diào)用了SerialExecutor 類(lèi)的execute方法。SerialExecutor 是個(gè)靜態(tài)內(nèi)部類(lèi),是所有實(shí)例化的AsyncTask對(duì)象公有的,SerialExecutor 內(nèi)部維持了一個(gè)隊(duì)列,通過(guò)鎖使得該隊(duì)列保證AsyncTask中的任務(wù)是串行執(zhí)行的,即多個(gè)任務(wù)需要一個(gè)個(gè)加到該隊(duì)列中,然后執(zhí)行完隊(duì)列頭部的再執(zhí)行下一個(gè),以此類(lèi)推。 在這個(gè)方法中,有兩個(gè)主要步驟。 ①向隊(duì)列中加入一個(gè)新的任務(wù),即之前實(shí)例化后的mFuture對(duì)象。

②調(diào)用 scheduleNext()方法,調(diào)用THREAD_POOL_EXECUTOR執(zhí)行隊(duì)列頭部的任務(wù)。 由此可見(jiàn)SerialExecutor 類(lèi)僅僅為了保持任務(wù)執(zhí)行是串行的,實(shí)際執(zhí)行交給了THREAD_POOL_EXECUTOR。 THREAD_POOL_EXECUTOR又是什么? 實(shí)際是個(gè)線(xiàn)程池,開(kāi)啟了一定數(shù)量的核心線(xiàn)程和工作線(xiàn)程。

然后調(diào)用線(xiàn)程池的execute()方法。執(zhí)行具體的耗時(shí)任務(wù),即開(kāi)頭構(gòu)造函數(shù)中mWorker中call()方法的內(nèi)容。先執(zhí)行完doInBackground()方法,又執(zhí)行postResult()方法,下面看該方法的具體內(nèi)容: 該方法向Handler對(duì)象發(fā)送了一個(gè)消息,下面具體看AsyncTask中實(shí)例化的Hanlder對(duì)象的源碼: 在InternalHandler 中,如果收到的消息是MESSAGE_POST_RESULT,即執(zhí)行完了doInBackground()方法并傳遞結(jié)果,那么就調(diào)用finish()方法。 如果任務(wù)已經(jīng)取消了,回調(diào)onCancelled()方法,否則回調(diào) onPostExecute()方法。

如果收到的消息是MESSAGE_POST_PROGRESS,回調(diào)onProgressUpdate()方法,更新進(jìn)度。 InternalHandler是一個(gè)靜態(tài)類(lèi),為了能夠?qū)?zhí)行環(huán)境切換到主線(xiàn)程,因此這個(gè)類(lèi)必須在主線(xiàn)程中進(jìn)行加載。所以變相要求AsyncTask的類(lèi)必須在主線(xiàn)程中進(jìn)行加載。

到此為止,從任務(wù)執(zhí)行的開(kāi)始到結(jié)束都從源碼分析完了。 AsyncTask的串行和并行 從上述源碼分析中分析得到,默?。

android中同時(shí)使用asynctask和handler有沖突嗎

Android的AsyncTask類(lèi)中使用自定義handler 熟知的AsyncTask就是Thread+handler實(shí)現(xiàn),但是這個(gè)handler并不能很好的被我們控制。在我的需求中希望在AsyncTask中使用自定義的handler,而且在必要的時(shí)候退出消息循環(huán)。

實(shí)現(xiàn)思路如下: AsyncTask中創(chuàng)建消息循環(huán),然后啟動(dòng)handler目標(biāo)操作,當(dāng)操作結(jié)束后,結(jié)束消息循環(huán),執(zhí)行后續(xù)代碼。

Android進(jìn)程間和線(xiàn)程間通信方式

?進(jìn)程:是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)**上的一次運(yùn)行活動(dòng),進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位。 線(xiàn)程:是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位。

線(xiàn)程自己基本上不擁有系統(tǒng)資源,只擁有一些在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個(gè)進(jìn)程的其他的線(xiàn)程共享進(jìn)程所擁有的全部資源。

區(qū)別: (1)、一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線(xiàn)程; (2)、線(xiàn)程的劃分尺度小于進(jìn)程,使得多線(xiàn)程程序的并發(fā)性高; (3)、進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線(xiàn)程共享內(nèi)存,但線(xiàn)程之間沒(méi)有單獨(dú)的地址空間,一個(gè)線(xiàn)程*掉就等于整個(gè)進(jìn)程*掉。 ——————— 一、Android進(jìn)程間通信方式 1.Bundle 由于Activity,Service,Receiver都是可以通過(guò)Intent來(lái)攜帶Bundle傳輸數(shù)據(jù)的,所以我們可以在一個(gè)進(jìn)程中通過(guò)Intent將攜帶數(shù)據(jù)的Bundle發(fā)送到另一個(gè)進(jìn)程的組件。 缺點(diǎn):無(wú)法傳輸Bundle不支持的數(shù)據(jù)類(lèi)型。 2.ContentProvider ContentProvider是Android四大組件之一,以表格的方式來(lái)儲(chǔ)存數(shù)據(jù),提供給外界,即Content Provider可以跨進(jìn)程訪(fǎng)問(wèn)其他應(yīng)用程序中的數(shù)據(jù)。

用法是繼承ContentProvider,實(shí)現(xiàn)onCreate,query,update,insert,delete和getType方法,onCreate是負(fù)責(zé)創(chuàng)建時(shí)做一些初始化的工作,增刪查改的方法就是對(duì)數(shù)據(jù)的查詢(xún)和修改,getType是返回一個(gè)String,表示Uri請(qǐng)求的類(lèi)型。注冊(cè)完后就可以使用ContentResolver去請(qǐng)求指定的Uri。 3.文件 兩個(gè)進(jìn)程可以到同一個(gè)文件去交換數(shù)據(jù),我們不僅可以保存文本文件,還可以將對(duì)象持久化到文件,從另一個(gè)文件恢復(fù)。

要注意的是,當(dāng)并發(fā)讀/寫(xiě)時(shí)可能會(huì)出現(xiàn)并發(fā)的問(wèn)題。 4.Broadcast Broadcast可以向android系統(tǒng)中所有應(yīng)用程序發(fā)送廣播,而需要跨進(jìn)程通訊的應(yīng)用程序可以監(jiān)聽(tīng)這些廣播。 5.AIDL方式 Service和Content Provider類(lèi)似,也可以訪(fǎng)問(wèn)其他應(yīng)用程序中的數(shù)據(jù),Content Provider返回的是Cursor對(duì)象,而Service返回的是Java對(duì)象,這種可以跨進(jìn)程通訊的服務(wù)叫AIDL服務(wù)。

AIDL通過(guò)定義服務(wù)端暴露的接口,以提供給客戶(hù)端來(lái)調(diào)用,AIDL使服務(wù)器可以并行處理,而Messenger封裝了AIDL之后只能串行運(yùn)行,所以Messenger一般用作消息傳遞。 6.Messenger Messenger是基于AIDL實(shí)現(xiàn)的,服務(wù)端(被動(dòng)方)提供一個(gè)Service來(lái)處理客戶(hù)端(主動(dòng)方)連接,維護(hù)一個(gè)Handler來(lái)創(chuàng)建Messenger,在onBind時(shí)返回Messenger的binder。 雙方用Messenger來(lái)發(fā)送數(shù)據(jù),用Handler來(lái)處理數(shù)據(jù)。

Messenger處理數(shù)據(jù)依靠Handler,所以是串行的,也就是說(shuō),Handler接到多個(gè)message時(shí),就要排隊(duì)依次處理。 7.Socket Socket方法是通過(guò)**來(lái)進(jìn)行數(shù)據(jù)交換,注意的是要在子線(xiàn)程請(qǐng)求,不然會(huì)堵塞主線(xiàn)程??蛻?hù)端和服務(wù)端建立連接之后即可不斷傳輸數(shù)據(jù),比較適合實(shí)時(shí)的數(shù)據(jù)傳輸 二、Android線(xiàn)程間通信方式 一般說(shuō)線(xiàn)程間通信主要是指主線(xiàn)程(也叫UI線(xiàn)程)和子線(xiàn)程之間的通信,主要有以下兩種方式: 1.AsyncTask機(jī)制 AsyncTask,異步任務(wù),也就是說(shuō)在UI線(xiàn)程運(yùn)行的時(shí)候,可以在后臺(tái)的執(zhí)行一些異步的操作;AsyncTask可以很容易且正確地使用UI線(xiàn)程,AsyncTask允許進(jìn)行后臺(tái)操作,并在不顯示使用工作線(xiàn)程或Handler機(jī)制的情況下,將結(jié)果反饋給UI線(xiàn)程。但是AsyncTask只能用于短時(shí)間的操作(最多幾秒就應(yīng)該結(jié)束的操作),如果需要長(zhǎng)時(shí)間運(yùn)行在后臺(tái),就不適合使用AsyncTask了,只能去使用Java提供的其他API來(lái)實(shí)現(xiàn)。

2.Handler機(jī)制 Handler,繼承自O(shè)bject類(lèi),用來(lái)發(fā)送和處理Message對(duì)象或Runnable對(duì)象;Handler在創(chuàng)建時(shí)會(huì)與當(dāng)前所在的線(xiàn)程的Looper對(duì)象相關(guān)聯(lián)(如果當(dāng)前線(xiàn)程的Looper為空或不存在,則會(huì)拋出異常,此時(shí)需要**程中主動(dòng)調(diào)用Looper.prepare()來(lái)創(chuàng)建一個(gè)Looper對(duì)象)。使用Handler的主要作用就是在后面的過(guò)程中發(fā)送和處理Message對(duì)象和讓其他的線(xiàn)程完成某一個(gè)動(dòng)作(如在工作線(xiàn)程中通過(guò)Handler對(duì)象發(fā)送一個(gè)Message對(duì)象,讓UI線(xiàn)程進(jìn)行UI的更新,然后UI線(xiàn)程就會(huì)在MessageQueue中得到這個(gè)Message對(duì)象(取出Message對(duì)象是由其相關(guān)聯(lián)的Looper對(duì)象完成的),并作出相應(yīng)的響應(yīng))。 三、Android兩個(gè)子線(xiàn)程之間通信 面試的過(guò)程中,有些面試官可能會(huì)問(wèn)Android子線(xiàn)程之間的通信方式,由于絕大部分程序員主要關(guān)注的是Android主線(xiàn)程和子線(xiàn)程之間的通信,所以這個(gè)問(wèn)題很容易讓人懵逼。 主線(xiàn)程和子線(xiàn)程之間的通信可以通過(guò)主線(xiàn)程中的handler把子線(xiàn)程中的message發(fā)給主線(xiàn)程中的looper,或者,主線(xiàn)程中的handler通過(guò)post向looper中發(fā)送一個(gè)runnable。

但looper默認(rèn)存在于main線(xiàn)程中,子線(xiàn)程中沒(méi)有Looper,該怎么辦呢?其實(shí)原理很簡(jiǎn)單,把looper綁定到子線(xiàn)程中,并且創(chuàng)建一個(gè)handler。在另一個(gè)線(xiàn)程中通過(guò)這個(gè)handler發(fā)送消息,就可以實(shí)現(xiàn)子線(xiàn)程之間的通信了。

關(guān)于 Handler 的這 20 個(gè)問(wèn)題,你都清楚嗎?

Android 11?開(kāi)始,AsyncTask?正式謝幕,變成了不推薦使用的 API。**建議采用?Kotlin 協(xié)程替代,或者自行實(shí)現(xiàn)。

事實(shí)上,無(wú)論是 AsyncTask 還是協(xié)程,背后都有 Handler 的功勞。

無(wú)論從普及原理的角度、還是從自行實(shí)現(xiàn)的角度,我們都需要吃透這個(gè) Android 系統(tǒng)所特有的線(xiàn)程間通信方式Handler?機(jī)制! 初嘗 Handler 機(jī)制的時(shí)候,原以為 Handler 類(lèi)發(fā)揮了很大的作用。當(dāng)你深入了解它的原理之后,會(huì)發(fā)現(xiàn) Handler 只是該機(jī)制的 調(diào)用入口和回調(diào) 而已,最重要的東西是?Looper?和?MessagQueue,以及不斷流轉(zhuǎn)的?Message。 本次針對(duì) Handler 機(jī)制常被提及和容易困擾的?20 個(gè)問(wèn)題進(jìn)行整理和回答,供大家解惑和回顧~ 簡(jiǎn)述下 Handler 機(jī)制的總體原理? Looper 存在哪?如何可以保證線(xiàn)程獨(dú)有? 如何理解 ThreadLocal 的作用? 主線(xiàn)程 Main Looper 和一般 Looper 的異同? Handler 或者說(shuō) Looper 如何切換線(xiàn)程? Looper 的 loop() *循環(huán)為什么不卡*? Looper 的等待是如何能夠準(zhǔn)確喚醒的? Message 如何獲???為什么這么設(shè)計(jì)? MessageQueue 如何管理 Message? 理解 Message 和 MessageQueue 的異同? Message 的執(zhí)行時(shí)刻如何管理? Handler、Mesage 和 Runnable 的關(guān)系如何理解? IdleHandler 空閑 Message 了解過(guò)嗎?有什么用? 異步 Message 或同步屏障了解過(guò)嗎?怎么用?什么原理? Looper 和 MessageQueue、Message 及 Handler 的關(guān)系? Native 側(cè)的 NativeMessageQueue 和 Looper 的作用是? Native 側(cè)如何使用 Looper? Handler 為什么可能導(dǎo)致內(nèi)存泄露?如何避免? Handler 在系統(tǒng)當(dāng)中的應(yīng)用 Android 為什么不允許并發(fā)訪(fǎng)問(wèn) UI? 1. 簡(jiǎn)述下 Handler 機(jī)制的總體原理? Looper 準(zhǔn)備和開(kāi)啟輪循: 尚無(wú) Message 的話(huà),調(diào)用 Native 側(cè)的?pollOnce()?進(jìn)入 無(wú)限等待 存在 Message,但執(zhí)行時(shí)間?when?尚未滿(mǎn)足的話(huà),調(diào)用 pollOnce() 時(shí)傳入剩余時(shí)長(zhǎng)參數(shù)進(jìn)入 有限等待 Looper#prepare()?初始化線(xiàn)程獨(dú)有的?Looper?以及?MessageQueue Looper#loop()?開(kāi)啟 *循環(huán) 讀取 MessageQueue 中下一個(gè)滿(mǎn)足執(zhí)行時(shí)間的 Message Message 發(fā)送、入隊(duì)和出隊(duì): Native 側(cè)如果處于無(wú)限等待的話(huà):任意線(xiàn)程向?Handler?發(fā)送?Message?或?Runnable?后,Message 將按照 when 條件的先后,**入 Handler 持有的 Looper 實(shí)例所對(duì)應(yīng)的 MessageQueue 中 適當(dāng)?shù)奈恢?。MessageQueue 發(fā)現(xiàn)有合適的 Message 插入后將調(diào)用 Native 側(cè)的?wake()?喚醒無(wú)限等待的線(xiàn)程。

這將促使 MessageQueue 的讀取繼續(xù) 進(jìn)入下一次循環(huán) ,此刻 Queue 中已有滿(mǎn)足條件的 Message 則出隊(duì)返回給 Looper Native 側(cè)如果處于有限等待的話(huà):在等待指定時(shí)長(zhǎng)后 epoll_wait 將返回。線(xiàn)程繼續(xù)讀取 MessageQueue,此刻因?yàn)闀r(shí)長(zhǎng)條件將滿(mǎn)足將其出隊(duì) Looper 處理 Message 的實(shí)現(xiàn): Looper 得到 Message 后回調(diào) Message 的?callback?屬性即 Runnable,或依據(jù)?target?屬性即 Handler,去執(zhí)行 Handler 的回調(diào)。 存在?mCallback?屬性的話(huà)回調(diào)?Handler$Callback 反之,回調(diào)?handleMessage() 2. Looper 存在哪?如何可以保證線(xiàn)程獨(dú)有? Looper 實(shí)例被管理在靜態(tài)屬性?sThreadLocal?中 ThreadLocal?內(nèi)部通過(guò)?ThreadLocalMap?持有 Looper,key?為 ThreadLocal 實(shí)例本身,value?即為 Looper 實(shí)例 每個(gè) Thread 都有一個(gè)自己的 ThreadLocalMap,這樣可以保證每個(gè)線(xiàn)程對(duì)應(yīng)一個(gè)獨(dú)立的 Looper 實(shí)例,進(jìn)而保證?myLooper()?可以獲得線(xiàn)程獨(dú)有的 Looper 彩蛋:一個(gè) App 擁有幾個(gè) Looper 實(shí)例?幾個(gè) ThreadLocal 實(shí)例?幾個(gè) MessageQueue 實(shí)例?幾個(gè) Message 實(shí)例?幾個(gè) Handler 實(shí)例 一個(gè)線(xiàn)程只有一個(gè) Looper 實(shí)例 一個(gè) Looper 實(shí)例只對(duì)應(yīng)著一個(gè) MessageQueue 實(shí)例 一個(gè) MessageQueue 實(shí)例可對(duì)應(yīng)多個(gè) Message 實(shí)例,其從 Message 靜態(tài)池里獲取,存在 50 的上限 一個(gè)線(xiàn)程可以擁有多個(gè) Handler 實(shí)例,其Handler 只是發(fā)送和執(zhí)行任務(wù)邏輯的入口和出口 ThreadLocal 實(shí)例是靜態(tài)的,整個(gè)進(jìn)程 共用一個(gè)實(shí)例 。

每個(gè) Looper 存放的 ThreadLocalMap 均弱引用它作為 key 3. 如何理解 ThreadLocal 的作用? 首先要明確并非不是用來(lái)切換線(xiàn)程的, 只是為了讓每個(gè)線(xiàn)程方便程獲取自己的 Looper 實(shí)例 ,見(jiàn) Looper#myLooper() 后續(xù)可供 Handler 初始化時(shí) 指定其所屬的 Looper 線(xiàn)程 也可用來(lái)線(xiàn)程判斷自己是否 是主線(xiàn)程 4. 主線(xiàn)程 Main Looper 和一般 Looper 的異同? 區(qū)別: Main Looper?不可?quit 主線(xiàn)程需要不斷讀取系統(tǒng)消息和用書(shū)輸入,是進(jìn)程的入口,只可被系統(tǒng)直接終止。進(jìn)而其 Looper 在創(chuàng)建的時(shí)候設(shè)置了 不可quit的標(biāo)志 ,而 其他線(xiàn)程的 Looper 則可以也必須手動(dòng) quit Main Looper 實(shí)例還被 靜態(tài)緩存 為了便于每個(gè)線(xiàn)程獲得主線(xiàn)程 Looper 實(shí)例,見(jiàn) Looper#getMainLooper(),Main Looper 實(shí)例還作為?sMainLooper?屬性緩存到了 Looper 類(lèi)中。 相同點(diǎn): 都是通過(guò) Looper#prepare() 間接調(diào)用 Looper 構(gòu)造函數(shù)創(chuàng)建的實(shí)例 都被靜態(tài)實(shí)例 ThreadLocal 管理,方便每個(gè)線(xiàn)程獲取自己的 Looper 實(shí)例 彩蛋:主線(xiàn)程為什么不用初始化 Looper? App 的入口并非 MainActivity,也不是 Application,而是 ActivityThread。

其為了 Application、ContentProvider、Activity 等組件的運(yùn)行,必須事先啟動(dòng)不停接受輸入的 Looper 機(jī)制,所以在 main() 執(zhí)行的**將調(diào)用 prepareMainLooper() 創(chuàng)建 Looper 并調(diào)用 loop() 輪循。 不需要我們調(diào)用,也不可能有我們調(diào)用。 可以說(shuō)如果主線(xiàn)程沒(méi)有創(chuàng)建 Looper 的話(huà),我們的組件也不可能運(yùn)行得到! 5. Handler 或者說(shuō) Looper 如何切換線(xiàn)程? Handler 創(chuàng)建的時(shí)候指定了其所屬線(xiàn)程的 Looper,進(jìn)而持有了 Looper 獨(dú)有的 MessageQueue Looper#loop() 會(huì)持續(xù)讀取 MessageQueue 中合適的 Message,沒(méi)有 Message 的時(shí)候進(jìn)入等待 當(dāng)向 Handler 發(fā)送 Message 或 Runnable 后,會(huì)向持有的 MessageQueue 中插入 Message Message 抵達(dá)并滿(mǎn)足條件后會(huì)喚醒 MessageQueue 所屬的線(xiàn)程,并將 Message 返回給 Looper Looper 接著回調(diào) Message 所指向的 Handler Callback 或 Runnable,達(dá)到線(xiàn)程切換的目的 簡(jiǎn)言之,向 Handler 發(fā)送 Message 其實(shí)是向 Handler 所屬線(xiàn)程的獨(dú)有 MessageQueue 插入 Message。

而線(xiàn)程獨(dú)有的 Looper 又會(huì)持續(xù)讀取該 MessageQueue。所以向其他線(xiàn)程的 Handler 發(fā)送完 Message,該線(xiàn)程的 Looper 將自動(dòng)響應(yīng)。 6. Looper 的 loop() *循環(huán)為什么不卡*? 為了讓主線(xiàn)程持續(xù)處理用戶(hù)的輸入,loop() 是 *循環(huán) ,持續(xù)調(diào)用 MessageQueue#next()?讀取合適的 Message。 但當(dāng)沒(méi)有 Message 的時(shí)候,會(huì)調(diào)用?pollOnce()?并通過(guò) Linux 的?epoll?機(jī)制進(jìn)入等待并釋放資源。

同時(shí)?eventFd?會(huì)監(jiān)聽(tīng) Message 抵達(dá)的寫(xiě)入事件并進(jìn)行喚醒。 這樣可以 空閑時(shí)釋放資源、不卡*線(xiàn)程,同時(shí)能持續(xù)接收輸入的目的 。 彩蛋1:loop() 后的處理為什么不可執(zhí)行 因?yàn)?loop() 是*循環(huán),直到 quit 前后面的處理無(wú)法得到執(zhí)行,所以避免將處理放在 loop() 的后面。 彩蛋2:Looper 等待的時(shí)候線(xiàn)程到底是什么狀態(tài)? 調(diào)用 Linux 的 epoll 機(jī)制進(jìn)入 等待 ,事實(shí)上 Java 側(cè)打印該線(xiàn)程的狀態(tài),你會(huì)發(fā)現(xiàn)線(xiàn)程處于?Runnable?狀態(tài),只不過(guò) CPU 資源被暫時(shí)釋放。

7. Looper 的等待是如何能夠準(zhǔn)確喚醒的? 讀取合適 Message 的 MessageQueue#next() 會(huì)因?yàn)?Message 尚無(wú)或執(zhí)行條件尚未滿(mǎn)足進(jìn)行兩種等的等待: 無(wú)限等待 尚無(wú) Message(隊(duì)列中沒(méi)有 Message 或建立了同步屏障但尚無(wú)異步 Message)的時(shí)候,調(diào)用 Natvie 側(cè)的?pollOnce()?會(huì)傳入?yún)?shù)?-1 。 Linux 執(zhí)行?epoll_wait()?將進(jìn)入無(wú)限等待,其等待合適的 Message 插入后調(diào)用 Native 側(cè)的?wake()?向喚醒 fd 寫(xiě)入事件觸發(fā)喚醒 MessageQueue 讀取的下一次循環(huán) 有限等待 有限等待的場(chǎng)合將下一個(gè) Message?剩余時(shí)長(zhǎng)作為參數(shù) 交給 epoll_wait(),epoll 將等待一段時(shí)間之后 自動(dòng)返回 ,接著回到 MessageQueue 讀取的下一次循環(huán) 8. Message 如何獲???為什么這么設(shè)計(jì)? 享元設(shè)計(jì)模式:通過(guò) Message 的靜態(tài)方法?obatin()?獲取,因?yàn)樵摲椒ú皇菬o(wú)腦地 new,而是 從單鏈表池子里獲取實(shí)例 ,并在?recycle()?后將其放回池子 好處在于復(fù)用 Message 實(shí)例,滿(mǎn)足頻繁使用 Message 的場(chǎng)景,更加高效 當(dāng)然,緩存池存在上限?50 ,因?yàn)闆](méi)必要無(wú)限制地緩存,這本身也是一種浪費(fèi) 需要留意緩存池是靜態(tài)的,也就是整個(gè)進(jìn)程共用一個(gè)緩存池 9. MessageQueue 如何管理 Message? MessageQueue 通過(guò)單鏈表管理 Message,不同于進(jìn)程共用的 Message Pool,其是線(xiàn)程獨(dú)有的 通過(guò) Message 的執(zhí)行時(shí)刻 when 對(duì) Message 進(jìn)行排隊(duì)和出隊(duì) MessageQueue 除了管理 Message,還要管理空閑 Handler 和 同步屏障 10. 理解 Message 和 MessageQueue 的異同? 相同點(diǎn):都是通過(guò) 單鏈表來(lái)管理 Message 實(shí)例; Message 通過(guò)?obtain() 和 recycle() 向單鏈表獲取插入節(jié)點(diǎn) MessageQueue 通過(guò)?enqueueMessage() 和 next() 向單鏈表獲取和插入節(jié)點(diǎn) 區(qū)別: Message 單鏈表是 靜態(tài)的,供進(jìn)程使用的緩存池 MessageQueue 單鏈表 非靜態(tài),只供 Looper 線(xiàn)程使用 11. Message 的執(zhí)行時(shí)刻如何管理? 發(fā)送的 Message 都是按照?qǐng)?zhí)行時(shí)刻?when?屬性的先后管理在 MessageQueue 里 延時(shí) Message 的 when 等于調(diào)用的當(dāng)前時(shí)刻和?delay?之和 非延時(shí) Message 的 when 等于當(dāng)前時(shí)刻(delay 為?0) 插隊(duì) Message 的 when 固定為?0,便于插入隊(duì)列的?head 之后 MessageQueue 會(huì)根據(jù) 讀取的時(shí)刻和 when 進(jìn)行比較 將 when 已抵達(dá)的出隊(duì), 尚未抵達(dá)的計(jì)算出 當(dāng)前時(shí)刻和目標(biāo) when 的插值 ,交由 Native 等待對(duì)應(yīng)的時(shí)長(zhǎng),時(shí)間到了自動(dòng)喚醒繼續(xù)進(jìn)行 Message 的讀取 事實(shí)上,無(wú)論上述哪種 Message 都不能保證在其對(duì)應(yīng)的 when 時(shí)刻執(zhí)行,往往都會(huì)延遲一些!因?yàn)楸仨毜犬?dāng)前執(zhí)行的 Message 處理完了才有機(jī)會(huì)讀取隊(duì)列的下一個(gè) Message。 比如發(fā)送了非延時(shí) Message,when 即為發(fā)送的時(shí)刻,可它們不會(huì)立即執(zhí)行。都要等主線(xiàn)程現(xiàn)有的任務(wù)(Message)走完才能有機(jī)會(huì)出隊(duì),而當(dāng)這些任務(wù)執(zhí)行完 when 的時(shí)刻已經(jīng)過(guò)了。

假使隊(duì)列的前面還有其他 Message 的話(huà),延遲會(huì)更加明顯! 彩蛋:. onCreate() 里向 Handler 發(fā)送大量 Message 會(huì)導(dǎo)致主線(xiàn)程卡頓嗎? 不會(huì),發(fā)送的大量 Message 并非立即執(zhí)行,只是先放到隊(duì)列當(dāng)中而已。 onCreate() 以及之后同步調(diào)用的 onStart() 和 onResume() 處理,本質(zhì)上也是 Message。等這個(gè) Message 執(zhí)行完之后,才會(huì)進(jìn)行讀取 Message 的下一次循環(huán),這時(shí)候才能回調(diào) onCreate 里發(fā)送的 Message。

需要說(shuō)明的是,如果發(fā)送的是 FrontOfQueue 將 Message 插入隊(duì)首也不會(huì)立即先執(zhí)行,因?yàn)?onStart 和 onResume 是 onCreate 之后同步調(diào)用的,本質(zhì)上是同一個(gè) Message 的作業(yè)周期 12. Handler、Mesage 和 Runnable 的關(guān)系如何理解? 作為使用 Handler 機(jī)制的入口, Handler 是發(fā)送 Message 或 Runnable 的起點(diǎn) 發(fā)送的?Runnable 本質(zhì)上也是 Message ,只不過(guò)作為?callback?屬性被持有 Handler 作為?target?屬性被持有在 Mesage 中 ,在 Message 執(zhí)行條件滿(mǎn)足的時(shí)候供 Looper 回調(diào) 事實(shí)上,Handler 只是供 App 使用 Handler 機(jī)制的 API,實(shí)質(zhì)來(lái)說(shuō),Message 是更為重要的載體。 13. IdleHandler 空閑 Message 了解過(guò)嗎?有什么用? 適用于期望 空閑時(shí)候執(zhí)行,但不影響主線(xiàn)程操作 的任務(wù) 系統(tǒng)應(yīng)用: Activity?destroy?回調(diào)就放在了?IdleHandler?中 ActivityThread?中?GCHandler?使用了 IdleHandler,在空閑的時(shí)候執(zhí)行?GC 操作 App 應(yīng)用: 發(fā)送一個(gè)返回 true 的 IdleHandler,在里面讓某個(gè) View 不停閃爍,這樣當(dāng)用戶(hù)發(fā)呆時(shí)就可以誘導(dǎo)用戶(hù)點(diǎn)擊這個(gè) View 將某部分初始化放在 IdleHandler 里不影響 Activity 的啟動(dòng) 14. 異步 Message 或同步屏障了解過(guò)嗎?怎么用?什么原理? 異步 Message:設(shè)置了?isAsync?屬性的 Message 實(shí)例 可以用異步 Handler 發(fā)送 也可以調(diào)用 Message#setAsynchronous()?直接設(shè)置為異步 Message 同步屏障:在 MessageQueue 的 某個(gè)位置放一個(gè) target 屬性為 null 的 Message ,確保此后的非異步 Message 無(wú)法執(zhí)行,只能執(zhí)行異步 Message 原理:當(dāng) MessageQueue 輪循 Message 時(shí)候 發(fā)現(xiàn)建立了同步屏障的時(shí)候,會(huì)去跳過(guò)其他 Message,讀取下個(gè) async 的 Message 并執(zhí)行,屏障移除之前同步 Message 都會(huì)被阻塞 應(yīng)用:比如 屏幕刷新?Choreographer?就使用到了同步屏障 ,確保屏幕刷新事件不會(huì)因?yàn)殛?duì)列負(fù)荷影響屏幕及時(shí)刷新。 注意: 同步屏障的添加或移除 API 并未對(duì)外公開(kāi),App 需要使用的話(huà)需要依賴(lài)反射機(jī)制 15. Looper 和 MessageQueue、Message 及 Handler 的關(guān)系? Message 是承載任務(wù)的載體,在 Handler 機(jī)制中貫穿始終 Handler 則是對(duì)外公開(kāi)的 API,負(fù)責(zé)發(fā)送 Message 和處理任務(wù)的回調(diào),是?Message 的生產(chǎn)者 MessagQueue 負(fù)責(zé)管理待處理 Message 的入隊(duì)和出隊(duì),是?Message 的容器 Looper 負(fù)責(zé)輪循 MessageQueue,保持線(xiàn)程持續(xù)運(yùn)行任務(wù),是?Message 的消費(fèi)者 彩蛋:如何保證 MessageQueue 并發(fā)訪(fǎng)問(wèn)安全? 任何線(xiàn)程都可以通過(guò) Handler 生產(chǎn) Message 并放入 MessageQueue 中,可 Queue 所屬的 Looper 在持續(xù)地讀取并嘗試消費(fèi) Message。

如何保證兩者不產(chǎn)生*鎖? Looper 在消費(fèi) Message 之前要先拿到 MessageQueue 的鎖, 只不過(guò)沒(méi)有 Message 或 Message 尚未滿(mǎn)足條件的進(jìn)行等待前會(huì)事先釋放鎖 ,具體在于 nativePollOnce() 的調(diào)用在 synchronized 方法塊的外側(cè)。 Message 入隊(duì)前也需先拿到 MessageQueue 的鎖,而這時(shí) Looper 線(xiàn)程正在等待且不持有鎖,可以確保 Message 的成功入隊(duì)。入隊(duì)后執(zhí)行喚醒后釋放鎖,Native 收到 event 寫(xiě)入后恢復(fù) MessagQueue 的讀取并可以拿到鎖,成功出隊(duì)。 這樣一種在沒(méi)有 Message 可以消費(fèi)時(shí)執(zhí)行等待同時(shí)不占著鎖的機(jī)制,避免了生產(chǎn)和消費(fèi)的*鎖。

16. Native 側(cè)的 NativeMessageQueue 和 Looper 的作用是? NativeMessageQueue 負(fù)責(zé)連接 Java 側(cè)的 MessageQueue,進(jìn)行后續(xù)的?wait?和?wake,后續(xù)將創(chuàng)建 wake 的FD,并通過(guò) epoll 機(jī)制等待或喚醒。 但并不參與管理 Java 的 Message Native 側(cè)也需要 Looper 機(jī)制,等待和喚醒的需求是同樣的,所以將這部分實(shí)現(xiàn)都封裝到了 JNI 的NativeMessageQueue 和 Native 的 Looper 中, 供 Java 和 Native 一起使用 17. Native 側(cè)如何使用 Looper? Looper Native 部分承擔(dān)了 Java 側(cè) Looper 的等待和喚醒,除此之外其還提供了 Message、MessageHandler?或?WeakMessageHandler、LooperCallback?或?SimpleLooperCallback?等 API 這些部分可供 Looper 被 Native 側(cè)直接調(diào)用,比如?InputFlinger?廣泛使用了 Looper 主要方法是調(diào)用 Looper 構(gòu)造函數(shù)或 prepare 創(chuàng)建 Looper,然后通過(guò) poll 開(kāi)始輪詢(xún),接著?sendMessage?或?addEventFd,等待 Looper 的喚醒。 使用過(guò)程和 Java 的調(diào)用思路類(lèi)似 18. Handler 為什么可能導(dǎo)致內(nèi)存泄露?如何避免? 持有 Activity 實(shí)例的內(nèi)名內(nèi)部類(lèi)或內(nèi)部類(lèi)的 生命周期 應(yīng)當(dāng)和 Activity 保持一致,否則產(chǎn)生內(nèi)存泄露的風(fēng)險(xiǎn)。

如果 Handler 使用不當(dāng),將造成不一致,表現(xiàn)為:匿名內(nèi)部類(lèi)或內(nèi)部類(lèi)寫(xiě)法的 Handler、Handler$Callback、Runnable,或者Activity 結(jié)束時(shí)仍有活躍的 Thread 線(xiàn)程或 Looper 子線(xiàn)程 具體在于:異步任務(wù)仍然活躍或通過(guò)發(fā)送的 Message 尚未處理完畢,將使得內(nèi)部類(lèi)實(shí)例的 生命周期被錯(cuò)誤地延長(zhǎng) 。造成本該回收的 Activity 實(shí)例 被別的?Thread?或?Main Looper?占據(jù)而無(wú)法及時(shí)回收 (活躍的 Thread 或 靜態(tài)屬性 sMainLooper 是 GC Root 對(duì)象) 建議的做法: 無(wú)論是 Handler、Handler$Callback 還是 Runnable,盡量采用 靜態(tài)內(nèi)部類(lèi) + 弱引用 的寫(xiě)法,確保盡管發(fā)生不當(dāng)引用的時(shí)候也可以因?yàn)槿跻媚芮宄钟嘘P(guān)系 另外在 Activity 銷(xiāo)毀的時(shí)候及時(shí)地 終止 Thread、停止子線(xiàn)程的 Looper 或清空 Message ,確保徹底切斷 Activity 經(jīng)由 Message 抵達(dá) GC Root 的引用源頭(Message 清空后會(huì)其與 Handler 的引用關(guān)系,Thread 的終止將結(jié)束其 GC Root 的源頭) 注意:靜態(tài)的 sThreadLocal 實(shí)例不持有存放 Looper 實(shí)例的 ThreadLocalMap,而是由 Thread 持有。從這個(gè)角度上來(lái)講,Looper 會(huì)被活躍的 GC Root Thread 持有,進(jìn)而也可能導(dǎo)致內(nèi)存泄露。 彩蛋:網(wǎng)傳的 Handler$Callback 方案能否解決內(nèi)存泄露? 不能。

Callback 采用內(nèi)部類(lèi)或匿名內(nèi)部類(lèi)寫(xiě)法的話(huà),默認(rèn)持有 Activity 的引用,而 Callback 被 Handler 持有。這最終將導(dǎo)致 Message -> Handler -> Callback -> Activity 的鏈條仍然存在。 19. Handler 在系統(tǒng)當(dāng)中的應(yīng)用 特別廣泛,比如: Activity 生命周期的管理 屏幕刷新 HandlerThread、IntentService AsyncTask 等。

主要利用 Handler 的切換線(xiàn)程、主線(xiàn)程異步 Message 的重要特性。注意:Binder 線(xiàn)程非主線(xiàn)程,但很多操作比如生命周期的管理?。