Android進(jìn)階之路——線程機(jī)制

? ? 今天leo主要總結(jié)線程方面的,分為以下幾個(gè)知識(shí)點(diǎn):

? 認(rèn)識(shí)線程

? 線程的基本用法

? 線程同步

? 子線程更新UI

? 線程間通信機(jī)制

? ? Android是單線程模型,我們創(chuàng)建的Service、Activity以及Broadcast均是在一個(gè)主線程處理,這里我們可以理解為UI線程。

? ? 但是在操作一些耗時(shí)操作時(shí),比如I/O讀寫的大文件讀寫,數(shù)據(jù)庫操作以及網(wǎng)絡(luò)下載需要很長(zhǎng)時(shí)間,為了不阻塞用戶界面,出現(xiàn)ANR的響應(yīng)提示窗口,這個(gè)時(shí)候我們考慮使用Thread線程來解決。

? 進(jìn)程與線程

? ? 線程是指進(jìn)程內(nèi)的一個(gè)執(zhí)行單元,也是進(jìn)程內(nèi)的可調(diào)度實(shí)體,與進(jìn)程的區(qū)別:

(1)地址空間: 進(jìn)程內(nèi)的一個(gè)執(zhí)行單元;進(jìn)程至少有一個(gè)線程,它們共享進(jìn)程的地址空間;而進(jìn)程有自己獨(dú)立的地址空間;

(2)資源擁有: 進(jìn)程是資源分配和擁有的單位,同一個(gè)進(jìn)程內(nèi)的線程共享進(jìn)程的資源;

(3)線程是處理器調(diào)度的基本單位,但進(jìn)程不是;

(4)二者均可并發(fā)執(zhí)行。

? 實(shí)現(xiàn)?

? ? ? 繼承java.lang.Thread類

? ? ? 實(shí)現(xiàn)Runnable接口

? 啟動(dòng)

? ? Thread類代表線程類,它的兩個(gè)最主要的方法是:

? ? ? run()--包含線程運(yùn)行時(shí)所執(zhí)行的代碼

? ? ? Start()--用于啟動(dòng)線程

? 通信

? ? Handler機(jī)制,它是Runnable和Activity交互的橋梁,在run方法中發(fā)送Message,在Handler里,通過不同的Message執(zhí)行不同的任務(wù)。

? 簡(jiǎn)介

? ? 當(dāng)使用多個(gè)線程來訪問同一個(gè)數(shù)據(jù)時(shí),非常容易出現(xiàn)線程安全問題(比如多個(gè)線程都在操作同一數(shù)據(jù)導(dǎo)致數(shù)據(jù)不一致),所以我們用同步機(jī)制來解決這些問題。

? 實(shí)現(xiàn)方法

? ? ? 同步代碼塊:synchronized(同一個(gè)數(shù)據(jù)){} 同 ? ? ? 一個(gè)數(shù)據(jù):就是N條線程同時(shí)訪問一個(gè)數(shù)據(jù)。

? ? ? 同步方法:public synchronized 數(shù)據(jù)返回類 ? ? ? 型 方法名(){}

? 子線程更新UI的四種方法

? ? 1. handle.post(Runnable r)

? ? 2. handle.handleMessage(Message msg)

? ? 3. runOnUiThread(Runnable r)

? ? 4. View.post(Runnable r)

? 用于線程間通訊的類

? ? 1.?Handler :在android里負(fù)責(zé)發(fā)送和處理消息,通過它可以實(shí)現(xiàn)其他線程與Main線程之間的消息通訊。

? ? 2. Looper:負(fù)責(zé)管理線程的消息隊(duì)列和消息循環(huán)?。

? ? 3. Message??:線程間通訊的消息載體。兩個(gè)碼頭之間運(yùn)輸貨物,Message充當(dāng)集裝箱的功能,里面可以存放任何你想要傳遞的消息。

? ? 4. MessageQueue:消息隊(duì)列,先進(jìn)先出,它的作用是保存有待線程處理的消息。

Android多線程機(jī)制

一、使用線程

