深入淺出談Android多線(xiàn)程及AsyncTask機制
本篇隨筆將講解一下Android的多線(xiàn)程的知識,以及如何通過(guò)AsyncTask機制來(lái)實(shí)現線(xiàn)程之間的通信。
本文引用地址:http://dyxdggzs.com/article/201807/383682.htm在Android當中,當一個(gè)應用程序的組件啟動(dòng)的時(shí)候,并且沒(méi)有其他的應用程序組件在運行時(shí),Android系統就會(huì )為該應用程序組件開(kāi)辟一個(gè)新的線(xiàn)程來(lái)執行。默認的情況下,在一個(gè)相同Android應用程序當中,其里面的組件都是運行在同一個(gè)線(xiàn)程里面的,這個(gè)線(xiàn)程我們稱(chēng)之為Main線(xiàn)程。當我們通過(guò)某個(gè)組件來(lái)啟動(dòng)另一個(gè)組件的時(shí)候,這個(gè)時(shí)候默認都是在同一個(gè)線(xiàn)程當中完成的。當然,我們可以自己來(lái)管理我們的Android應用的線(xiàn)程,我們可以根據我們自己的需要來(lái)給應用程序創(chuàng )建額外的線(xiàn)程。
二、Main Thread 和 Worker Thread
在A(yíng)ndroid當中,通常將線(xiàn)程分為兩種,一種叫做Main Thread,除了Main Thread之外的線(xiàn)程都可稱(chēng)為Worker Thread。
當一個(gè)應用程序運行的時(shí)候,Android操作系統就會(huì )給該應用程序啟動(dòng)一個(gè)線(xiàn)程,這個(gè)線(xiàn)程就是我們的Main Thread,這個(gè)線(xiàn)程非常的重要,它主要用來(lái)加載我們的UI界面,完成系統和我們用戶(hù)之間的交互,并將交互后的結果又展示給我們用戶(hù),所以Main Thread又被稱(chēng)為UI Thread。
Android系統默認不會(huì )給我們的應用程序組件創(chuàng )建一個(gè)額外的線(xiàn)程,所有的這些組件默認都是在同一個(gè)線(xiàn)程中運行。然而,某些時(shí)候當我們的應用程序需要完成一個(gè)耗時(shí)的操作的時(shí)候,例如訪(fǎng)問(wèn)網(wǎng)絡(luò )或者是對數據庫進(jìn)行查詢(xún)時(shí),此時(shí)我們的UI Thread就會(huì )被阻塞。例如,當我們點(diǎn)擊一個(gè)Button,然后希望其從網(wǎng)絡(luò )中獲取一些數據,如果此操作在UI Thread當中完成的話(huà),當我們點(diǎn)擊Button的時(shí)候,UI線(xiàn)程就會(huì )處于阻塞的狀態(tài),此時(shí),我們的系統不會(huì )調度任何其它的事件,更糟糕的是,當我們的整個(gè)現場(chǎng)如果阻塞時(shí)間超過(guò)5秒鐘(官方是這樣說(shuō)的),這個(gè)時(shí)候就會(huì )出現 ANR (Application Not Responding)的現象,此時(shí),應用程序會(huì )彈出一個(gè)框,讓用戶(hù)選擇是否退出該程序。對于A(yíng)ndroid開(kāi)發(fā)來(lái)說(shuō),出現ANR的現象是絕對不能被允許的。
另外,由于我們的Android UI控件是線(xiàn)程不安全的,所以我們不能在UI Thread之外的線(xiàn)程當中對我們的UI控件進(jìn)行操作。因此在A(yíng)ndroid的多線(xiàn)程編程當中,我們有兩條非常重要的原則必須要遵守:
- 絕對不能在UI Thread當中進(jìn)行耗時(shí)的操作,不能阻塞我們的UI Thread
- 不能在UI Thread之外的線(xiàn)程當中操縱我們的UI元素
三、如何處理UI Thread 和 Worker Thread之間的通信
既然在A(yíng)ndroid當中有兩條重要的原則要遵守,那么我們可能就有疑問(wèn)了?我們既不能在主線(xiàn)程當中處理耗時(shí)的操作,又不能在工作線(xiàn)程中來(lái)訪(fǎng)問(wèn)我們的UI控件,那么我們比如從網(wǎng)絡(luò )中要下載一張圖片,又怎么能將其更新到UI控件上呢?這就關(guān)系到了我們的主線(xiàn)程和工作線(xiàn)程之間的通信問(wèn)題了。在A(yíng)ndroid當中,提供了兩種方式來(lái)解決線(xiàn)程直接的通信問(wèn)題,一種是通過(guò)Handler的機制(這種方式在后面的隨筆中將詳細介紹),還有一種就是今天要詳細講解的 AsyncTask 機制。
四、AsyncTask
AsyncTask:異步任務(wù),從字面上來(lái)說(shuō),就是在我們的UI主線(xiàn)程運行的時(shí)候,異步的完成一些操作。AsyncTask允許我們的執行一個(gè)異步的任務(wù)在后臺。我們可以將耗時(shí)的操作放在異步任務(wù)當中來(lái)執行,并隨時(shí)將任務(wù)執行的結果返回給我們的UI線(xiàn)程來(lái)更新我們的UI控件。通過(guò)AsyncTask我們可以輕松的解決多線(xiàn)程之間的通信問(wèn)題。
怎么來(lái)理解AsyncTask呢?通俗一點(diǎn)來(lái)說(shuō),AsyncTask就相當于A(yíng)ndroid給我們提供了一個(gè)多線(xiàn)程編程的一個(gè)框架,其介于Thread和Handler之間,我們如果要定義一個(gè)AsyncTask,就需要定義一個(gè)類(lèi)來(lái)繼承AsyncTask這個(gè)抽象類(lèi),并實(shí)現其唯一的一個(gè) doInBackgroud 抽象方法。要掌握AsyncTask,我們就必須要一個(gè)概念,總結起來(lái)就是: 3個(gè)泛型,4個(gè)步驟。
3個(gè)泛型指的是什么呢?我們來(lái)看看AsyncTask這個(gè)抽象類(lèi)的定義,當我們定義一個(gè)類(lèi)來(lái)繼承AsyncTask這個(gè)類(lèi)的時(shí)候,我們需要為其指定3個(gè)泛型參數:

