Android子線程中更新UI的3種方法

轉載: http://gqdy365.iteye.com/blog/2112471

在Android項目中經常有碰到這樣的問題,在子線程中完成耗時操作之後要更新UI,下面就自己經歷的一些項目總結一下更新的方法: 


在看方法之前看一下Android中消息機制: 

 
引用

Message:消息,其中包含了消息ID,消息處理對象以及處理的數據等,由MessageQueue統一列隊,終由Handler處理。 
Handler:處理者,負責Message的發送及處理。使用Handler時,需要實現handleMessage(Message msg)方法來對特定的Message進行處理,例如更新UI等。 
MessageQueue:消息隊列,用來存放Handler發送過來的消息,並按照FIFO規則執行。當然,存放Message並非實際意義的保存,而是將Message以鏈表的方式串聯起來的,等待Looper的抽取。 
Looper:消息泵,不斷地從MessageQueue中抽取Message執行。因此,一個MessageQueue需要一個Looper。 
Thread:線程,負責調度整個消息循環,即消息循環的執行場所。 


不熟悉的朋友可以參考一下這篇文檔: 
Android知識梳理:消息機制之Handler:http://gqdy365.iteye.com/blog/2148925 
Android知識梳理:消息機制之Looper :http://gqdy365.iteye.com/blog/2137494 

下面基於上述原理說一下更新方法: 
方法一:用Handler 

1、主線程中定義Handler: 

Java代碼  收藏代碼
  1. Handler mHandler = new Handler() {  
  2.   
  3.         @Override  
  4.         public void handleMessage(Message msg) {  
  5.             super.handleMessage(msg);  
  6.             switch (msg.what) {  
  7.             case 0:  
  8.                 //完成主界面更新,拿到數據  
  9.                 String data = (String)msg.obj;  
  10.                   
  11.                 updateWeather();  
  12.                 textView.setText(data);  
  13.                 break;  
  14.             default:  
  15.                 break;  
  16.             }  
  17.         }  
  18.   
  19.     };  


2、子線程發消息,通知Handler完成UI更新: 
Java代碼  收藏代碼
  1. private void updateWeather() {  
  2.           
  3.           
  4.         new Thread(new Runnable(){  
  5.   
  6.             @Override  
  7.             public void run() {  
  8.                 //耗時操作,完成之後發送消息給Handler,完成UI更新;  
  9.                 mHandler.sendEmptyMessage(0);  
  10.                   
  11.                 //需要數據傳遞,用下面方法;  
  12.                 Message msg =new Message();  
  13.                 msg.obj = "數據";//可以是基本類型,可以是對象,可以是List、map等;  
  14.                 mHandler.sendMessage(msg);  
  15.             }  
  16.               
  17.         }).start();  
  18.           
  19.     }  

方法一的Handler對象必須定義在主線程中,如果是多個類直接互相調用,就不是很方便,需要傳遞content對象或通過接口調用; 

方法二:用Activity對象的runOnUiThread方法更新 
在子線程中通過runOnUiThread()方法更新UI: 
Java代碼  收藏代碼
  1. new Thread() {  
  2.             public void run() {  
  3.                 //這兒是耗時操作,完成之後更新UI;  
  4.                 runOnUiThread(new Runnable(){  
  5.   
  6.                     @Override  
  7.                     public void run() {  
  8.                         //更新UI  
  9.                         imageView.setImageBitmap(bitmap);  
  10.                     }  
  11.                       
  12.                 });  
  13.             }  
  14.         }.start();  

如果在非上下文類中(Activity),可以通過傳遞上下文實現調用; 
Java代碼  收藏代碼
  1. Activity activity = (Activity) imageView.getContext();  
  2.                 activity.runOnUiThread(new Runnable() {  
  3.   
  4.                     @Override  
  5.                     public void run() {  
  6.                         imageView.setImageBitmap(bitmap);  
  7.                     }  
  8.                 });  

這種方法使用比較靈活,但如果Thread定義在其他地方,需要傳遞Activity對象; 

方法三:View.post(Runnable r) 

Java代碼  收藏代碼
  1. imageView.post(new Runnable(){  
  2.   
  3.                     @Override  
  4.                     public void run() {  
  5.                         imageView.setImageBitmap(bitmap);  
  6.                     }  
  7.                       
  8.                 });  


這種方法更簡單,但需要傳遞要更新的View過去; 
總結:UI的更新必須在主線程中完成,所以不管上述那種方法,都是將更新UI的消息發送到了主線程的消息對象,讓主線程做處理;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章