? ? 1. 任何耗時(shí)的處理過程都會(huì)降低用戶界面的響應(yīng)速度,甚至導(dǎo)致用戶界面失去響應(yīng),當(dāng)用戶界面失去響應(yīng)超過5秒鐘,Android系統(tǒng)會(huì)允許用戶強(qiáng)行關(guān)閉應(yīng)用程序。

? ? 2. 較好的解決方法是將耗時(shí)的處理過程轉(zhuǎn)移到子線程上,這樣可以避免負(fù)責(zé)界面更新的主線程無法處理界面事件,從而避免用戶界面長(zhǎng)時(shí)間失去響應(yīng)。

? ? 3. 線程是獨(dú)立的程序單元,多個(gè)線程可以并行工作。

? ? 4. 在多處理器系統(tǒng)中,每個(gè)中央處理器(CPU)單獨(dú)運(yùn)行一個(gè)線程,因此線程是并行工作的。

? ? 5.? 在單處理器系統(tǒng)中,處理器會(huì)給每個(gè)線程一小段時(shí)間,在這個(gè)時(shí)間內(nèi)線程是被執(zhí)行的,然后處理器執(zhí)行下一個(gè)線程,這樣就產(chǎn)生了線程并行運(yùn)行的假象。

? ? 6. 無論線程是否真的并行工作,在宏觀上可以認(rèn)為子線程是獨(dú)立于主線程,且能與主線程并行工作的程序單元。

? ? 7. Android中的線程是基于Java定義的線程,其內(nèi)部結(jié)構(gòu)如圖所示:

? ? 8. 一個(gè)應(yīng)用程序中可能會(huì)包含多個(gè)線程(Thread),每個(gè)線程中都有一個(gè)run()方法,run()方法內(nèi)部的程序執(zhí)行完畢后,所在的線程就自動(dòng)結(jié)束。

? ? 9. 每個(gè)線程都有一個(gè)消息隊(duì)列,用于不同的線程之間傳遞消息。在run()方法內(nèi)部,如果不主動(dòng)去讀取消息隊(duì)列中的消息,這些消息就是一些無用的消息,因?yàn)樗鼈儧]有被處理。

? ? 10. 在Android系統(tǒng)中,讀取消息和處理消息是兩個(gè)步驟,并由兩個(gè)不同的部分完成,先讀取消息,然后才能處理消息。

? ? 11. 無論是本線程的還是其它線程,都不能直接處理消息隊(duì)列中的消息,而是需要通過在線程內(nèi)部定義一個(gè)Handler類對(duì)象來處理消息隊(duì)列。一個(gè)Thread只能包含一個(gè)Handler對(duì)象。在實(shí)際應(yīng)用中,讀取消息隊(duì)列一般需要循環(huán)執(zhí)行,即不斷地從消息隊(duì)列中獲取消息并進(jìn)行相應(yīng)處理,這就又需要一個(gè)Looper對(duì)象。

? ? 12. Looper對(duì)象用于循環(huán)讀取消息隊(duì)列的值,并回調(diào)Handler對(duì)象中定義的消息處理函數(shù),同時(shí),Looper對(duì)象還可以將讀取的消息從隊(duì)列中移除,執(zhí)行完一次消息處理后,再循環(huán)從消息隊(duì)列中讀取下一個(gè)消息,直到Looper對(duì)象調(diào)用stop()方法退出循環(huán)。如果消息隊(duì)列中沒有消息,Looper對(duì)象則會(huì)等待,線程不會(huì)退出。

? ? 13. 為了更方便地從線程中使用Looper功能,Android又定義了一個(gè)HandlerThread類,該類基于Thread,并且內(nèi)部已經(jīng)添加了Looper功能,使用者只需重寫其onLooperPrepared ()方法,添加具體應(yīng)用代碼即可。Android中一個(gè)Activity就是一個(gè)線程,多個(gè)Activity之間的切換是在同一個(gè)線程中。

二、Android中Activity的調(diào)用流程

? ? 1. 以上偽代碼中,while(1)循環(huán)用于指定該Thread一直執(zhí)行,永不退出,直到被操作系統(tǒng)殺掉。

? ? 2. if(hasHandler())語句判斷該Thread中是否定義了Handler對(duì)象,該Handler對(duì)象是由應(yīng)用程序定義的(也可不定義)。

