轉載: 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:
- Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- switch (msg.what) {
- case 0:
- //完成主界面更新,拿到數據
- String data = (String)msg.obj;
- updateWeather();
- textView.setText(data);
- break;
- default:
- break;
- }
- }
- };
2、子線程發消息,通知Handler完成UI更新:
- private void updateWeather() {
- new Thread(new Runnable(){
- @Override
- public void run() {
- //耗時操作,完成之後發送消息給Handler,完成UI更新;
- mHandler.sendEmptyMessage(0);
- //需要數據傳遞,用下面方法;
- Message msg =new Message();
- msg.obj = "數據";//可以是基本類型,可以是對象,可以是List、map等;
- mHandler.sendMessage(msg);
- }
- }).start();
- }
方法一的Handler對象必須定義在主線程中,如果是多個類直接互相調用,就不是很方便,需要傳遞content對象或通過接口調用;
方法二:用Activity對象的runOnUiThread方法更新
在子線程中通過runOnUiThread()方法更新UI:
- new Thread() {
- public void run() {
- //這兒是耗時操作,完成之後更新UI;
- runOnUiThread(new Runnable(){
- @Override
- public void run() {
- //更新UI
- imageView.setImageBitmap(bitmap);
- }
- });
- }
- }.start();
如果在非上下文類中(Activity),可以通過傳遞上下文實現調用;
- Activity activity = (Activity) imageView.getContext();
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- imageView.setImageBitmap(bitmap);
- }
- });
這種方法使用比較靈活,但如果Thread定義在其他地方,需要傳遞Activity對象;
方法三:View.post(Runnable r)
- imageView.post(new Runnable(){
- @Override
- public void run() {
- imageView.setImageBitmap(bitmap);
- }
- });
這種方法更簡單,但需要傳遞要更新的View過去;
總結:UI的更新必須在主線程中完成,所以不管上述那種方法,都是將更新UI的消息發送到了主線程的消息對象,讓主線程做處理;