线程更新UI
最近发现一个问题,当在activity中启动一个线程,这个线程类有一个构造参数是textview时,在run中更新这个textview中的setText不出错,,反而new 无参线程类后,再setTextView(TextView)后在run中setText()就出错,这是怎么回事呢??求教 --------------------编程问答-------------------- 非UI线程是没有更新UI的权限的。 --------------------编程问答-------------------- 为什么上面其中一个办法就能更新呢? --------------------编程问答-------------------- - -第一个能更新么~ 想看看你怎么写的。~ 非UI线程更新UI会报错的 --------------------编程问答--------------------
你确定自己启动了一个线程? --------------------编程问答-------------------- 顶一下!
发一下代码:
package extthread;
import android.widget.TextView;
public class MyUpdateUIThread extends Thread {
private TextView textView1;
public MyUpdateUIThread(TextView textView1) {
super();
this.textView1 = textView1;
}
@Override
public void run() {
super.run();
textView1.setText("zzzzzzzzzzzzzz");
}
}
------------------------------
package testtest.test.run;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import extthread.MyUpdateUIThread;
public class Main extends Activity {
TextView textView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView) this.findViewById(R.id.textView1);
Thread thread = new Thread(new MyUpdateUIThread(textView));
thread.start();
}
};
上面用线程代码不出错! --------------------编程问答-------------------- 只能在主线程中操作UI。
所以如果你想在非主线程中操作UI,就要在使用消息发送的方式。
例:
在主线程中定义handler:
Handler h=new Handler(){
public void handleMessage(Message msg){
//你的操作
}
}
在非主线程这样使用:
h.sendMessage(Message.obtain()); //也可以新建一个Message对象 --------------------编程问答--------------------
楼上的是可以的。
以至于你的代码为什么没错,估计是因为把对象传过来了,而对象是在主线程中new的。所以就可以更新了吧。 --------------------编程问答-------------------- --------------------编程问答-------------------- Handler h=new Handler(){
public void handleMessage(Message msg){
//你的操作
}
}
在非主线程这样使用:
h.sendMessage(Message.obtain()); //也可以新建一个Message对象
这种方法可行! --------------------编程问答-------------------- Thread thread = new Thread(new MyUpdateUIThread(textView));
thread.start();
首先看到你这样创建线程时,我震惊了~你的MyUpdateUIThread纯当实现Runnable接口的类来使用了~
直接
Thread thread = new MyUpdateUIThread(textView);
thread.start();
就好了。
然后我直接测试下。。发现问题了。。
居然真的能textView1.setText("zzzzzzzzzzzzzz");不报错。
这太操蛋了~于是我分别在onCreate和run方法里加了打印语句Thread.currentThread().getName()
10-31 09:55:15.348: VERBOSE/King(1228): in run : Thread-10
10-31 09:56:33.088: VERBOSE/King(1328): in Activity : main
明明是不同线程是确定了的~
然后。。。我在run方法里加了个sleep()想看看可不可以隔几秒再把“zzzzzzz”更新到UI上去,如下:
public void run() {
super.run();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
textView1.setText("zzzzzzzzzzzzzz");
Log.v("King", "in run : "+Thread.currentThread().getName());
}
这样就出错了。
我也纳闷了。为了不sleep能正常运行。应该是会出错的啊。
建议没试过的童鞋都试一下。。惊天发现啊~
--------------------编程问答-------------------- 正在跟踪这个问题,确实蛮有趣的,不过这和UI单线程不冲突,只是我们理解不全面造成的,网上的单线程安全很少考虑这个问题。这个单线程的内部实现机制有关吧,继续关注。 --------------------编程问答-------------------- 测试过程发现,如果这个线程是通过监听器启动的,也就是说不是在主线程中直接启动,就会报错。现在想来和java的线程触发可能有关联。 --------------------编程问答--------------------
run方法的里面的sleep()抛的异常是什么? --------------------编程问答-------------------- sleep方法不会抛异常。
textView1.setText("zzzzzzzzzzzzzz");这句才会。
异常信息如下,大家应该曾经都见过~:
10-31 11:47:04.118: ERROR/AndroidRuntime(3878): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
我估计是在主线程初始化界面完毕之前其他线程能改UI的内容吧...或许是在onResume执行完毕之前...像什么通过监听器触发或者sleep了几秒后,UI初始化已经完毕了,于是不能在别的线程里改了... --------------------编程问答-------------------- 呵呵,感谢大家的顶贴,继续顶一顶, --------------------编程问答-------------------- ding顶一下吧
--------------------编程问答-------------------- --------------------编程问答--------------------
都是在onCreate里进行操作。都是不耗时的简单线程。这样有什么意义呢?如果你的线程在onResume之后执行,100%出错。 --------------------编程问答-------------------- 我也测试了一下Thread.sleep()
这句话放到activity里面就没有问题,放到run里面就不行,求解 --------------------编程问答-------------------- 刚才测试了,onResume中启动线程依然没报错,挺神奇的! --------------------编程问答--------------------
不神奇。onResume之后就会报错了。比如点击button启动 --------------------编程问答-------------------- 老问题了,用HANDLE实现 --------------------编程问答-------------------- 顶!顶!顶!顶! --------------------编程问答-------------------- 要通过handler --------------------编程问答-------------------- 用handler安全无痛苦。。。 --------------------编程问答-------------------- 在线程的run方法中使用runOnUiThread来更新TextView
Your_Current_Activity.this.runOnUiThread(new Runnable() {
public void run() {
//update textview here
}
});
改变你的 MyUpdateUIThread 构造函数:
private TextView textView1;
Activity activity;
public MyUpdateUIThread(TextView textView1,Activity activity) {
super();
this.textView1 = textView1;
this.activity=activity;
}
@Override
public void run() {
super.run();
activity.runOnUiThread(new Runnable() {
public void run() {
//update textview here
textView1.setText("zzzzzzzzzzzzzz");
}
});
}
然后在 Main Activity 中创建 MyUpdateUIThread 对象:
Thread thread = new Thread(new MyUpdateUIThread(textView,Main.this));
--------------------编程问答-------------------- 在oncreate和onresume之前view是没有调用invalidate()方法,所以调用到ViewRoot里面的 void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}这个方法,所以不会有异常抛出,而settext的字符已经设置进去了,在onresume后得到焦点,再invalidate()就出现了在线程设置的字符串 --------------------编程问答-------------------- 还没完?给分吧 --------------------编程问答-------------------- 还没完?给分吧+1 --------------------编程问答-------------------- 确实挺奇怪的,用handler吧。。。 --------------------编程问答-------------------- 一般只有在Activity的onResume()回调后,才会通过UI Thread建立View 树,当然最重要的是ViewRoot对象,如
你直接通过一个线程run时,可能onResume()方法还没有回调,此时当然能调用View.setXXX(),在onResume()方法回调后,一定会报异常的。这样就可以解释10L同学的答案了。 --------------------编程问答-------------------- .net可以通过delegate进行线程更新UI线程,java不知道怎么搞 --------------------编程问答--------------------
onResume里面更新也没报错 --------------------编程问答--------------------
基本原理是这样的,但由于这些行为都涉及了很多IPC操作,导致onResume()后,UI Thread建立View 树还没有成功,此时,依旧可以通过线程操作View对象了。不过View添加至窗口后,就只能在UI Thread更新了。 --------------------编程问答-------------------- --------------------编程问答-------------------- 用 Handler --------------------编程问答-------------------- 在子线程中除了可以改变textview,button的内容外,还有什么进度条,button,textview等等的显示(setvisibile属性),弄得我一时纳闷了,什么才是UI?不是子线程不能改变UI么? --------------------编程问答--------------------
先百度或google一下吧……
补充:移动开发 , Android