? ? 3. 如果有該對(duì)象,那么就會(huì)讀取Thread中消息隊(duì)列的值,并做一定的處理。執(zhí)行完一個(gè)消息后,接著需要執(zhí)行Activity中的用戶界面響應(yīng),例如是否有按鍵按下、觸摸屏是否按下等。 處理完一次用戶消息響應(yīng)后,則繼續(xù)循環(huán)讀取Thread中消息隊(duì)列的值。

三、MessageQueue、Looper、Handler調(diào)用關(guān)系

? ? 1. 在以上這個(gè)大循環(huán)中,Handler對(duì)象對(duì)應(yīng)的就是Handler.handleMessage()部分完成的功能,Looper對(duì)象對(duì)應(yīng)的就是整個(gè)while(1)循環(huán)控制和MessageQueue.getMessage()完成的功能。

? ? 2. Looper對(duì)象負(fù)責(zé)從線程的消息隊(duì)列中循環(huán)讀取消息值,再將這些消息傳遞給Handler對(duì)象,Handler對(duì)象中定義的消息處理函數(shù)會(huì)根據(jù)消息類型再調(diào)用Thread中定義的其它函數(shù)。如果Thread中沒有Looper對(duì)象,那么Thread的執(zhí)行體就無法讀取消息隊(duì)列;如果Thread中沒有Handler對(duì)象,則不會(huì)處理任何消息。

? ? 3. 一般情況下, Handler和Looper是同時(shí)使用的,要么同時(shí)有,要么同時(shí)沒有。

Android多線程定義

一、線程定義

? ? 1. Android中定義線程的方法與Java相同,可以使用兩種方法:一種是Thread類,另一種是Runnable接口。

? ? 2. Thread是一個(gè)類,根據(jù)Java繼承風(fēng)格,一個(gè)類只能有一個(gè)父類,繼承了Thread的子類不能再繼承其它類,這是一個(gè)缺陷。于是,出現(xiàn)了Runnable,其作用和Thread相同,都是啟動(dòng)另一個(gè)線程,不同的是,Runnable是一個(gè)接口(interface),因此可以同時(shí)實(shí)現(xiàn)多個(gè)接口。

? ? 3. Android中使用Thread與Java基本相同,所不同的是,Android拋棄了Java線程中一些不安全的做法。比如:終止一個(gè)Thread,在Java中可以調(diào)用線程名字.stop()、線程名字.destroy()等;而在Android中,這些方法都沒有實(shí)現(xiàn),即不能使用。

? ? 4. 新建一個(gè)Thread對(duì)象,需要實(shí)現(xiàn)兩個(gè)方法:

? ? ? 第一個(gè)是定義構(gòu)造方法。在Android程序中,新建的線程多為Activity、Service等程序片斷服 ? ? ? 務(wù),而在線程的內(nèi)部執(zhí)行過程中,很多時(shí)候都需要使用應(yīng)用程序內(nèi)部的Context對(duì)象,因此, ? ? ? 在實(shí)際應(yīng)用中,線程的構(gòu)造方法往往會(huì)傳遞應(yīng)用程序的Context對(duì)象,從而在線程的內(nèi)部可以 ? ? ? 調(diào)用Context相關(guān)的系統(tǒng)服務(wù)。當(dāng)然,這不是必須的。

? ? ?第二個(gè)是run()方法。該方法是Thread對(duì)象中必須實(shí)現(xiàn)的方法,用于完成具體的任務(wù)。啟動(dòng)線 ? ? ? 程時(shí),不能直接調(diào)用線程名字.run()方法,而是調(diào)用線程名字.start()方法啟動(dòng),start()方法是 ? ? ? ? Thread內(nèi)部使用的,該方法包含初始化線程的工作,然后回調(diào)run()方法,這些對(duì)應(yīng)用程序都 ? ? ? ? 是不可見的。

? ? 5. 停止線程時(shí),不能調(diào)用線程名字.destroy()方法或者線程名字.stop()方法。run()方法執(zhí)行完畢后,線程默認(rèn)會(huì)自動(dòng)停止。因此,如果需要線程循環(huán)執(zhí)行run()方法內(nèi)部的代碼,可以在線程內(nèi)部增加一個(gè)狀態(tài)變量,run()方法內(nèi)部通過檢查該狀態(tài)變量,決定是否繼續(xù)執(zhí)行;同時(shí)可在線程外設(shè)置該狀態(tài)變量的值,從而終止該線程。

