Android:用Handler實現非同步處理功能

來源:互聯網
上載者:User

標籤:android   style   http   ar   io   color   os   使用   sp   

Android:用Handler實現非同步處理功能 - 51CTO.COM

一.一個問題

有這樣一個問題值得我們思考,若把一些類似於下載的功能(既耗時且不一定有結果)寫在Activity(主線程)裡,會導致Activity阻塞,長時間無響應,直至頁面假死(如果5秒鐘還沒有完成的話,會收到Android系統的一個錯誤提示 "強制關閉")。因此,我們需要把這些耗時的操作放在單獨的子線程中操作。這就是Handler的使命。Handler提供非同步處理的功能,發送和接收不是同時的(Activity的主線程和線程隊列裡的線程是不同的線程,並行進行,互不影響)。

二.Handler簡介

Handler 為Android作業系統中的線程通訊工具,它主要由兩個作用:(1)安排訊息或Runnable 在某個主線程中某個地方執行(2)安排一個動作在另外的線程中執行。每個Handler對象維護兩個隊列(FIFO),訊息佇列和Runnable隊列, 都是有Android作業系統提供的。Handler可以通過這兩個隊列來分別:

  1. 發送、接受、處理訊息–訊息佇列;
  2. 啟動、結束、休眠線程–Runnable隊列;

Handler的使用方法大體分為3個步驟:1.建立Handler對象。2.建立Runnable和訊息。3.調用post以及sendMessage方法將Runnable和訊息添加到隊列。

三.Runnable隊列

1.java中的線程

在java中,線程的建立有兩種方法:繼承Thread類和實現Runnable介面。而這最重要的都是要複寫run方法來實現線程的功能。當線程的時間片到了,開始運行時,就執行run()函數,執行完畢,就進入死亡狀態。

