线程间通讯机制(基础篇)——Handler、Runnable、HandlerThread、AsyncTask的使用
前言:
android線程通訊機制是android應用開發的基礎課程,對于很多初學android的朋友可能還沒有完全理解,所以,今天我就做一下知識小結吧。
一、線程安全
可能有java基本的朋友都知道什么叫線程安全。
線程安全:如果你的代碼在所在的進程中有多個(兩個或兩個以上)的線程同時執行,若每次運行的結果和使用單線程模式運行的結果一致,并且變量的值也和預期的一樣,這樣就叫線程安全。或者說:一個類或者程序所提供的接口對于線程來說是原子操作或者多個線程之間的切換不會導致該接口的執行結果存在二義性,也就是說我們不用考慮同步的問題。
在android系統中,當一個android應用啟動的時候,會開啟一個Lliunx進程和主線程,這個主線程我們有稱UI線程。UI線程是負責顯示,處理UI以及相關事件的線程。
android的UI操作不是線程安全,就是說要UI線程才能處理UI控件,而且當UI線程阻塞超過5秒的時候,系統會報出Force?Close的強制關閉的提示。所以,如果要進行比較耗時的IO操作的時候,android系統就會出現假死的狀態,甚至出現FC提示,就如下載文件、打開大文件等等。
二、線程間通訊實現
面對以上問題,我們為了讓應用在用戶面前展現更加流暢和平滑的效果(就是更好的用戶體驗),我們需要多線程操作,所以,我們要考慮的是,如果讓UI線程和子線程交互。
強大的google開發的android系統里面已經提供了很優秀的線程通訊機制。
1、多線程任務開發可以通過以下幾個方式實現:
1.1、Handler+Message+Thread
1.2、HandlerThread
1.3、AsyncTask
2、如果子線程的數據想通知到UI線程中,可以一下的實現方法:
2.1、上述的三種方法
2.2、Activity.runOnUIThread(Runnable)
2.3、View.post(Runnable)
2.4、View.postDelayed(Runnable,?long)
三、分析
1、Handler+Message+Thread(Runnable)
Handler
1、發送消息到消息隊列
2、發送Runnable任務到消息隊列
3、從消息隊列中接受消息并在當前線程處理消息
4、從消息隊列中接受Runnable任務并執行
5、按時間計劃(指定時間、延遲時間、每隔時間段)來執行任務或者處理消息
Handler中分發消息的一些方法
????????post(Runnable)
????????postAtTime(Runnable,long)
????????postDelayed(Runnable?long)
????????sendEmptyMessage(int)
????????sendMessage(Message)
????????sendMessageAtTime(Message,long)
????????sendMessageDelayed(Message,long)
????????以上post類方法允許你排列一個Runnable對象到主線程隊列中,
????????sendMessage類方法,?允許你安排一個帶數據的Message對象到隊列中,等待更新.
Message
封裝了一系列的參數的消息實體類
Thread(Runnable)
子線程
消息通知簡單例子:
[html] view plain copy
注意:不能在子線程操作UI線程中的UI控件,因為之前也說過UI線程是線程不安全的,有的人可能操作了UI但是也沒有報錯。這是因為此時UI資源沒有被爭奪,沒有產生死鎖,但是也存在這個問題,所以要編寫高質量的代碼就要編寫健壯性強的代碼。所以只能在Handler里面來操作UI。
如果使用post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable?long)方法,里面的Runnable可以對UI操作,因為最后UI線程接受到Runnable的任務時,是直接執行run()方法,所以本質上在UI線程執行任務。
2、HandlerThread
Handy?class?for?starting?a?new?thread?that?has?a?looper.?The?looper?can?then?be?used?to?create?handler?classes.?Note?that?start()?must?still?be?called.?
1、本身繼承Thread,就是一個子線程
2、和Handler+Message+Thread的區別是:在Handler類里面處理Message消息可以是耗時操作,但是不能對UI操作。就是說把handleMessage方法在子線程執行了,而不是在UI線程執行,所以這個工具類應用不廣,只是多線程處理接受到的Message對象。
下面是一個簡單的例子:
[java] view plain copy3、AsyncTask
官方的描述(這個我就不翻譯了):
AsyncTask?enables?proper?and?easy?use?of?the?UI?thread.?This?class?allows?to?perform?background?operations?and?publish?results?on?the?UI?thread?without?having?to?manipulate?threads?and/or?handlers.
為了解決多線程執行任務的問題,Android?1.5提供了一個工具類:AsyncTask,它使創建需要與用戶界面交互的長時間運行的任務變得更簡單。相對來說AsyncTask更輕量級一些,適用于簡單的異步處理,不需要借助線程和Handler即可實現。其實說白了,這個工具類只是對線程和Handler的一個封裝,具體內部如何實現我將會在提高篇解析。
這個工具類使用很簡單主要有以下四個步驟:
1、繼承或者實現AsyncTask類(因為是abstract?修飾的抽象類)
2、實現以下方法
(1)onPreExecute(),?該方法將在執行實際的后臺操作前被UI?thread調用。可以在該方法中做一些準備工作,如在界面上顯示一個進度條。?
(2)doInBackground(Params...),?將在onPreExecute?方法執行后馬上執行,該方法運行在后臺線程中。這里將主要負責執行那些很耗時的后臺計算工作。可以調用?publishProgress方法來更新實時的任務進度。該方法是抽象方法,子類必須實現。?
?(3)onProgressUpdate(Progress...),在publishProgress方法被調用后,UI?thread將調用這個方法從而在界面上展示任務的進展情況,例如通過一個進度條進行展示。?
??(4)onPostExecute(Result),?在doInBackground?執行完成后,onPostExecute?方法將被UI?thread調用,后臺的計算結果將通過該方法傳遞到UI?thread.?
3、在UI線程中實例化定義好的AsyncTask或者其子類
4、調用execute(Params...)開始執行任務
為了正確使用AsyncTask類,必須遵循一下準則:
1、AsyncTask實例必須在UI線程中創建
2、execute方法必須在UI線程中調用
3、不允許手動調用onPreExecute(),?onPostExecute(Result),doInBackground(Params...),?onProgressUpdate(Progress...)這幾個方法?
4、AsyncTask的execute(Params...)執行方法只能執行一次,就是一個實例只能執行一次,執行多次會出現異常。需要說明AsyncTask不能完全取代線程,在一些邏輯較為復雜或者需要在后臺反復執行的邏輯就可能需要線程來實現了。
下面有個簡單的例子:
四、總結
這篇博文只是對android多線程處理任務和子線程和UI線程的通訊實現方法做了簡單的介紹。所以說,只是適合新手過目,這個也是android應用開發的基本功吧。通常學習某方面的知識的時候不要只局限于表面,聰明的人可能會問,為什么會這樣實現的?為什么一定要按照的步驟實現?為什么會有這么多中實現方法,內部會不會是一樣的實現原理呢?等等。
對,其實我想告訴初學者的一點學習建議(個人看法,適合自己的學習方法才是最重要):學習android?api的時候,首先要學會用,用熟了,再去研究其源碼或者內部底層實現原理。如果一下子就告訴你這個類的實現原理,可能會混淆你的總體邏輯思想,會越來越亂,連這個類到底是可以做什么都糊涂了。我個人就是這樣,在使用新知識的時候,多問問為什么,多想想方方面面,帶著問題,再去源碼或者實現原理找答案。當你弄懂了,會感覺很爽,哈哈。這樣的層次結構更加清晰。
所以,這就是我分基礎篇(使用方法)和提高篇(內部原理解析)的原因了(提高篇之后會出)。
原文地址: http://blog.csdn.net/q376420785/article/details/8882920
總結
以上是生活随笔為你收集整理的线程间通讯机制(基础篇)——Handler、Runnable、HandlerThread、AsyncTask的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何实现android和服务器长连接呢?
- 下一篇: 线程间通讯机制(提高篇)——深入浅出实现