摘 要:在Android應(yīng)用程序中,如果UI線(xiàn)程(主線(xiàn)程)處理事件占用的時(shí)間過(guò)長(zhǎng),就會(huì)出現(xiàn)ANR(應(yīng)用程序無(wú)響應(yīng))異常。因此,為了確保用戶(hù)順暢的操作體驗(yàn),我們需要將耗時(shí)長(zhǎng)的任務(wù)(如:訪問(wèn)網(wǎng)絡(luò)獲取數(shù)據(jù)、大量的數(shù)據(jù)計(jì)算)分配給后臺(tái)線(xiàn)程處理。其中涉及到UI線(xiàn)程與非UI線(xiàn)程信息交互等相關(guān)問(wèn)題。本文將主要討論如何最佳構(gòu)建應(yīng)用程序來(lái)提高響應(yīng)性能并避免ANR異常。
關(guān)鍵詞:Android;ANR異常;多線(xiàn)程技術(shù);異步任務(wù)
中圖分類(lèi)號(hào):TP311.52
Android是基于Linux平臺(tái)的開(kāi)源手機(jī)操作系統(tǒng),目前已廣泛地使用于手機(jī)等移動(dòng)設(shè)備。由于Android的開(kāi)源性,基于Android應(yīng)用軟件的開(kāi)發(fā)也有著很好的市場(chǎng)前景。為保證Android應(yīng)用軟件的良好用戶(hù)體驗(yàn),合理地分配UI線(xiàn)程和后臺(tái)線(xiàn)程中所執(zhí)行的任務(wù)是極為重要的。因此,在開(kāi)發(fā)Android應(yīng)用程序時(shí),引入多線(xiàn)程技術(shù)可以有效地明確應(yīng)用程序的結(jié)構(gòu),保證應(yīng)用程序的靈活性,降低任務(wù)間的耦合度,使得所開(kāi)發(fā)的應(yīng)用軟件能夠更加高效地運(yùn)行。
1 Android的相關(guān)知識(shí)
1.1 Android基本組件
一個(gè)Android應(yīng)用程序由松散耦合的組件組成,并由應(yīng)用程序清單綁定到一起。它主要由以下五個(gè)基本模塊構(gòu)成:
活動(dòng)(Activity):Android應(yīng)用程序的核心,形成顯示信息的圖形用戶(hù)接口并響應(yīng)用戶(hù)事件。
服務(wù)(Service):一直在后臺(tái)運(yùn)行,可以更新數(shù)據(jù)源和可見(jiàn)活動(dòng)并觸發(fā)通知。
內(nèi)容(Context):用來(lái)管理和共享應(yīng)用數(shù)據(jù)庫(kù),實(shí)現(xiàn)多個(gè)程序之間的數(shù)據(jù)共享。
意圖(Intent):一個(gè)應(yīng)用程序之間傳遞消息的橋梁。通過(guò)意圖,可以在系統(tǒng)范圍內(nèi)向目標(biāo)活動(dòng)或者服務(wù)廣播消息,以說(shuō)明執(zhí)行某個(gè)動(dòng)作的意圖。
廣播接收器(Broadcast Receiver):通過(guò)創(chuàng)建和注冊(cè)廣播接收器,應(yīng)用程序可以監(jiān)聽(tīng)到匹配特定過(guò)濾器的意圖廣播,廣播接收器會(huì)自動(dòng)啟動(dòng)應(yīng)用程序響應(yīng)某個(gè)意圖,這個(gè)特點(diǎn)使其成為事件驅(qū)動(dòng)應(yīng)用程序的最佳選擇。[1]
1.2 Android事件處理
在絕大部分情況下,應(yīng)用程序需要及時(shí)對(duì)用戶(hù)動(dòng)作做出響應(yīng)。因此,Android應(yīng)用程序與用戶(hù)的交互是十分重要的。要實(shí)現(xiàn)用戶(hù)與應(yīng)用程序的交互,就需要編寫(xiě)Java代碼來(lái)創(chuàng)建事件處理。
Android事件處理是一種“委托事件處理模型”(Delegation Event Model),分為“事件來(lái)源”(Event Source)和處理事件的“監(jiān)聽(tīng)者”(listener)對(duì)象。當(dāng)事件發(fā)生時(shí),注冊(cè)的監(jiān)聽(tīng)者對(duì)象可以接收事件,然后調(diào)用相關(guān)方法進(jìn)行處理,監(jiān)聽(tīng)者是一個(gè)委托處理設(shè)置事件的對(duì)象。[2]
2 Android系統(tǒng)中多線(xiàn)程信息交互具體方法
2.1 多線(xiàn)程技術(shù)的使用
Android的UI線(xiàn)程主要負(fù)責(zé)處理用戶(hù)的按鍵事件、用戶(hù)觸屏?xí)r間及屏幕繪圖事件等,因此其他的操作是不能夠阻塞UI線(xiàn)程的,否則UI界面會(huì)停止響應(yīng)。Android系統(tǒng)默認(rèn)約定當(dāng)UI線(xiàn)程阻塞超過(guò)20秒時(shí),將會(huì)引發(fā)應(yīng)用程序無(wú)響應(yīng)異常(ANR)。
為避免上述現(xiàn)象的發(fā)生,Android建議將耗時(shí)的操作放在新的子線(xiàn)程中完成。Android開(kāi)發(fā)框架中主要提供了兩種解決方法(以通過(guò)網(wǎng)絡(luò)下載大量資源為例):
(1)首先,程序需要啟動(dòng)一個(gè)新的子線(xiàn)程來(lái)獲取下載資源文件,資源獲取結(jié)束后通過(guò)Handler機(jī)制發(fā)送消息(Message),并同時(shí)在UI線(xiàn)程中處理消息,從而達(dá)到異步線(xiàn)程中處理事件的效果,然后通過(guò)Handler Message方法來(lái)更新線(xiàn)程。
(2)使用Android中提供的AsyncTask方式來(lái)完成異步操作。AsyncTask是使用java.util.concurrent框架來(lái)管理線(xiàn)程以及任務(wù)的執(zhí)行的,concurrent框架是一個(gè)非常成熟、高效的框架,經(jīng)過(guò)了嚴(yán)格的測(cè)試。這說(shuō)明AsyncTask的設(shè)計(jì)很好的解決了匿名線(xiàn)程存在的問(wèn)題。[3]
當(dāng)Android應(yīng)用程序啟動(dòng)主線(xiàn)程時(shí),主線(xiàn)程主要負(fù)責(zé)處理與UI相關(guān)的事件,并將相關(guān)的事件分配給對(duì)應(yīng)組件進(jìn)行處理。為了保證線(xiàn)程的安全性,Android規(guī)定:只允許主線(xiàn)程修改Activity中的組件。但是,在實(shí)際開(kāi)發(fā)中,很可能需要啟動(dòng)新的子線(xiàn)程修改UI組件的屬性,這就需要利用到Handler的消息傳遞機(jī)制。
2.2 Handler消息傳遞機(jī)制
Handler類(lèi)主要包括兩個(gè)作用:在新啟動(dòng)的線(xiàn)程中發(fā)送消息;在主線(xiàn)程中獲取、處理消息。通過(guò)回調(diào)的方式,主線(xiàn)程能夠處理新啟動(dòng)線(xiàn)程所發(fā)送的消息。當(dāng)新啟動(dòng)的線(xiàn)程發(fā)送消息時(shí),消息會(huì)發(fā)送到與之關(guān)聯(lián)的MessageQueue,而handler會(huì)不斷從MessageQueue中獲取并處理消息。
下面介紹與Handler類(lèi)工作的三個(gè)組件:
Message:Handler接收和處理的消息對(duì)象。
Looper:每個(gè)線(xiàn)程只能擁有一個(gè)Looper。它的loop方法負(fù)責(zé)讀取MessageQueue中的消息,讀到消息后就把消息交給發(fā)送該消息的Handler進(jìn)行處理。
MessageQueue:消息隊(duì)列,它采用先進(jìn)先出的方式來(lái)管理Message。
處理過(guò)程如圖1所示。
圖1
Looper對(duì)象與對(duì)應(yīng)的子線(xiàn)程綁定,在初始化Looper時(shí),會(huì)創(chuàng)建一個(gè)與之相關(guān)聯(lián)的MessageQueue,這個(gè)MessageQueue負(fù)責(zé)管理該子線(xiàn)程的消息。
每一個(gè)線(xiàn)程只能擁有一個(gè)Looper,它的loop方法負(fù)責(zé)讀取MessageQueue中的消息,讀到消息之后將其交給Handler處理。為確保Handler能夠正常工作,當(dāng)前的線(xiàn)程必須有一個(gè)MessageQueue,而MessageQueue又是由對(duì)應(yīng)的Looper負(fù)責(zé)管理的,所以啟動(dòng)一個(gè)子線(xiàn)程時(shí),必須為其創(chuàng)建一個(gè)Looper對(duì)象并啟動(dòng)它。
需要說(shuō)明的是,在主線(xiàn)程中,系統(tǒng)已經(jīng)初始化了一個(gè)Looper,因此只需創(chuàng)建一個(gè)Handler即可。[4]
2.3 AsyncTask
相對(duì)于Handler消息傳遞機(jī)制,AsyncTask更輕量級(jí)一些,適用于簡(jiǎn)單的異步處理,不需要借助線(xiàn)程和Handler即可實(shí)現(xiàn)。
AsyncTask
(1)Params:?jiǎn)?dòng)任務(wù)執(zhí)行的輸入?yún)?shù)的類(lèi)型。
(2)Progress:后臺(tái)任務(wù)完成的進(jìn)度值的類(lèi)型。
(3)Result:后臺(tái)執(zhí)行任務(wù)完成后返回結(jié)構(gòu)的類(lèi)型。
使用AsyncTask主要分為三步:
(1)創(chuàng)建AsyncTask的子類(lèi),并為三個(gè)泛型參數(shù)指定類(lèi)型;
(2)實(shí)現(xiàn)AsyncTask下面的幾個(gè)方法:
doInBackground(Params…):重寫(xiě)該方法指定后臺(tái)線(xiàn)程將要完成的任務(wù)。
onProgressUpdate(Progress...values):在調(diào)用publishProgress(Progress...values)時(shí),此方法被執(zhí)行,直接將進(jìn)度信息更新到UI組件上。
onPreExecute():該方法在執(zhí)行后臺(tái)耗時(shí)操作前被調(diào)用,通常用于完成初始化的準(zhǔn)備工作。
onPostExecute(Result result):當(dāng)doInBackground()完成后,系統(tǒng)調(diào)用該方法,將后臺(tái)計(jì)算的結(jié)果傳遞到UI線(xiàn)程中。
(3)調(diào)用AskncTask的子類(lèi)的execute()方法執(zhí)行耗時(shí)的任務(wù)。
Android提供的AsyncTask類(lèi)實(shí)質(zhì)上是Handler與Thread的封裝。因此,我們可以直接繼承AsyncTask類(lèi),并在類(lèi)中實(shí)現(xiàn)相關(guān)的異步操作,利用類(lèi)中提供的接口實(shí)現(xiàn)UI進(jìn)度的更新。
2.4 Handler機(jī)制與AsyncTask的比較
Handler機(jī)制與AsyncTask均能夠在Android中實(shí)現(xiàn)異步任務(wù)機(jī)制,由于它們各自不同的特點(diǎn)適用的環(huán)境也不盡相同。
Handler機(jī)制中涉及到Handler、Looper、Message、Thread四個(gè)對(duì)象,能夠清晰地將不同的后臺(tái)任務(wù)進(jìn)行劃分,有利于理解各個(gè)任務(wù)的實(shí)質(zhì)與功能,對(duì)于整個(gè)過(guò)程的控制比較精細(xì)。但是,當(dāng)其用于處理單一的后臺(tái)任務(wù)時(shí),相比于AsyncTask,其結(jié)構(gòu)顯得相對(duì)復(fù)雜,代碼段也較為臃腫,不易精確地控制任務(wù)。
AsyncTask的實(shí)現(xiàn)原理較為簡(jiǎn)單,因此在使用其實(shí)現(xiàn)異步任務(wù)時(shí)會(huì)更加快捷。但是,當(dāng)有多個(gè)異步操作需要訪問(wèn)或變更UI組件時(shí),處理過(guò)程就會(huì)變得復(fù)雜。
3 結(jié)束語(yǔ)
本文就Android操作系統(tǒng)應(yīng)用層的工作機(jī)制做了大致的介紹,并且分析了利用多線(xiàn)程技術(shù)來(lái)提高應(yīng)用軟件相應(yīng)性能以及避免ANR異常的方法。具體說(shuō)明了Android框架中2種用于避免UI線(xiàn)程阻塞的機(jī)制即Handler消息傳遞機(jī)制和異步任務(wù)機(jī)制,并且對(duì)兩者做出了簡(jiǎn)要的比較。
總的來(lái)說(shuō),開(kāi)發(fā)Android應(yīng)用程序時(shí)需要利用上述的兩種機(jī)制將耗時(shí)多的任務(wù)分配給后臺(tái)的子線(xiàn)程,這樣能夠減輕UI線(xiàn)程的負(fù)擔(dān),減小發(fā)生ANR的可能性,并進(jìn)一步提高用戶(hù)體驗(yàn)。
參考文獻(xiàn):
[1]閆偉,葉建栲.多線(xiàn)程技術(shù)在Android手機(jī)開(kāi)發(fā)中的應(yīng)用[J].信息通信,2012(01).
[2]陳會(huì)安.Android SDK程序設(shè)計(jì)與范例[M].北京:清華學(xué)出版社,2012.
[3]楊杰.基于Android的多線(xiàn)程處理技術(shù)[J].電腦知識(shí)與技術(shù),2013.
[4]李剛.瘋狂Android講義第二版[M].北京:電子工業(yè)出版社,2013.
作者簡(jiǎn)介:肖柏昀(1993.09-),女,湖北人,研究方向:計(jì)算機(jī)應(yīng)用。
作者單位:華中師范大學(xué)計(jì)算機(jī)學(xué)院,武漢 430079