Android update TextView in Thread and Runnable

70,150

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.

Share:
70,150
Admin
Author by

Admin

Updated on March 30, 2020

Comments

  • Admin
    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
    nesimtunc almost 11 years
    In my case, there is a textview which is inside a row of listview; can't update its text property ... Any suggestions?
  • Vadorequest
    Vadorequest over 10 years
    Is it bad practice? Use a Handler is better?
  • Meher
    Meher about 10 years
    yes..handler is a better option.Handler is from API 1.