五界酒、Android中的多線程
編寫代碼時首先要牢記的是:確保永遠(yuǎn)不要阻塞主線程!
Android中所有應(yīng)用程序都是從主線程(也稱為UI線程)開始運行嘴秸,除非啟動另外一個線程或者通過隱式調(diào)用函數(shù)來啟動一個線程毁欣,否則所有在Android應(yīng)用中的操作都會運行在主線程中。這意味著岳掐,如果在主線程執(zhí)行很耗時的操作(比如在 onResume 中運行代碼)凭疮,所有的繪制以及輸入事件將被阻塞,直到該操作完成串述。
1. Thread類
每次更新UI都需要創(chuàng)建一個新的 Runnable 對象执解。這使得代碼變得很亂,而且垃圾回收器還會進(jìn)行不必要的對象回收纲酗,這些都是開發(fā)者要避免的衰腌。為了在主線程中使用 runOnUiThread 方法更新UI,必須使用 Runnable 觅赊。這種方案還有一個問題:因為只能對 Thread 實例調(diào)用一次 start 方法右蕊,所以每次執(zhí)行操作都需要創(chuàng)建一個新的 Thread 對象。不斷創(chuàng)建新的線程是非常昂貴的茉兰,這不是一個非常靈活的方法,開發(fā)者應(yīng)避免直接使用 Thread 類欣簇。
2. AsyncTask
AsyncTask 是Android中比較流行的幾個類中的一個规脸,因為它很容易使用坯约。它允許開發(fā)者定義一個運行在單獨線程中的任務(wù),還能在任務(wù)的不同階段提供回調(diào)函數(shù)莫鸭。這些回調(diào)函數(shù)被設(shè)計成無需使用runOnUiThread 方法即可更新UI闹丐,這非常適合表示長時間運行的操作的進(jìn)度。
通過 AsyncTask 類被因,開發(fā)者可以很容易在其他線程中執(zhí)行耗時的任務(wù)卿拴,也可以在需要時很方便地和主線程通信。使用 AsyncTask 唯一的問題是該類的實例只能使用一次梨与,這意味著每次執(zhí)行操作都要新建一個MyAsyncTask對象 堕花。雖然是個輕量級的類(實際的線程是由ExecutorService 管理的),但它不適合那些頻繁的操作粥鞋,因為這會快速聚集需要垃圾回收的對象缘挽,并最終導(dǎo)致應(yīng)用程序界面卡頓。
此外呻粹, AsyncTask 不能對操作設(shè)置執(zhí)行時間壕曼,也無法間隔一段時間執(zhí)行操作。它適合文件下載等浊,以及不會頻繁發(fā)生或通過用戶交互等類似情況的操作腮郊。然而,由于容易實現(xiàn)筹燕, AsyncTask很可能是開發(fā)時首選的類轧飞。
3. Handler類
當(dāng)需要更細(xì)粒度地控制在一個單獨的線程中執(zhí)行操作時, Handler 類會是一個很有用的工具庄萎。該類允許開發(fā)者準(zhǔn)確地控制操作的執(zhí)行時間踪少,還可以重復(fù)多次使用它。執(zhí)行操作的線程會一直運行糠涛,直到被顯式地終止援奢。 Looper 類會處理幕后的事情,但開發(fā)者很少需要直接和它打交道忍捡,相反可以通過包裝類 HandlerThread 創(chuàng)建它集漾。
4. 選擇合適的線程
前面顯示了三種在Android上創(chuàng)建和使用線程的方式。API中和線程相關(guān)的類還有ExecutorService 和 Loader 砸脊。 ExecutorService 適合處理并行運行的多個任務(wù)具篇,這非常適合編寫響應(yīng)多客戶端的服務(wù)器應(yīng)用。 AsyncTask 內(nèi)部同樣使用 ExecutorService 處理多線程凌埂。如果希望能夠并行執(zhí)行多個 AsyncTask 驱显,也可以通過使用正確的 ExecutorService 來完成。
不建議直接使用Thread 類,除非是要完全控制線程的執(zhí)行埃疫。大多數(shù)情況下推薦使用 AsyncTask 和 Handler 類伏恐,具體使用哪一個取決于具體的需求。如果不是很頻繁地執(zhí)行操作栓霜,比如超過每分鐘一次翠桦,那么AsyncTask 可能是個不錯的選擇。如果需要安排操作的時間或者需要快速間隔地執(zhí)行操作胳蛮,Handler 會是更好的選擇销凑。從長遠(yuǎn)來看,使用 Handler 生成的代碼更少仅炊,不過 AsyncTask 更容易使用斗幼。