工作線程WorkThread和異步任務AsyncTask取捨

在應用開發過程中多線程技術是必不可少的手段,而如何對多線程併發和線程調度進行優化往往是其中最爲核心的部分。出於對包括用戶體驗在內的多種因素的考慮,Android不允許主線程阻塞,當主線程阻塞5秒以上,應用程序即失去響應,由此也衍生出Android編程的一些原則,譬如主線程不得進行耗時操作,工作線程不能更新用戶界面等等。源於這些原則,我們所有的耗時操作都要放在工作線程中進行,而且當需要在工作線程完成某項操作之後更新界面,則可使用一個發消息的工具向主線程發消息,主線程接受到消息之後在適當的時候更新界面,達成良好的線程交互。

實際上,幾乎所有的應用都必然包含耗時操作,某些方面是侷限於硬件性能,有些時候則是由於網絡,使用習慣等各種不確定因素,因而我們不可能在主線程中完成所有的工作,或多或少都會啓動一些工作線程,讓這些工作線程幫我們完成各種消耗大量時間的操作。

在使用工作線程時,我們常常在開始創建一個工作線程,在線程裏面寫好它需要執行的任務,然後在合適的時機啓動它,這樣工作線程就開始爲我們工作了,與主線程不同,Android的特性決定了工作線程只能在用戶不能觸及的地方默默工作。工作線程的工作必然也是爲了達成某項結果,那麼當它完成這項工作之後,如何讓用戶知道知道呢?前面說過了,可以使用一個發消息的工具,這個工具名叫Handler,每個線程都有一個Handler,由這個線程的任務隊列決定,取得某個線程的Handler之後即可向此線程發送消息。當工作線程完成任務之後取得主線程的Handler,向主線程發送消息,用戶通過接收消息就能知道。不僅工作線程能向主線程發消息,主線程也能向工作線程發消息,而且任何線程之間都能互相發消息,只要他們處於同一個進程下,這就是線程交互的原理。

在Android系統框架中有一個AsyncTask對象,我們常稱爲“異步任務對象”,使用的時候把耗時或者一些不需要用戶關心的操作交給它,然後等待結果即可,在它的doInBackground()方法中執行耗時操作,在onPostExecute()方法中取得結果,而且不用考慮繁雜的線程問題。

從使用的便利性來看,異步任務對象無疑是耗時操作的最佳選擇,我們根本不用考慮線程之間的交互,似乎異步任務對象根本就沒有工作線程這玩意。後來,經過研究源碼瞭解到異步任務對象的原理,它的底層其實也是由線程池ExecutorService加Handler實現的,Google將它們封裝起來,使開發者能輕易地完成一些耗時和線程交互工作。

雖然Google的技術員很強,但AsyncTask對象也不是萬能的。在AsyncTask中,由線程池完成線程的調度(有關池的概念會在其他篇章中講述),在doInBackground()方法中啓動工作線程並執行耗時操作,完成進度和結果由Handler發送給主線程,在onProgressUpdate()方法 和onPostExecute()方法中處理結果。有時候不能滿足需求的地方在於:AsyncTask中的任務隊列是阻塞式的,並沒有多少的併發量,因而在我們有意大量併發的時候達不到要求。

在面向對象程序開發時,我常常陷於很多選擇的矛盾中,到底是優先選擇別人寫好的框架還是自己從基礎部分逐漸實現所需功能。由於經驗短淺,在自己實現功能的過程中往往挫折叢叢,效率不高;而使用強大的三方框架能簡單快速地實現功能,效率非常高。而另一方面,在遇到問題或者別人寫好的框架不能滿足自己的需求時,使用三方框架的人可能覺得非常棘手,三方框架雖然強大,但在自己能力不足的時候,理解起來也很困難,出了問題只能寄希望於別人的指導,在需要基於框架擴展功能的時候,由於源碼不開放或者即便開放但自己並不理解,所以無能爲力,如果是自己從基礎部分實現的功能,雖然很蹩腳,但非常瞭解,可能隨時擴展和維護。畢竟,這個社會是一個講究效率的社會,完全由自己蹣跚獨步並不明智,很多時候善於利用工具能發揮更大的功效,究竟如何選擇,需要我們根據實際的工作需要,結合自己的目標,在這數者之間尋找一個平衡。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章