在Thread和Runnable中更新Android的TextView

36
我想在Android上制作一个简单的计时器,每秒更新一次TextView。它只是像扫雷一样计算秒数。
问题是当我忽略tvTime.setText(...)(将其变为// tvTime.setText(...))时,每秒钟会在LogCat中打印出以下数字。但是当我想将此数字设置为另一个线程中创建的TextView时,程序会崩溃。
有没有人有想法如何轻松解决这个问题?
以下是代码(该方法在启动时调用):
private void startTimerThread() {
    Thread th = new Thread(new Runnable() {
        private long startTime = System.currentTimeMillis();
        public void run() {
            while (gameState == GameState.Playing) {
                System.out.println((System.currentTimeMillis() - this.startTime) / 1000);
                tvTime.setText("" + ((System.currentTimeMillis() - this.startTime) / 1000));
                try {
                    Thread.sleep(1000);
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });
    th.start();
}

编辑:

最终,我搞定了。 以下是解决方案,供有兴趣的人参考。

private void startTimerThread() {       
    Thread th = new Thread(new Runnable() {
        private long startTime = System.currentTimeMillis();
        public void run() {
            while (gameState == GameState.Playing) {                
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tvTime.setText(""+((System.currentTimeMillis()-startTime)/1000));
                    }
                });
                try {
                    Thread.sleep(1000);
                } 
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });
    th.start();
}

1
谢谢伙计,这有很大帮助! - CybeX
但是当您点击返回按钮时,它会崩溃。 - J.K
4个回答

54

用户界面只能由UI线程更新。您需要一个Handler,将其发布到UI线程:

private void startTimerThread() {
    Handler handler = new Handler();
    Runnable runnable = new Runnable() {
        private long startTime = System.currentTimeMillis();
        public void run() {
            while (gameState == GameState.Playing) {  
                try {
                    Thread.sleep(1000);
                }    
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
                handler.post(new Runnable(){
                    public void run() {
                       tvTime.setText("" + ((System.currentTimeMillis() - this.startTime) / 1000));
                }
            });
            }
        }
    };
    new Thread(runnable).start();
}

在我的情况下,有一个TextView位于ListView的一行内; 无法更新其文本属性... 有什么建议吗? - nesimtunc

32

或者,您也可以在需要更新 UI 元素时直接在您的线程中执行以下操作:

runOnUiThread(new Runnable() {
    public void run() {
        // Update UI elements
    }
});

这是不好的做法吗?使用Handler更好吗? - Vadorequest
是的,handler 是更好的选项。Handler 来自 API 1。 - Meher

2
作为一种选择,可以使用runOnUiThread()在主线程中更改视图属性。
  runOnUiThread(new Runnable() {
        @Override
        public void run() {       
                textView.setText("Stackoverflow is cool!");
        }
    });

1

非 UI 线程无法访问 UI 元素。尝试使用另一个 Runnable 包装对 setText(...) 的调用,然后查看 View.post(Runnable) 方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接