J. Walsh
J. Walsh

Reputation: 43

Android Dev: Run TimerTask in UI Thread

Im trying to update a TextView.

This method is located in my Main Class and it is called in onCreate();

I have tried using runOnUiThread() to no avail..

As soon as the 30 seconds is reached and it tries to update the TextView it crashes!

Any help is appreciated:

public void updateDisplay() {
    Timer timer = new Timer();


    timer.schedule(new TimerTask() {


                       public void run() {
                           Calendar c = Calendar.getInstance();
                           int mYear = c.get(Calendar.YEAR);
                           int mMonth = c.get(Calendar.MONTH);
                           int mDay = c.get(Calendar.DAY_OF_MONTH);
                           int mHour = c.get(Calendar.HOUR_OF_DAY);
                           int mMinute = c.get(Calendar.MINUTE);

                           textView3.setText(new StringBuilder()
                                   // Month is 0 based so add 1
                                   .append(mDay).append("/")
                                   .append(mMonth + 1).append("/")
                                   .append(mYear)
                                   .append(" - ")
                                   .append(mHour)
                                   .append(":")
                                   .append(mMinute));
                       }
                   }

            ,0,30000);//Update text every 30 seconds
}

And the error is:

E/AndroidRuntime: FATAL EXCEPTION: Timer-0
              Process: ggrgroup.com.workforceapp, PID: 21879
              android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
                  at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7261)
                  at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:1100)
                  at android.view.ViewGroup.invalidateChild(ViewGroup.java:5219)
                  at android.view.View.invalidateInternal(View.java:12900)
                  at android.view.View.invalidate(View.java:12860)
                  at android.view.View.invalidate(View.java:12844)
                  at android.widget.TextView.checkForRelayout(TextView.java:7459)
                  at android.widget.TextView.setText(TextView.java:4390)
                  at android.widget.TextView.setText(TextView.java:4247)
                  at android.widget.TextView.setText(TextView.java:4222)
                  at ggrgroup.com.workforceapp.MainActivity$1.run(MainActivity.java:77)
                  at java.util.Timer$TimerImpl.run(Timer.java:284)

Upvotes: 3

Views: 5409

Answers (3)

pleft
pleft

Reputation: 7905

Use a handler as stated by @Ezio

Handler handler = new Handler(Looper.getMainLooper());
    
Runnable runnable = new Runnable() {

    public void run() {
        Calendar c = Calendar.getInstance();
        int mYear = c.get(Calendar.YEAR);
        int mMonth = c.get(Calendar.MONTH);
        int mDay = c.get(Calendar.DAY_OF_MONTH);
        int mHour = c.get(Calendar.HOUR_OF_DAY);
        int mMinute = c.get(Calendar.MINUTE);

        textView3.setText(new StringBuilder()
            // Month is 0 based so add 1
            .append(mDay).append("/")
            .append(mMonth + 1).append("/")
            .append(mYear)
            .append(" - ")
            .append(mHour)
            .append(":")
            .append(mMinute));

        //repeat every 30secs
        handler.postDelayed(this, 30000);
    }
}

handler.postDelayed(runnable, 30000);
  • Looper.getMainLooper() will run the runnable on the UI Thread
  • handler.postDelayed(this, 30000); will make it repeat every 30secs

Upvotes: 1

Hiroo
Hiroo

Reputation: 135

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

because you edit textView3 in thread

try it :

public void updateDisplay() { Timer timer = new Timer();

timer.schedule(new TimerTask(){


    public void run() {

        runOnUiThread(new Runnable(){
            @Override
            public void run() {
                Calendar c = Calendar.getInstance();
                int mYear = c.get(Calendar.YEAR);
                int mMonth = c.get(Calendar.MONTH);
                int mDay = c.get(Calendar.DAY_OF_MONTH);
                int mHour = c.get(Calendar.HOUR_OF_DAY);
                int mMinute = c.get(Calendar.MINUTE);

                textView3.setText(new StringBuilder()
                    // Month is 0 based so add 1
                    .append(mDay).append("/")
                    .append(mMonth + 1).append("/")
                    .append(mYear)
                    .append(" - ")
                    .append(mHour)
                    .append(":")
                    .append(mMinute));
            }
        });

    }
}

, 0, 30000);//Update text every 30 seconds

}

Upvotes: 1

Dilip
Dilip

Reputation: 2734

    public void updateDisplay() {   
      Timer timer = new Timer();
      timer.schedule(new TimerTask() {

    @Override
    public void run() {
        // Your logic here...

        // When you need to modify a UI element, do so on the UI thread. 
        // 'getActivity()' is required as this is being ran from a Fragment.
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // This code will always run on the UI thread, therefore is safe to modify UI elements.
                myTextBox.setText("my text");
            }
        });
    }
}, 0, 30000); // End of your timer code.   

 }

Upvotes: 2

Related Questions