- Params: 這個(gè)泛型指定的是我們傳遞給異步任務(wù)執行時(shí)的參數的類(lèi)型
- Progress: 這個(gè)泛型指定的是我們的異步任務(wù)在執行的時(shí)候將執行的進(jìn)度返回給UI線(xiàn)程的參數的類(lèi)型
- Result: 這個(gè)泛型指定的異步任務(wù)執行完后返回給UI線(xiàn)程的結果的類(lèi)型
我們在定義一個(gè)類(lèi)繼承AsyncTask類(lèi)的時(shí)候,必須要指定好這三個(gè)泛型的類(lèi)型,如果都不指定的話(huà),則都將其寫(xiě)成Void,例如:

4個(gè)步驟:當我們執行一個(gè)異步任務(wù)的時(shí)候,其需要按照下面的4個(gè)步驟分別執行
- onPreExecute(): 這個(gè)方法是在執行異步任務(wù)之前的時(shí)候執行,并且是在UI Thread當中執行的,通常我們在這個(gè)方法里做一些UI控件的初始化的操作,例如彈出要給ProgressDialog
- doInBackground(Params... params): 在onPreExecute()方法執行完之后,會(huì )馬上執行這個(gè)方法,這個(gè)方法就是來(lái)處理異步任務(wù)的方法,Android操作系統會(huì )在后臺的線(xiàn)程池當中開(kāi)啟一個(gè)worker thread來(lái)執行我們的這個(gè)方法,所以這個(gè)方法是在worker thread當中執行的,這個(gè)方法執行完之后就可以將我們的執行結果發(fā)送給我們的最后一個(gè) onPostExecute 方法,在這個(gè)方法里,我們可以從網(wǎng)絡(luò )當中獲取數據等一些耗時(shí)的操作
- onProgressUpdate(Progess... values): 這個(gè)方法也是在UI Thread當中執行的,我們在異步任務(wù)執行的時(shí)候,有時(shí)候需要將執行的進(jìn)度返回給我們的UI界面,例如下載一張網(wǎng)絡(luò )圖片,我們需要時(shí)刻顯示其下載的進(jìn)度,就可以使用這個(gè)方法來(lái)更新我們的進(jìn)度。這個(gè)方法在調用之前,我們需要在 doInBackground 方法中調用一個(gè) publishProgress(Progress) 的方法來(lái)將我們的進(jìn)度時(shí)時(shí)刻刻傳遞給 onProgressUpdate 方法來(lái)更新
評論