二、線程定義thread

? ? 1. 線程定義Thread,繼承Thread類,并重寫run()方法。在run()中放置代碼的主體部分。

? ? 2. 以上代碼包括3個(gè)基本方法:Thread1()為構(gòu)造方法,用于保存調(diào)用者的Context對(duì)象,供以后可能使用;run()方法內(nèi)部是應(yīng)用代碼;setToStop()用于設(shè)置全局變量mRunState的值,run()內(nèi)部循環(huán)執(zhí)行時(shí)會(huì)判斷該值,決定是否退出run()方法,即終止該線程。

? ? 3. 要在Activity啟動(dòng)Thread1,首先需要定義一個(gè)Thread1對(duì)象,并使用構(gòu)造方法將Activity的Context對(duì)象傳遞給Thread1,然后調(diào)用線程的start()方法啟動(dòng)Thread1線程。要終止Thread的運(yùn)行,可調(diào)用自定義的Thread1的setToStop()方法。

? ? 4. 以上代碼中,id值為action_stop的按鈕,用于停止Thread1的運(yùn)行。這是Android系統(tǒng)建議的啟動(dòng)線程和退出線程的方法。

三、線程定義Runnable

? ? 1. Runnable的作用和Thread基本相同,都是用于定義一個(gè)線程,但兩者本質(zhì)上有重要區(qū)別。

? ? 2. 第一:Runnable只是一個(gè)接口(interface),其內(nèi)部沒有定義任何已實(shí)現(xiàn)的方法。因此,要使用與線程有關(guān)的方法,只能使用Thread的靜態(tài)方法,比如:不能直接調(diào)用sleep(),而要調(diào)用Thread.sleep()方法。

? ? 3. 第二:定義一個(gè)Thread對(duì)象,就意味著創(chuàng)建了一個(gè)新線程,而定義一個(gè)Runnable對(duì)象,只是定義了一個(gè)可以當(dāng)作線程運(yùn)行的代碼對(duì)象,并沒有創(chuàng)建新線程。因此,如果調(diào)用Runnable對(duì)象的run()方法,僅相當(dāng)于把Runnable對(duì)象當(dāng)作普通類對(duì)象進(jìn)行調(diào)用,并沒有啟動(dòng)一個(gè)新線程,Runnable對(duì)象和調(diào)用者在同一個(gè)線程中運(yùn)行。

? ? 4. 如果要?jiǎng)?chuàng)建一個(gè)新線程,則還需要將Runnable對(duì)象傳入Thread的構(gòu)造方法,從而創(chuàng)建一個(gè)新線程,新線程的執(zhí)行碼就是Runnable所定義的。

? ? 5. 第三:Runnable對(duì)象經(jīng)常被當(dāng)作參數(shù)傳遞給一些與線程有關(guān)的方法,用于啟動(dòng)一個(gè)新的線程。

? ? 6. 實(shí)現(xiàn)Java的Runnable接口,并重載run()方法。在run()中放置代碼的主體部分

? ? 7. 創(chuàng)建Thread對(duì)象,并將上面實(shí)現(xiàn)的Runnable對(duì)象作為參數(shù)傳遞給Thread對(duì)象

? ? ① Thread的構(gòu)造函數(shù)中,第1個(gè)參數(shù)用來表示線程組。

? ? ② 第2個(gè)參數(shù)是需要執(zhí)行的Runnable對(duì)象。

? ? ③ 第3個(gè)參數(shù)是線程的名稱。

? ? 8. 調(diào)用start()方法啟動(dòng)線程。直接用workThread.start();

? ? 9. 線程在run()方法返回后,線程就自動(dòng)終止了;不推薦使用調(diào)用stop()方法在外部終止線程。

? ? 10. 最好的方法是通知線程自行終止,一般調(diào)用interrupt()方法通告線程準(zhǔn)備終止,線程會(huì)釋放它正在使用的資源,在完成所有的清理工作后自行關(guān)閉。方法是workThread.interrupt();

