[Android] thread 處理 UI update

Android 背景執行緒出現『Only the original thread...』錯誤的解法:使用 runOnUiThread 方法才能安全修改 UI,附 ProgressDialog 完整程式碼範例。

不知道大家在寫 Android 用 thread 處理 UI 更新時,有沒有遇過這樣的錯誤:

Only the original thread that created a view hierarchy can touch its views.

通常這是因為自己產生的 thread 不能去更動到 原本 main thread 的 view

只有 main thread 可以去動 UI,因此我們必須透過 runOnUiThread 這個方法來對 UI 做操作

這裡以下面這個 ProgressDialog 做例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package org.twgg.kerkerj;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class PDExample extends Activity implements Runnable {
	private String pi="null";
  private Button btn;
  private TextView text;
  private ProgressDialog pd;
  
  public void onCreate(Bundle icicle) {
  	super.onCreate(icicle);
    setContentView(R.layout.main);
    
    text = (TextView) this.findViewById(R.id.text);
    btn = (Button) this.findViewById(R.id.btn);
    
    //按下 Button 則會開始運算,運算的東西放在 thread 裡
    btn.setOnClickListener(new OnClickListener(){
    	public void onClick(View v) {
      	// Progress Dialog 開始跑
        pd = ProgressDialog.show(PDExample.this, "運算中", "機哩咕嚕機哩咕嚕...", true, false);
        Thread thread = new Thread(PDExample.this);
        
        //進入 thread
        thread.start();
       }
    });
	}
  
  public void run() {
  	try {
    	//要運算的東西放這裡
      Thread.sleep(10000); //在這裡只是讓 thread停久一點感覺一下
      pi = "ya, we're done!";
      
      //Wrong!! 以下兩行會出錯, 因為這是在新的 thread 裡要求更改 UI view
      pd.dismiss();
      text.setText(pi);
    } catch (InterruptedException e) {
    	e.printStackTrace();
    }
  }  
}  

正確的 run() 必須這樣:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public void run() {
	try {
  	//要運算的東西放這裡
    Thread.sleep(10000); //在這裡只是讓 thread停久一點感覺一下
    pi = "ya, we're done!";
    
    runOnUiThread(new Runnable() { // Correct!! 
    	public void run() {
    		//modify View object
      	pd.dismiss();
      	text.setText(pi);
    	}
  	});
	} catch (InterruptedException e) {
  	e.printStackTrace();
	}  
}

p.s. 之前 Google 有另外一種解法是用 handler 去處理 UI update

不過既然都有 runOnUiThread 這個好用的方法就用它吧 :)

2012/06/13續: [Android] thread 處理 UI update (2)

comments powered by Disqus
Powered by Hugo. Theme Stack. All Rights Reserved.