1

我试图做其他事情,但继续删除代码,认为简化事情将有助于识别我的错误。这就是我剩下的(经过大量简化),但我仍然不明白为什么它不应该这样做!

public class MyOwnTimerActivity extends Activity {

    int timeLeft = 5;
    TextView timerTextView;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button timerButton = (Button) findViewById(R.id.button1);
        timerTextView = (TextView) findViewById(R.id.timerText);

        Thread timer = new Thread() {
            public void run() {
                try {
                    sleep(3000);
                } 
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
                finally{
                    timerTextView.setText("something");
                }
            }
        };
        timer.start();
    }
}

错误:应用程序在 3 秒后崩溃,即在计时器关闭后。

4

3 回答 3

4

啊,是的))这是因为您尝试从非 UI 线程修改 UI

更新:

有几种方法可以从另一个线程修改 UI:

  • 使用Handler具有覆盖handleMessage()方法 的类
  • 使用Activity带有调用runOnUI()方法的类,将Runnable对象传递run()给您修改 UI 的方法
  • 使用View.post()View.postDelayed()方法

    在您的情况下,最后一个变体是最方便的。以这种方式修改您的代码:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button timerButton = (Button) findViewById(R.id.button1);
        timerTextView = (TextView) findViewById(R.id.timerText);
        timerTextView.postDelayed(
            new Runnable() {
               @Override
               run() {
                   timerTextView.setText("something");
               }
            }, 3000);
    }
    
  • 于 2012-06-14T17:52:32.030 回答
    2

    您不应该从工作线程更改 UI。使用在主线程上初始化的处理程序,并使用临时 Runnable 在主线程上执行 setText()。

    Handler h = new Handler();
    Thread timer = new Thread() { 
    //...
        finally
        {
             h.post(new Runnable(){
                 public void run()
                 {
                     timerTextView.setText("something"); 
                 }
             });
         }
    

    事实上,整个片段可以使用 Handler.postDelayed() 重写。但是你最终可能会想用线程做更多有趣的事情。

    于 2012-06-14T17:53:18.327 回答
    0

    您是否尝试过使用 runOnUI 从 UI 线程设置文本?你可以这样做:

    runOnUiThread(new Runnable() { 
        public void run() 
        { 
            timerTextView.setText("something");
        } 
     }); 
    

    请记住,您对 timerTextView 的引用以及您想要显示的任何文本都必须修改为最终变量,以便从另一个线程引用它。

    于 2012-06-14T17:54:55.867 回答