? ? ① interrupt()方法并不能直接終止線程,僅是改變了線程內(nèi)部的一個(gè)布爾字段,run()方法能夠檢測(cè)到這個(gè)布爾字段,從而知道何時(shí)應(yīng)該釋放資源和終止線程

? ? ② 在run()方法的代碼,一般通過Thread.interrupted()方法查詢線程是否被中斷

? ? 11. 下面的代碼是以1秒為間隔循環(huán)檢測(cè)斷線程是否被中斷

? ? ① 第4行代碼使線程休眠1000毫秒。

? ? ② 當(dāng)線程在休眠過程中被中斷,則會(huì)產(chǎn)生InterruptedException 。

? ? ③ 在中斷的線程上調(diào)用sleep()方法,同樣會(huì)產(chǎn)生InterruptedException。

? ? 12. Thread.interrupted()方法功能

? ? ① 判斷線程是否應(yīng)被中斷。

? ? ② 通過捕獲InterruptedException判斷線程是否應(yīng)被中斷,并且在捕獲到InterruptedException后,安全終止線程。

Handler

一、使用Handler

? ? 1. Handler用于處理線程中的消息隊(duì)列。當(dāng)Looper對(duì)象從消息隊(duì)列中獲取消息后,會(huì)把消息派發(fā)給Handler對(duì)象。一個(gè)線程中只能有一個(gè)Handler對(duì)象,可以通過該對(duì)象向所在線程發(fā)送消息。因此,只要擁有其它線程中Handler對(duì)象的引用,就可以向其發(fā)送消息;除了給別的線程發(fā)送消息外,還可以給本線程發(fā)送消息。

? ? 2. Handler一般有兩種用途:

? ? ① 實(shí)現(xiàn)一個(gè)定時(shí)任務(wù)。這個(gè)有點(diǎn)類似于Windows中的定時(shí)器功能,可以通過Handler對(duì)象向所在線程發(fā)送一個(gè)延時(shí)消息。當(dāng)消息指定的時(shí)間到達(dá)后,通過Handler對(duì)象的消息處理方法完成指定任務(wù)。

? ? ② 在線程間傳遞數(shù)據(jù)。

? ? 3. Handler完成定時(shí)任務(wù):

? ? ① 在一個(gè)Activity內(nèi)部,經(jīng)常需要做一些定時(shí)器的功能,比如周期性更新某個(gè)視圖的內(nèi)容、在指定時(shí)間后結(jié)束某個(gè)操作等。

? ? ② 完成定時(shí)任務(wù),可以通過Handler對(duì)象的延遲發(fā)送消息方法來實(shí)現(xiàn)。

? ? ③ 在介紹發(fā)送消息之前,需要先了解一下消息Message的數(shù)據(jù)結(jié)構(gòu)。Message是一個(gè)描述消息的數(shù)據(jù)結(jié)構(gòu)類,Message包含很多成員變量和方法,但對(duì)于簡(jiǎn)單的消息處理,一般僅需了解3項(xiàng),分別是:⑴ int what 這是用戶自定義的一個(gè)整型值,用于區(qū)分消息類型。⑵ int arg1 這是額外消息參數(shù)。⑶ int arg2 同arg1。

? ? 對(duì)于需要包含更多數(shù)據(jù)的消息,可以使用message.setData()和getData()方法。setData()方法用于把一個(gè)Bundle類數(shù)據(jù)對(duì)象加入到Message中,而getData()則是取出該Bundle數(shù)據(jù)。Bundle數(shù)據(jù)類型就是包含“鍵值對(duì)”數(shù)據(jù)的類型。

? ? 4. Handler發(fā)送消息的方式:

? ? ① 一類是postXXX()方法,該方法用于把一個(gè)Runnable對(duì)象發(fā)送到消息隊(duì)列。從而當(dāng)消息被處理時(shí),能夠執(zhí)行Runnable對(duì)象;

? ? ② 另一類是sendXXX()方法,該方法用于發(fā)送一個(gè)Message類型的消息到消息隊(duì)列,當(dāng)消息被處理時(shí),系統(tǒng)會(huì)調(diào)用Handler對(duì)象定義的handleMessage()方法處理該消息。

