android項目課程的設計與實施國培thread_第1頁
android項目課程的設計與實施國培thread_第2頁
android項目課程的設計與實施國培thread_第3頁
android項目課程的設計與實施國培thread_第4頁
android項目課程的設計與實施國培thread_第5頁
已閱讀5頁,還剩55頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

Android項目課程的設計與實施(國培)第8天Android線程機制項目涉及技能#技能項重點難點隸屬課程1Activity組件√Android程序設計基礎2Boradcastreceiver組件√√Android程序設計基礎3線程√√Android程序設計基礎4Service組件√Android程序設計基礎5自定義組件(button)√√Android高級程序設計6文件讀寫與數(shù)據(jù)存儲√Android高級程序設計主要內(nèi)容認識線程線程的基本用法線程間通信機制AsyncTask子線程更新UI線程同步認識線程Android是單線程模型,我們創(chuàng)建的Service、Activity以及Broadcast均是在一個主線程處理,這里我們可以理解為UI線程。

但是在操作一些耗時操作時,比如I/O讀寫的大文件讀寫,數(shù)據(jù)庫操作以及網(wǎng)絡下載需要很長時間,為了不阻塞用戶界面,出現(xiàn)ANR的響應提示窗口,這個時候我們考慮使用Thread線程來解決。認識線程進程與線程線程是指進程內(nèi)的一個執(zhí)行單元,也是進程內(nèi)的可調(diào)度實體,與進程的區(qū)別:

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

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

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

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

基本用法實現(xiàn)繼承java.lang.Thread類

實現(xiàn)Runnable接口啟動Thread類代表線程類,它的兩個最主要的方法是:

run()——包含線程運行時所執(zhí)行的代碼

Start()——用于啟動線程通信Handler機制,它是Runnable和Activity交互的橋梁,在run方法中發(fā)送Message,在Handler里,通過不同的Message執(zhí)行不同的任務。線程同步簡介當使用多個線程來訪問同一個數(shù)據(jù)時,非常容易出現(xiàn)線程安全問題(比如多個線程都在操作同一數(shù)據(jù)導致數(shù)據(jù)不一致),所以我們用同步機制來解決這些問題。實現(xiàn)方法同步代碼塊:

synchronized(同一個數(shù)據(jù)){}

同一個數(shù)據(jù):就是N條線程同時訪問一個數(shù)據(jù)。同步方法:

publicsynchronized

數(shù)據(jù)返回類型

方法名(){}子線程更新UI子線程更新UI的四種方法handle.post(Runnabler)handle.handleMessage(Messagemsg)runOnUiThread(Runnabler)View.post(Runnabler)線程間通訊

Handler

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

Looper:負責管理線程的消息隊列和消息循環(huán)

。Message

:線程間通訊的消息載體。兩個碼頭之間運輸貨物,Message充當集裝箱的功能,里面可以存放任何你想要傳遞的消息。

MessageQueue:消息隊列,先進先出,它的作用是保存有待線程處理的消息。

用于線程間通訊的類Android多線程機制

