Android中有着和J2SE同樣優秀的多線程支持,可以把那些耗時較多的操作放在新線程中操作。但是當新線程中有涉及到操作UI的操作時,就會對主線程產生危險,因此,Android提供了Handler作爲主線程和子線程的紐帶。同時,Handler對象初始化後,就默認與對它初始化的進程的消息隊列綁定,因此可以利用Handler所包含的消息隊列,制定一些操作的順序。
根據SDK文檔的說明:“A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.”由此可以清楚的知道,可以把消息和Runnble對象發送到與Handler對象所關聯的消息隊列中去。 |
下面,就Handler的以上兩點作用,分別進行討論。
1. 傳遞Message。用於接受子線程發送的數據, 並用此數據配合主線程更新UI。
在Android中,對於UI的操作通常需要放在主線程中進行操作。如果在子線程中有關於UI的操作,那麼就需要把數據消息作爲一個Message對象發送到消息隊列中,然後,有Handler中的handlerMessge方法處理傳過來的數據信息,並操作UI。當然,Handler對象是在主線程中初始化的,以爲它需要綁定在主線程的消息隊列中。
類sendMessage(Message msg)方法實現發送消息的操作。 在初始化Handler對象時重寫的handleMessage方法來接收Messgae並進行相關操作。
|
以上的例子中,子線程只是對進度條的參數進行了變更,並將結果以message形式發送到消息隊列中去,子線程的內部並未進行UI操作,而是在重寫的Handler的handlerMessage方法中操作了UI界面。
2. 傳遞Runnable對象。用於通過Handler綁定的消息隊列,安排不同操作的執行順序。
Handler對象在進行初始化的時候,會默認的自動綁定消息隊列。利用類post方法,可以將Runnable對象發送到消息隊列中,按照隊列的機制按順序執行不同的Runnable對象中的run方法。
|
程序的運行結果就是每隔3秒鐘,就會在控制檯打印一行UpdateTread。這是因爲實現了Runnable接口的updateThread對象進入了空的消息隊列即被立即執行run方法,而在run方法的內部,又在3000ms之後將其再次發送進入消息隊列中。
3. Handler和多線程
post方法雖然發送的是一個實現了Runnable接口的類對象,但是它並非創建了一個新線程,而是執行了該對象中的run方法。也就是說,整個run中的操作和主線程處於同一個線程。
這樣對於那些簡單的操作,似乎並不會影響。但是對於耗時較長的操作,當它被加入到消息隊列中之後執行會佔用很長的時間,以至於處於同一線程的其他操作無法繼續執行,就會出現“假死”。爲了解決這個問題,就需要使得handler綁定到一個新開啓線程的消息隊列上,在這個處於另外線程的上的消息隊列中處理傳過來的Runnable對象和消息。SDK文檔中也提供了相關說明:
When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. You can create your own threads, and communicate back with the main application thread through a Handler. This is done by calling the same post or sendMessage methods as before, but from your new thread. The given Runnable or Message will than be scheduled in the Handler's message queue and processed when appropriate. |
具體操作方法如下:
|
這樣,當使用sendMessage方法傳遞消息或者使用post方法傳遞Runnable對象時,就會把它們傳遞到與handler對象綁定的處於另外一個線程的消息隊列中,它們將在另外的消息隊列中被處理。而主線程還會在發送操作完成時候繼續進行,不會影響當前的操作。
這裏需要注意,這裏用到的多線程並非由Runnable對象開啓的,而是ThreadHandler對象開啓的。Runnable對象只是作爲一個封裝了操作的對象被傳遞,並未產生新線程。