? ? 5. 實(shí)現(xiàn)定時(shí)任務(wù)則主要使用sendXXX()類,該類具體包含如下方法:

? ? ① sendEmptyMessage(int what),空消息是指該消息僅包含what值。

? ? ② sendEmptyMessageAtTime(int what, long uptimeMilis),在指定時(shí)間點(diǎn)發(fā)送空消息,uptimeMilis是指從本次開機(jī)開始運(yùn)行的時(shí)間點(diǎn),不包含系統(tǒng)休眠的時(shí)間,單位為毫秒。參照SystemClock類。

? ? ③ sendEmptyMessageDelayed(int what, long delayMillis),在指定時(shí)間后發(fā)送空消息,指定的時(shí)間以毫秒為單位。

? ? ④ sendMessage(Message),發(fā)送Message指定的消息。

? ? ⑤ sendMessageAtTime(Message,long),在指定時(shí)間點(diǎn)發(fā)送該消息。

? ? ⑥ sendMessageDelayed(Message, long),在指定的時(shí)間后發(fā)送該消息。

? ? 實(shí)現(xiàn)定時(shí)任務(wù)時(shí),一般使用sendMessageAtDelayed()或者sendEmptyMessageAtDelayed()方法,即在指定的時(shí)間后發(fā)送消息。當(dāng)收到該消息后,系統(tǒng)會(huì)調(diào)用Handler對(duì)象實(shí)現(xiàn)的消息處理接口handleMessage(),handleMessage()的參數(shù)是Message對(duì)象,可以通過Message的相關(guān)方法獲得Message的具體值,并根據(jù)其消息完成不同的任務(wù)。

二、Handler定時(shí)案例

? ? 1. handleMessage用于處理Activity所在線程接收到的消息,此處是把當(dāng)前時(shí)間顯示在文本框中。obtainMessage()方法用于從全局的消息池中獲得一個(gè)已有的Message對(duì)象,系統(tǒng)為了加速線程間的消息傳遞,創(chuàng)建了一些全局的消息對(duì)象供各線程使用,這些全局消息對(duì)象稱為全局消息池,使用該方法比重新創(chuàng)建一個(gè)消息對(duì)象的效率高。該方法的第一個(gè)參數(shù)用于指定初始化返回消息的what值。sendMessageDelayed()方法用于在1000毫秒后發(fā)送what值為100的消息,即在顯示完當(dāng)前時(shí)間后的1秒,再發(fā)送一次消息,從而可以每過1秒更新一次文本框的時(shí)間。此處使用100代表該消息類型。

? ? 2. 需要注意的是:在應(yīng)用程序運(yùn)行時(shí),當(dāng)用戶按Back鍵返回后,盡管Activity進(jìn)入了暫?;蛘咄V沟臓顟B(tài),但是消息的發(fā)送會(huì)依然在后臺(tái)執(zhí)行,因此,程序員需要根據(jù)情況決定是否要停止消息發(fā)送。例如可以在onPause()方法內(nèi)將消息隊(duì)列中的消息移除,并在onResume()方法中重新開始消息發(fā)送。removeMessage(100)方法用于移除消息隊(duì)列中what值為100的全部消息。

? ? 3. Handler完成線程間傳遞數(shù)據(jù)。

? ? ① 使用Handler對(duì)象不但可以給本線程發(fā)送消息,還可以給其它線程發(fā)送消息,前提是需要獲取其它線程中的Handler對(duì)象。

? ? ② 線程之間傳遞數(shù)據(jù)在GUI應(yīng)用中十分廣泛,比如后臺(tái)線程正在執(zhí)行具體的數(shù)據(jù)處理,前臺(tái)界面需要顯示出處理的進(jìn)度,典型的就是進(jìn)度對(duì)話框。在這種應(yīng)用中,前臺(tái)線程(一般是指Activity)創(chuàng)建一個(gè)后臺(tái)線程,并把前臺(tái)線程的Handler對(duì)象傳遞給后臺(tái)線程,后臺(tái)線程就可以通過該Handler對(duì)象向前臺(tái)線程發(fā)送消息,報(bào)告后臺(tái)數(shù)據(jù)處理的進(jìn)度。

