我写了下面一段代码,如果把PPP类中的run方法里面的sleep去除,会发现程序成功的改变了TextView的文字,或者sleep后的参数放置的比较小,程序也能成功的改变TextView的文字。如果我在sleep后面放置的值大一些(换过一些数字后发现是 > 150,也许和运行环境有关),就会出现CalledFromWrongThreadException异常,这是什么原理?为什么在前面的情况下我可以在非主线程中间改变ui,而后面的情况却不可以?public class TV extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        HandlerThread ht = new HandlerThread("pig");
        ht.start();
        Handler h = new Handler(ht.getLooper());
        
        h.post(new PPP((TextView) findViewById(R.id.t)));
    }
    
    class PPP implements Runnable{     private TextView tv;
     public PPP(TextView tv){
     this.tv = tv;
     }
    
@Override
public void run() {
try {
Thread.sleep(140);//这里
} catch (InterruptedException e) {
e.printStackTrace();
}
tv.setText("11111111111");
}
    }
}

解决方案 »

  1.   

    当你的业务运行需要的时间很长导致需要开启子线程去做这个业务, 而又需要对更新UI的时候。
    因为如果长时间的业务放到了UI线程的话, 当这个业务在运行的时候,你在UI上做了别的操作,
    如果一段时间之内的这个操作没有响应就会导致ANR的
      

  2.   

    闲得蛋疼,这是未定义行为,因为ui的类都不是thread-safe的,你不是试图是推断出什么时候可以操作,什么时候不可以操作,竞态条件什么时候满足你怎么去推测
      

  3.   

    额,这个太玄了,那能说下后面贴的代码的行为为什么会随着sleep时间的长短表现出不同的行为来着
      

  4.   

    ui操作还是放到ui线程里去做
    正如3楼所说
    有时候你放在子线程里去对ui线程做操作并不会报错,但是那是不安全的,还是有几率报错的
      

  5.   

    非主线程更改UI会报错的,这里的更改是对控件进行设置即set操作。
      

  6.   

     ViewRoot是所有视图的基类,在创建任何View时都会调用Thread.currentThread获取当前线程并赋给ViewRoot中的全局变量(作为该View的绑定线程)以后对view的任何操作都会调用ViewRoot中的checkThread验证当前线程(Thread.currentThread)与创建时绑定的线程是否相同,不同则抛出异常CalledFromWrongThreadException一般很少在创建View时开启线程,所以View的绑定线程通常是主线程(main)
      

  7.   

    在创建时开启自己的线程,在该线程中UI操作当然就能通过checkThread的验证,从而不会抛出异常CalledFromWrongThreadException