Android update TextView in Thread and Runnable
Solution 1
The UserInterface can only be updated by the UI Thread. You need a Handler, to post to the UI Thread:
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();
}
Solution 2
Alternatively, you can also just do this in your thread whenever you want to update a UI element:
runOnUiThread(new Runnable() {
public void run() {
// Update UI elements
}
});
Solution 3
As an option use runOnUiThread() to change de views properties in the main thread.
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("Stackoverflow is cool!");
}
});
Solution 4
You cannot access UI elements from non-UI threads. Try surrounding the call to setText(...)
with another Runnable
and then look into the View.post(Runnable)
method.
Admin
Updated on March 30, 2020Comments
-
Admin about 4 years
I want to make a simple timer in Android that updates a TextView every second. It simply counts seconds like in Minesweeper.
The problem is when i ignore the tvTime.setText(...) (make it //tvTime.setText(...), in LogCat will be printed the following number every second. But when i want to set this number to a TextView (created in another Thread), the program crashes.
Does anyone have an idea how to solve this easily?
Here's the code (method is called on startup):
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:
Finally, I got it. Here is the solution, for those who are interested in.
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(); }
-
nesimtunc almost 11 yearsIn my case, there is a textview which is inside a row of listview; can't update its text property ... Any suggestions?
-
Vadorequest over 10 yearsIs it bad practice? Use a Handler is better?
-
Meher about 10 yearsyes..handler is a better option.Handler is from API 1.