android 多線程Thread,Runnable,Handler,AsyncTask等之間的關係

android 的多線程實際上就是java的多線程。android的UI線程又稱爲主線程。

我們創建的Service、Activity以及Broadcast均是一個主線程處理,這裏我們可以理解爲UI線程。但是在操作一些耗時操作時,比如I/O讀寫的大文件讀寫,數據庫操作以及網絡下載需要很長時間,爲了不阻塞用戶界面,出現ANR的響應提示窗口,這個時候我們可以考慮使用Thread線程來解決。

Thread 和 Runnable

關於這兩者的關係,很多人會說,在java中可有兩種方式實現多線程,一種是繼承Thread類,一種是實現Runnable接口;Thread類是在java.lang包中定義的。一個類只要繼承了Thread類同時覆寫了本類中的run()方法就可以實現多線程操作了,但是一個類只能繼承一個父類,這是此方法的侷限。所以,通常會實現Runnable接口方式。

Thread纔是一個線程,而Runnable可以理解爲一個任務。這個任務只是一個接口。具體的任務執行是在 run()方法執行。

Thread thread = new Thread(Runnable);

 那麼就是把一個Runnable任務放到線程裏面。當調用thread.start() 的時候,系統新開一個線程去執行,這個runnable任務是在多線程執行的。是在新開的線程執行的。

但是thread.run() ,這樣子實際上只是在UI線程執行了Runnable 並沒有實現多線程。系統也沒有新開一個線程。

如果直接 new Runnable().run();那麼實際上是直接在UI線程執行了這個任務沒有進行一個多線程的操作。

總結:runnable()只是一個任務的抽象,並不是多線程。Thread.start()。纔是新開一個多線程。並且在新開的線程執行Thread你們的run()方法。

但是,在實現時,當使用 runnable 接口時,不能直接創建所需類的對象並運行它;必須從 Thread 類的一個實例內部運行它。

如:class test implements Runnable 

     Thread thread = new Thread(new test());  

Handler

是android 的多線程通信機制的產物,在Android中不允許Activity新啓動的線程訪問該Activity裏的UI組件,這樣會導致新啓動的線程無法改變UI組件的屬性值。但實際開發中,很多地方需要在工作線程中改變UI組件的屬性值,比如下載網絡圖片、動畫等等。

Handler,它直接繼承自Object,一個Handler允許發送和處理Message或者Runnable對象,並且會關聯到主線程的MessageQueue中。每個Handler具有一個單獨的線程,並且關聯到一個消息隊列的線程,就是說一個Handler有一個固有的消息隊列。當實例化一個Handler的時候,它就承載在一個線程和消息隊列的線程,這個Handler可以把Message或Runnable壓入到消息隊列,並且從消息隊列中取出Message或Runnable,進而操作它們。

Handler可以把一個Message對象或者Runnable對象壓入到消息隊列中,進而在UI線程中獲取Message或者執行Runnable對象,所以Handler把壓入消息隊列有兩大體系,Post和sendMessage:

對於Handler的Post方式來說,它會傳遞一個Runnable對象到消息隊列中,在這個Runnable對象中,重寫run()方法。一般在這個run()方法中寫入需要在UI線程上的操作。hanlder實際上是不涉及多線程的。

post(Runnable)  讓當前線程執行Runnable任務。如果是在主線程調用,那麼就是在UI線程執行Runnable。實際上沒有多線程執行runnable。
postAtTime(Runnable,long)  也是讓當前線程在 時間點long 執行Runnble
postDelayed(Runnable long) 讓當前線程延時 long 後執行Runnable。

這3個方法實際上可以把handler看成是一個任務調度器,而不是一個多線程相關的。



Handler如果使用sendMessage的方式把消息入隊到消息隊列中,需要傳遞一個Message對象,而在Handler中,需要重寫handleMessage()方法,用於獲取工作線程傳遞過來的消息,此方法運行在UI線程上。

Message自帶的有如下幾個屬性:

  • int arg1:參數一,用於傳遞不復雜的數據,複雜數據使用setData()傳遞。
  • int arg2:參數二,用於傳遞不復雜的數據,複雜數據使用setData()傳遞。
  • Object obj:傳遞一個任意的對象。
  • int what:定義的消息碼,一般用於設定消息的標誌。
對於Message對象,一般並不推薦直接使用它的構造方法得到,而是建議通過使用Message.obtain()這個靜態的方法或者Handler.obtainMessage()獲取。Message.obtain()會從消息池中獲取一個Message對象,如果消息池中是空的,纔會使用構造方法實例化一個新Message,這樣有利於消息資源的利用。並不需要擔心消息池中的消息過多,它是有上限的,上限爲10個。Handler.obtainMessage()具有多個重載方法,如果查看源碼,會發現其實Handler.obtainMessage()在內部也是調用的Message.obtain()。

sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long) 發出消息的方法

handleMessage(Message msg)處理消息 這纔是android 的hanlder的多線程通信用到的,看下圖


可以看到3個線程共用一個消息隊列Message Queue,一個消息循環器Looper(作用不斷循環讀取消息隊列的消息)。

另外2個線程通過hanlder的sendMessage等方法發送Message,message中可以包含數據。或者是一些action的標記值。

主線程的hanlder通過handleMessage把包含數據等信息的消息取出來。這個過程中其他線程的數據通過message+hanlder傳遞到主線程實現的多線程通信。

可以在一個線程的run方法中調用handler對象的 postMessage或sendMessage方法來實現,Android程序內部維護着一個消息隊列,會輪詢處理這些消息。

Message.obtain()方法具有多個重載方法,大致可以分爲爲兩類,一類是無需傳遞Handler對象,對於這類的方法,當填充好消息後,需要調用Handler.sendMessage()方法來發送消息到消息隊列中。第二類需要傳遞一個Handler對象,這類方法可以直接使用Message.sendToTarget()方法發送消息到消息隊列中,這是因爲在Message對象中有一個私有的Handler類型的屬性Target,當時obtain方法傳遞進一個Handler對象的時候,會給Target屬性賦值,當調用sendToTarget()方法的時候,實際在它內部還是調用的Target.sendMessage()方法。

AsyncTask

可以開啓一個多線程執行任務,並且多線程的數據傳遞也是有這個類自己完成。

實際上AsyncTask 是由 thread + handler的封裝實現。所以AsyncTask 跟Thread+handler實現沒有本質的差別。

AsyncTask的代碼更少,使用比Thread+handler簡單。

主要有    onPreExecute() ; 是指在執行多線程任務之前的一個初始化執行。在UI線程調用

      doInBackground(Params... params);這個方法是AsyncTask新啓動的線程實現的。在新線程調用
    onPostExecute(Result result) ;這個是doInBackground()方法執行完成後,才調用的方法。

result 就是doInBackground()的結果,就是用Hanlder的方式傳遞的數據。這個方法在UI線程調用

    protected void onProgressUpdate(Progress... values);處理中間數據。doInBackGround()方法中,即在新開的線程中調用publishProgress方法,那麼hanlder就把publishProgress的值傳遞到UI線程中。

並且把值交給onProgressUpdate方法處理。所以onProgressUpdate是在UI線程調用的。




本文摘自:http://blog.csdn.net/u012565107/article/details/22749677

handler部分摘自:http://www.cnblogs.com/plokmju/p/android_handler.html

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