Looper

? ? 1. Thread在默認(rèn)情況下,只要run()方法執(zhí)行完畢,線程就結(jié)束。簡(jiǎn)單控制線程不主動(dòng)退出的方法是:在run()方法內(nèi)部加一個(gè)while()循環(huán),這的確也能解決一些問題,對(duì)于那些不需要接收消息而言,基本上夠用了。

? ? 2. 但在另一些情況下,新建的線程需要接收消息并處理,因此,在新線程中,除了需要添加一個(gè)Handler對(duì)象外,還需要從線程的消息隊(duì)列中取出消息,并負(fù)責(zé)分發(fā)消息,這就需要Looper了。

? ? 3. 事實(shí)上,Activity內(nèi)部就有一個(gè)Looper,只是Activity是一個(gè)特殊的Thread,操作系統(tǒng)已經(jīng)將其封裝了而已。

? Looper往往和Handler同時(shí)使用

? ? 4. Looper.prepare()用于給該線程創(chuàng)建一個(gè)Looper對(duì)象;Looper.loop()用于開始執(zhí)行Looper對(duì)象,所謂的執(zhí)行就是讓Looper對(duì)象開始讀取線程的消息隊(duì)列,并派發(fā)消息到Handler對(duì)象的handleMessage()方法。

? ? 5. 請(qǐng)注意以上的someOtherFunction()方法,run()方法中,該方法只能被執(zhí)行一次,執(zhí)行完該方法后,開始執(zhí)行Looper.loop()方法,系統(tǒng)便進(jìn)入了Looper對(duì)象的世界里,以后就只會(huì)執(zhí)行handleMessage方法了。

? ? 6. 從LogCat的輸出結(jié)果來看,someOtherFunction()在線程啟動(dòng)后執(zhí)行一次。而Thread每收到一次what值為100的消息,method1()就會(huì)被執(zhí)行一次;當(dāng)thread收到what值為200的消息后,調(diào)用getLooper().quit()方法,Looper對(duì)象就停止運(yùn)行,run()方法會(huì)執(zhí)行完畢,該線程結(jié)束。

? ? 7. looperTest()方法中,開始時(shí)先創(chuàng)建后臺(tái)線程并啟動(dòng),然后調(diào)用線程的自定義方法getHandler()獲得后臺(tái)線程的Handler對(duì)象。注意此處使用do/while語句,線程在啟動(dòng)后其內(nèi)部的Handler對(duì)象不會(huì)馬上就緒,因此這里需要等待。

? ? 8. 接著讓兩個(gè)按鈕按下時(shí)分別發(fā)送what值為100和200的Message,用于執(zhí)行method1()方法和looper退出操作。

? ? HandlerThread類是一種內(nèi)部包含了Looper對(duì)象的Thread子類。該類是為了簡(jiǎn)化Looper的操作,使用時(shí)只需要重寫onLooperPrepared()方法,在其中添加一個(gè)Handler對(duì)象即可。其作用與在Thread中加入Looper對(duì)象和Handler對(duì)象是完全一樣的。onLooperPrepared()被調(diào)用的時(shí)機(jī)類似于在Thread中執(zhí)行完Looper.prepared()方法。

? ? 線程是獨(dú)立的程序單元,多個(gè)線程可以并行工作,每個(gè)線程都有一個(gè)消息隊(duì)列,用于不同的線程之間傳遞消息。無論是本線程的還是其它線程,都不能直接處理消息隊(duì)列中的消息,而是需要通過在線程內(nèi)部定義一個(gè)Handler類對(duì)象來處理消息隊(duì)列。

? ? leo這里給大家強(qiáng)調(diào)下一個(gè)Thread只能包含一個(gè)Handler對(duì)象。在實(shí)際應(yīng)用中,讀取消息隊(duì)列一般需要循環(huán)執(zhí)行,即不斷地從消息隊(duì)列中獲取消息并進(jìn)行相應(yīng)處理,這就又需要一個(gè)Looper對(duì)象。今天就leo就給大家總結(jié)到這了,希望對(duì)同是Android開發(fā)者的你們有用,如有什么指正建議,歡迎提出并聯(lián)系!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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