Подтвердить что ты не робот

Обновление Android TextView в потоке и Runnable

Я хочу сделать простой таймер в Android, который обновляет TextView каждую секунду. Он просто подсчитывает секунды, как в Minesweeper.

Проблема в том, что я игнорирую 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();
}

EDIT:

Наконец, я понял. Вот решение для тех, кто интересуется.
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();
}
4b9b3361

Ответ 1

Пользовательский интерфейс может обновляться только через поток пользовательского интерфейса. Вам нужно Handler, чтобы опубликовать его в теме пользовательского интерфейса:

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();
}

Ответ 2

Кроме того, вы можете просто сделать это в своем потоке всякий раз, когда хотите обновить элемент пользовательского интерфейса:

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

Ответ 3

Вы не можете получить доступ к элементам пользовательского интерфейса из потоков, отличных от UI. Попробуйте связать вызов setText(...) с другим Runnable, а затем просмотрите метод View.post(Runnable).

Ответ 4

В качестве опции используйте runOnUiThread() для изменения свойств представлений в основном потоке.

  runOnUiThread(new Runnable() {
        @Override
        public void run() {       
                textView.setText("Stackoverflow is cool!");
        }
    });