舉個建立線程的例子:

  1. Runnable r=new Runnable(){ 
  2.  
  3. @Override 
  4. public void run() { 
  5. // TODO Auto-generated method stub 
  6. System.out.println("thread"); 
  7. handler.postDelayed(thread, 3000); 
  8. }; 

2.關於Runnable隊列

(1)原理

Android的線程非同步處理機制:Handler對象維護一個線程隊列,有新的Runnable送來(post())的時候,把它放在隊尾,而處理 Runnable的時候,從隊頭取出Runnable執行。當向隊列發送一個Runnable後,立即就返回,並不理會Runnable是否被執行,執行 是否成功等。而具體的執行則是當排隊排到該Runnable後系統拿來執行的。這就好比郵局的例子。寄信者將信寫好後放入郵筒就回家了,他並不知道郵件何 時被郵局分發,何時寄到,對方怎樣讀取這些事。這樣,就實現了Android的非同步處理機制。

(2)具體操作

向隊列添加線程:

handler.post(Runnable );將Runnable直接添排入佇列

handler.postDelayed(Runnable, long)延遲一定時間後,將Runnable添排入佇列

handler.postAtTime(Runnable,long)定時將Runnable添排入佇列

終止線程:

handler.removeCallbacks(thread);將Runnable從Runnable隊列中取出

四.訊息佇列

1.訊息對象

(1)Message對象

Message對象攜帶資料,通常它用arg1,arg2來傳遞訊息,當然它還可以有obj參數,可以攜帶Bundle資料。它的特點是系統效能消耗非常少。

初始化: Message msg=handler.obtainMessage();

(2)Bundle對象

Bundle是Android提供的類,可以把它看做是特殊的Map,即索引值對的包。而它特殊在鍵和值都必須要是基礎資料型別 (Elementary Data Type)或是基礎資料型別 (Elementary Data Type)的數組(Map的索引值要求都是對象),特別的,鍵要求都是String類型。用Message來攜帶Bundle資料:

放入:msg.setData(Bundle bundle);

取出:msg.getData();

2.關於訊息佇列

(1)原理

Android的訊息非同步處理機制:Handler對象維護一個訊息佇列,有新的訊息送來(sendMessage())的時候,把它放在隊尾,之後排隊 到處理該訊息的時候,由主線程的Handler對象處理(handleMessage())。整個過程也是非同步,和Runnable隊列的原理相同。

(2)具體操作:

向隊列添加Runnable:handler.sendMessage(Message);

將訊息發送到訊息佇列msg.sendToTarget();

延遲一定時間後,將訊息發送到訊息佇列 handler.sendMessageDelayed(Message,long);

定時將訊息發送到訊息佇列 handler.sendMessageAtTime(Message,long)

處理訊息:

訊息的具體處理過程,需要在new Handler對象時使用匿名內部類重寫Handler的handleMessage(Message msg)方法,如下:

  1. Handler handler=new Handler(){ 
  2.  
  3. @Override 
  4. public void handleMessage(Message msg) { 
  5. // TODO Auto-generated method stub 
  6. 。。。。。。 
  7.  
  8. 。。。。。。 
  9. }; 
五.Handler的兩個作用

1.安排訊息或Runnable 在某個主線程中某個地方執行

程式碼範例:

  1. public class HandlerTestActivity extends Activity { 
  2. private Button start; 
  3. @Override 
  4. protected void onCreate(Bundle savedInstanceState) { 
  5. // TODO Auto-generated method stub 
  6. super.onCreate(savedInstanceState); 
  7. setContentView(R.layout.handlertest); 
  8. start=(Button) findViewById(R.id.start); 
  9. start.setOnClickListener(new startListener()); 
  10.  
  11. System.out.println("Activity Thread:"+Thread.currentThread().getId()); 
  12. Handler handler=new Handler(); 
  13. Runnable thread=new Runnable(){ 
  14.  
  15. @Override 
  16. public void run() { 
  17. // TODO Auto-generated method stub 
  18. System.out.println("HandlerThread:"+Thread.currentThread().getId()); 
  19.  
  20. }; 
  21. class startListener implements OnClickListener{ 
  22.  
  23. @Override 
  24. public void onClick(View v) { 
  25. // TODO Auto-generated method stub 
  26. handler.post(thread); 
  27.  

這個小程式中,首先程式啟動,進入onCreate(),列印出當前線程(即主線程)的ID,之後點擊按鈕start,會將線程thread添加到線程隊 列,執行線程thread,thread的作用就是列印出當前線程的ID。在這個程式中,我們可以看到通過Handler我們可以實現安排 Runnable 在某個主線程中某個地方執行,即作用(1)。

不過這裡有個小小的陷阱,你發現了嗎?這個程式看上去似乎實現了Handler的非同步機制, handler.post(thread)似乎實現了新啟線程的作用,不過通過執行我們發現,兩個線程的ID相同!也就是說,實際上thread還是原來 的主線程,由此可見,handler.post()方法並未真正建立線程,只是在原線程上執行而已,我們並未實現非同步機制。

2.安排一個動作在另外的線程中執行。

(1)java中標準的建立線程的方法

第一步:

 

  1.  Runnable r=new Runnable(){ 
  2.  
  3. @Override 
  4. public void run() { 
  5. // TODO Auto-generated method stub 
  6. System.out.println("thread"); 
  7. handler.postDelayed(thread, 3000); 
  8. }; 

第二步:

  1. Thread t=new Thread (r); 

第三步:

  1. t.start(); 

若把上面樣本程式中的handler.post(thread);語句改成以上形式,通過列印我們可以看到,兩個ID是不同的,新的線程啟動了!

(2)關於Looper

Looper類用來為線程開啟一個訊息迴圈,作用是可以迴圈的從訊息佇列讀取訊息,所以Looper實際上就是訊息佇列+訊息迴圈的封裝。每個線程只能對應一個Looper,除主線程外,Android中的線程預設是沒有開啟Looper的。

通過Handler與Looper互動,Handler可以看做是Looper的介面,用來向指定的Looper發送訊息以及定義處理方法。預設情況下Handler會與其所線上程的Looper綁定,即:

Handler handler=new Handler();等價於Handler handler=new Handler(Looper.myLooper());

Looper有兩個主要方法:

Looper.prepare();啟用Looper
Looper.loop(); 讓Looper開始工作,從訊息佇列裡取訊息,處理訊息。

注意:寫在Looper.loop()之後的代碼不會被執行,這個函數內部應該是一個迴圈,當調用mHandler.getLooper().quit()後,loop才會中止,其後的代碼才能得以運行。

(3)Handler非同步機制的實現

Handler是通過HandlerThread 使得子線程與主線程分屬不同線程的。實際上,HandlerThread 是一個特殊的線程,它是一個封裝好Looper的線程,

程式碼範例:

  1.  //建立一個名叫handler_hread的HandlerThread 對象 
  2. HandlerThread handlerThread=new HandlerThread("handler_hread"); 
  3.  
  4. //開啟handlerThread,在使用handlerThread.getLooper()之前必須先調用start方法,否則取出的是空 
  5. handlerThread.start(); 
  6.  
  7. //將handler綁定在handlerThread的Looper上,即這個handler是運行在handlerThread線程中的 
  8. myHandler handler=new myHandler(handlerThread.getLooper()); 
  9.  
  10. class myHandler extends Handler{ 
  11. public myHandler(){} 
  12. public myHandler(Looper looper){ 
  13. super(looper); 
  14. @Override 
  15. public void handleMessage(Message msg) { 
  16. // TODO Auto-generated method stub 
  17. System.out.println("Activity Thread:"+Thread.currentThread().getId()); 
  18. }

這樣,就實現了handler的非同步處理機制,在調用handler.post()方法,通過列印線程ID可以得知,子線程與主線程是分屬不同線程的。

----------------------------------------------------------------------

google對handler的說明

A Handler allows you to send and process Message and Runnable objects associated with a thread‘s MessageQueue. Each Handler instance is associated with a single thread and that thread‘s message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.

Scheduling messages is accomplished with the post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long) methods. The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; the sendMessage versions allow you to enqueue a Message object containing a bundle of data that will be processed by the Handler‘s handleMessage(Message) method (requiring that you implement a subclass of Handler).

When posting or sending to a Handler, you can either allow the item to be processed as soon as the message queue is ready to do so, or specify a delay before it gets processed or absolute time for it to be processed. The latter two allow you to implement timeouts, ticks, and other timing-based behavior.

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 then be scheduled in the Handler‘s message queue and processed when appropriate.

 

 

Android:用Handler實現非同步處理功能

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.