Android多線程3.1使用線程任何耗時的處理過程都會降低用戶界面的響應速度,甚至導致用戶界面失去響應,當用戶界面失去響應超過5秒鐘,Android系統(tǒng)會允許用戶強行關閉應用程序較好的解決方法是將耗時的處理過程轉移到子線程上,這樣可以避免負責界面更新的主線程無法處理界面事件,從而避免用戶界面長時間失去響應本地服務3.1使用線程線程是獨立的程序單元,多個線程可以并行工作在多處理器系統(tǒng)中,每個中央處理器(CPU)單獨運行一個線程,因此線程是并行工作的在單處理器系統(tǒng)中,處理器會給每個線程一小段時間,在這個時間內(nèi)線程是被執(zhí)行的,然后處理器執(zhí)行下一個線程,這樣就產(chǎn)生了線程并行運行的假象無論線程是否真的并行工作,在宏觀上可以認為子線程是獨立于主線程,且能與主線程并行工作的程序單元3本地服務3.1使用線程Android中的線程是基于Java定義的線程,其內(nèi)部結構如圖所示:…消息隊列消息隊列線程1run(){…}線程Nrun(){…}3本地服務3.1使用線程一個應用程序中可能會包含多個線程(Thread),每個線程中都有一個run()方法,run()方法內(nèi)部的程序執(zhí)行完畢后,所在的線程就自動結束。每個線程都有一個消息隊列,用于不同的線程之間傳遞消息。在run()方法內(nèi)部,如果不主動去讀取消息隊列中的消息,這些消息就是一些無用的消息,因為它們沒有被處理。3本地服務3.1使用線程在Android系統(tǒng)中,讀取消息和處理消息是兩個步驟,并由兩個不同的部分完成,先讀取消息,然后才能處理消息。無論是本線程的還是其它線程,都不能直接處理消息隊列中的消息,而是需要通過在線程內(nèi)部定義一個Handler類對象來處理消息隊列。一個Thread只能包含一個Handler對象。在實際應用中,讀取消息隊列一般需要循環(huán)執(zhí)行,即不斷地從消息隊列中獲取消息并進行相應處理,這就又需要一個Looper對象。3本地服務3.1使用線程Looper對象用于循環(huán)讀取消息隊列的值,并回調(diào)Handler對象中定義的消息處理函數(shù),同時,Looper對象還可以將讀取的消息從隊列中移除,執(zhí)行完一次消息處理后,再循環(huán)從消息隊列中讀取下一個消息,直到Looper對象調(diào)用stop()方法退出循環(huán)。如果消息隊列中沒有消息,Looper對象則會等待,線程不會退出。為了更方便地從線程中使用Looper功能,Android又定義了一個HandlerThread類,該類基于Thread,并且內(nèi)部已經(jīng)添加了Looper功能,使用者只需重寫其onLooperPrepared()方法,添加具體應用代碼即可。Android中一個Activity就是一個線程,多個Activity之間的切換是在同一個線程中。Android中Activity的調(diào)用流程publicclassPseudoActivityextendsThread{ voidrun(){ while(1){ //如果定義了Handler對象,則進行消息派發(fā)

if(hasHandler()){ if(MessageQueue.getMessage()!=null) Handler.handleMessage(); //執(zhí)行完一個消息后,接著執(zhí)行與用戶界面相關的響應。

activity(){ //以下是Activity的核心代碼,包括用戶按鍵消息、菜單、對話框等處理。 //經(jīng)過ifelse等程序控制語句,回調(diào)一些接口函數(shù),如onXXX()。 if..else.. switch...case...for...onCreate...,,,onStart(); }}}} //以下為一些回調(diào)函數(shù)定義

publicvoidonCreate(){ } publiconStart(){ } ....}

3本地服務3.1使用線程以上偽代碼中,while(1)循環(huán)用于指定該Thread一直執(zhí)行,永不退出,直到被操作系統(tǒng)殺掉。if(hasHandler())語句判斷該Thread中是否定義了Handler對象,該Handler對象是由應用程序定義的(也可不定義);如果有該對象,那么就會讀取Thread中消息隊列的值,并做一定的處理。執(zhí)行完一個消息后,接著需要執(zhí)行Activity中的用戶界面響應,例如是否有按鍵按下、觸摸屏是否按下等。處理完一次用戶消息響應后,則繼續(xù)循環(huán)讀取Thread中消息隊列的值。MessageQueue、Looper、Handler調(diào)用關系在以上這個大循環(huán)中,Handler對象對應的就是Handler.handleMessage()部分完成的功能,Looper對象對應的就是整個while(1)循環(huán)控制和MessageQueue.getMessage()完成的功能。一個ThreadHandler接口對象Looper對象MessageQueue(消息隊列)其它功能函數(shù)3本地服務3.1使用線程Looper對象負責從線程的消息隊列中循環(huán)讀取消息值,再將這些消息傳遞給Handler對象,Handler對象中定義的消息處理函數(shù)會根據(jù)消息類型再調(diào)用Thread中定義的其它函數(shù)。如果Thread中沒有Looper對象,那么Thread的執(zhí)行體就無法讀取消息隊列;如果Thread中沒有Handler對象,則不會處理任何消息。一般情況下,Handler和Looper是同時使用的,要么同時有,要么同時沒有。Android多線程定義

4線程定義4.1線程定義Android中定義線程的方法與Java相同,可以使用兩種方法:一種是Thread類,另一種是Runnable接口。Thread是一個類,根據(jù)Java繼承風格,一個類只能有一個父類,繼承了Thread的子類不能再繼承其它類,這是一個缺陷。于是,出現(xiàn)了Runnable,其作用和Thread相同,都是啟動另一個線程,不同的是,Runnable是一個接口(interface),因此可以同時實現(xiàn)多個接口。4線程定義4.1線程定義Android中使用Thread與Java基本相同,所不同的是,Android拋棄了Java線程中一些不安全的做法。比如:終止一個Thread,在Java中可以調(diào)用線程名字.stop()、線程名字.destroy()等;而在Android中,這些方法都沒有實現(xiàn),即不能使用。新建一個Thread對象,需要實現(xiàn)兩個方法:4線程定義4.1線程定義第一個是定義構造方法。在Android程序中,新建的線程多為Activity、Service等程序片斷服務,而在線程的內(nèi)部執(zhí)行過程中,很多時候都需要使用應用程序內(nèi)部的Context對象,因此,在實際應用中,線程的構造方法往往會傳遞應用程序的Context對象,從而在線程的內(nèi)部可以調(diào)用Context相關的系統(tǒng)服務。當然,這不是必須的。第二個是run()方法,該方法是Thread對象中必須實現(xiàn)的方法,用于完成具體的任務。啟動線程時,不能直接調(diào)用線程名字.run()方法,而是調(diào)用線程名字.start()方法啟動,start()方法是Thread內(nèi)部使用的,該方法包含初始化線程的工作,然后回調(diào)run()方法,這些對應用程序都是不可見的。4線程定義4.1線程定義停止線程時,不能調(diào)用線程名字.destroy()方法或者線程名字.stop()方法。run()方法執(zhí)行完畢后,線程默認會自動停止。因此,如果需要線程循環(huán)執(zhí)行run()方法內(nèi)部的代碼,可以在線程內(nèi)部增加一個狀態(tài)變量,run()方法內(nèi)部通過檢查該狀態(tài)變量,決定是否繼續(xù)執(zhí)行;同時可在線程外設置該狀態(tài)變量的值,從而終止該線程。4線程定義4.1線程定義線程定義Thread繼承Thread類,并重寫run()方法。在run()中放置代碼的主體部分classThread1extendsThread{privateContextmCtx; Thread1(Contextcontext){ mCtx=context; }@Override publicvoidrun(){

//過程代碼}4線程定義4.1線程定義以上代碼包括3個基本方法:Thread1()為構造方法,用于保存調(diào)用者的Context對象,供以后可能使用;run()方法內(nèi)部是應用代碼;setToStop()用于設置全局變量mRunState的值,run()內(nèi)部循環(huán)執(zhí)行時會判斷該值,決定是否退出run()方法,即終止該線程。要在Activity啟動Thread1,首先需要定義一個Thread1對象,并使用構造方法將Activity的Context對象傳遞給Thread1,然后調(diào)用線程的start()方法啟動Thread1線程。要終止Thread的運行,可調(diào)用自定義的Thread1的setToStop()方法。以上代碼中,id值為action_stop的按鈕,用于停止Thread1的運行。這是Android系統(tǒng)建議的啟動線程和退出線程的方法。4線程定義4.1線程定義RunnableRunnable的作用和Thread基本相同,都是用于定義一個線程,但兩者本質(zhì)上有重要區(qū)別。第1:Runnable只是一個接口(interface),其內(nèi)部沒有定義任何已實現(xiàn)的方法。因此,要使用與線程有關的方法,只能使用Thread的靜態(tài)方法,比如:不能直接調(diào)用sleep(),而要調(diào)用Thread.sleep()方法。4線程定義4.1線程定義Runnable第2:定義一個Thread對象,就意味著創(chuàng)建了一個新線程,而定義一個Runnable對象,只是定義了一個可以當作線程運行的代碼對象,并沒有創(chuàng)建新線程。因此,如果調(diào)用Runnable對象的run()方法,僅相當于把Runnable對象當作普通類對象進行調(diào)用,并沒有啟動一個新線程,Runnable對象和調(diào)用者在同一個線程中運行。如果要創(chuàng)建一個新線程,則還需要將Runnable對象傳入Thread的構造方法,從而創(chuàng)建一個新線程,新線程的執(zhí)行碼就是Runnable所定義的。4線程定義4.1線程定義Runnable第3:Runnable對象經(jīng)常被當作參數(shù)傳遞給一些與線程有關的方法,用于啟動一個新的線程。4線程定義4.1線程定義線程定義Runnable實現(xiàn)Java的Runnable接口,并重載run()方法。在run()中放置代碼的主體部分privateRunnablebackgroudWork=newRunnable(){ @Override publicvoidrun(){ //過程代碼 } };4線程定義4.1線程定義線程定義實現(xiàn)Java的Runnable接口,并重載run()方法。在run()中放置代碼的主體部分。privateRunnablebackgroudWork=newRunnable(){ @Override publicvoidrun(){ //過程代碼 } };4線程定義4.1線程定義線程定義創(chuàng)建Thread對象,并將上面實現(xiàn)的Runnable對象作為參數(shù)傳遞給Thread對象Thread的構造函數(shù)中,第1個參數(shù)用來表示線程組第2個參數(shù)是需要執(zhí)行的Runnable對象第3個參數(shù)是線程的名稱調(diào)用start()方法啟動線程privateThreadworkThread;workThread=newThread(null,backgroudWork,"WorkThread");workThread.start();4線程定義4.1線程定義線程在run()方法返回后,線程就自動終止了;不推薦使用調(diào)用stop()方法在外部終止線程最好的方法是通知線程自行終止,一般調(diào)用interrupt()方法通告線程準備終止,線程會釋放它正在使用的資源,在完成所有的清理工作后自行關閉interrupt()方法并不能直接終止線程,僅是改變了線程內(nèi)部的一個布爾字段,run()方法能夠檢測到這個布爾字段,從而知道何時應該釋放資源和終止線程在run()方法的代碼,一般通過Terrupted()方法查詢線程是否被中斷workTerrupt();4線程定義4.1線程定義下面的代碼是以1秒為間隔循環(huán)檢測斷線程是否被中斷第4行代碼使線程休眠1000毫秒當線程在休眠過程中被中斷,則會產(chǎn)生InterruptedException在中斷的線程上調(diào)用sleep()方法,同樣會產(chǎn)生InterruptedExceptionpublicvoidrun(){ while(!Terrupted()){ //過程代碼 Thread.sleep(1000); }}4線程定義4.1線程定義Terrupted()方法功能判斷線程是否應被中斷通過捕獲InterruptedException判斷線程是否應被中斷,并且在捕獲到InterruptedException后,安全終止線程publicvoidrun(){ try{ while(true){ //過程代碼 Thread.sleep(1000); } }catch(InterruptedExceptione){ e.printStackTrace(); }}Handler5

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

Handler5.1使用HandlerHandler一般有兩種用途:實現(xiàn)一個定時任務。這個有點類似于Windows中的定時器功能,可以通過Handler對象向所在線程發(fā)送一個延時消息。當消息指定的時間到達后,通過Handler對象的消息處理方法完成指定任務。在線程間傳遞數(shù)據(jù)。5

Handler5.1使用HandlerHandler完成定時任務在一個Activity內(nèi)部,經(jīng)常需要做一些定時器的功能,比如周期性更新某個視圖的內(nèi)容、在指定時間后結束某個操作等。完成定時任務,可以通過Handler對象的延遲發(fā)送消息方法來實現(xiàn)。在介紹發(fā)送消息之前,需要先了解一下消息Message的數(shù)據(jù)結構。Message是一個描述消息的數(shù)據(jù)結構類,Message包含很多成員變量和方法,但對于簡單的消息處理,一般僅需了解3項,分別是:intwhat這是用戶自定義的一個整型值,用于區(qū)分消息類型。intarg1這是額外消息參數(shù)intarg2同arg1對于需要包含更多數(shù)據(jù)的消息,可以使用message.setData()和getData()方法。setData()方法用于把一個Bundle類數(shù)據(jù)對象加入到Message中,而getData()則是取出該Bundle數(shù)據(jù)。Bundle數(shù)據(jù)類型就是包含“鍵值對”數(shù)據(jù)的類型。Handler發(fā)送消息的方式:一類是postXXX()方法,該方法用于把一個Runnable對象發(fā)送到消息隊列。從而當消息被處理時,能夠執(zhí)行Runnable對象;另一類是sendXXX()方法,該方法用于發(fā)送一個Message類型的消息到消息隊列,當消息被處理時,系統(tǒng)會調(diào)用Handler對象定義的handleMessage()方法處理該消息。實現(xiàn)定時任務則主要使用sendXXX()類,該類具體包含如下方法:sendEmptyMessage(intwhat),空消息是指該消息僅包含what值。sendEmptyMessageAtTime(intwhat,longuptimeMilis),在指定時間點發(fā)送空消息,uptimeMilis是指從本次開機開始運行的時間點,不包含系統(tǒng)休眠的時間,單位為毫秒。參照SystemClock類。sendEmptyMessageDelayed(intwhat,longdelayMillis),在指定時間后發(fā)送空消息,指定的時間以毫秒為單位。sendMessage(Message),發(fā)送Message指定的消息。sendMessageAtTime(Message,long),在指定時間點發(fā)送該消息。sendMessageDelayed(Message,long),在指定的時間后發(fā)送該消息。實現(xiàn)定時任務時,一般使用sendMessageAtDelayed()或者sendEmptyMessageAtDelayed()方法,即在指定的時間后發(fā)送消息。當收到該消息后,系統(tǒng)會調(diào)用Handler對象實現(xiàn)的消息處理接口handlhandleMessage()的參數(shù)是Message對象,可以通過Message的相關方法獲得Message的具體值,并根據(jù)其消息完成不同的任務。Handle定時任務案例演示1)、handleMessage用于處理Activity所在線程接收到的消息,此處是把當前時間顯示在文本框中。obtainMessage()方法用于從全局的消息池中獲得一個已有的Message對象,系統(tǒng)為了加速線程間的消息傳遞,創(chuàng)建了一些全局的消息對象供各線程使用,這些全局消息對象稱為全局消息池,使用該方法比重新創(chuàng)建一個消息對象的效率高。該方法的第一個參數(shù)用于指定初始化返回消息的what值。sendMessageDelayed()方法用于在1000毫秒后發(fā)送what值為100的消息,即在顯示完當前時間后的1秒,再發(fā)送一次消息,從而可以每過1秒更新一次文本框的時間。此處使用100代表該消息類型。2)、需要注意的是:在應用程序運行時,當用戶按Back鍵返回后,盡管Activity進入了暫?;蛘咄V沟臓顟B(tài),但是消息的發(fā)送會依然在后臺執(zhí)行,因此,程序員需要根據(jù)情況決定是否要停止消息發(fā)送。例如可以在onPause()方法內(nèi)將消息隊列中的消息移除,并在onResume()方法中重新開始消息發(fā)送。removeMessage(100)方法用于移除消息隊列中what值為100的全部消息。課堂練習:跳動的時鐘HandlerHandler完成線程間傳遞數(shù)據(jù)使用Handler對象不但可以給本線程發(fā)送消息,還可以給其它線程發(fā)送消息,前提是需要獲取其它線程中的Handler對象。線程之間傳遞數(shù)據(jù)在GUI應用中十分廣泛,比如后臺線程正在執(zhí)行具體的數(shù)據(jù)處理,前臺界面需要顯示出處理的進度,典型的就是進度對話框。在這種應用中,前臺線程(一般是指Activity)創(chuàng)建一個后臺線程,并把前臺線程的Handler對象傳遞給后臺線程,后臺線程就可以通過該Handler對象向前臺線程發(fā)送消息,報告后臺數(shù)據(jù)處理的進度。Looper6

Handler6.1使用LooperThread在默認情況下,只要run()方法執(zhí)行完畢,線程就結束。簡單控制線程不主動退出的方法是:在run()方法內(nèi)部加一個while()循環(huán),這的確也能解決一些問題,對于那些不需要接收消息而言,基本上夠用了。但在另一些情況下,新建的線程需要接收消息并處理,因此,在新線程中,除了需要添加一個Handler對象外,還需要從線程的消息隊列中取出消息,并負責分發(fā)消息,這就需要Looper了。事實上,Activity內(nèi)部就有一個Looper,只是Activity是一個特殊的Thread,操作系統(tǒng)已經(jīng)將其封裝了而已。Looper往往和Handler同時使用,案例如下所示:6

Handler6.1使用LooperLooper.prepare()用于給該線程創(chuàng)建一個Looper對象;Looper.loop()用于開始執(zhí)行Looper對象,所謂的執(zhí)行就是讓Looper對象開始讀取線程的消息隊列,并派

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論