1

i am trying to run a handler inside a thread but i'm getting the error "Can't create handler inside thread that has not called Looper.prepare()" i have spent hours looking for a resolution but couldnt find one so i decided to post this. i have tried calling "Looper.prepare();" it fixed the force close problem but stops the code inside handler from working.

    public void ten(View view) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            private Vibrator mVibrator;
            private Runnable runnable;
            private Handler handler;

            public void run() {
                mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                mVibrator.vibrate(1000 * 10);// 10 sec sprint

                // HANDLER
                handler = new Handler();
                runnable = new Runnable() {
                    public void run() {
                        // calculate result1
                        TextView theFact = (TextView) findViewById(R.id.txtCurrentSpeed);
                        String shareFact = theFact.getText().toString();
                        TextView theFact1 = (TextView) findViewById(R.id.result1);
                        theFact1.setText(String.valueOf(shareFact));
                        // calculate result1
                    }
                };
                handler.postDelayed(runnable, 3000);
                // HANDLER END //
            }
        }, 5000, 60 * 1000 * 3);// 3 minute break (+5s first run delay)
    }
}



08-10 21:37:59.187: E/AndroidRuntime(26129): FATAL EXCEPTION: Timer-0
08-10 21:37:59.187: E/AndroidRuntime(26129): Process: com.example.speedometer, PID: 26129
08-10 21:37:59.187: E/AndroidRuntime(26129): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
08-10 21:37:59.187: E/AndroidRuntime(26129):    at android.os.Handler.<init>(Handler.java:200)
08-10 21:37:59.187: E/AndroidRuntime(26129):    at android.os.Handler.<init>(Handler.java:114)
08-10 21:37:59.187: E/AndroidRuntime(26129):    at com.example.speedometer.MainActivity$2.run(MainActivity.java:141)
08-10 21:37:59.187: E/AndroidRuntime(26129):    at java.util.Timer$TimerImpl.run(Timer.java:284)

i replaced the Handler with Thread, the code inside the thread worked, however it force closes giving the following exception:

08-10 21:57:35.477: E/AndroidRuntime(31261): FATAL EXCEPTION: Thread-4399
08-10 21:57:35.477: E/AndroidRuntime(31261): Process: com.example.speedometer, PID: 31261
08-10 21:57:35.477: E/AndroidRuntime(31261): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7147)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:998)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.view.View.requestLayout(View.java:18491)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.view.View.requestLayout(View.java:18491)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.view.View.requestLayout(View.java:18491)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.view.View.requestLayout(View.java:18491)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:361)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.view.View.requestLayout(View.java:18491)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.widget.TextView.checkForRelayout(TextView.java:8060)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.widget.TextView.setText(TextView.java:4836)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.widget.TextView.setText(TextView.java:4660)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.widget.TextView.setText(TextView.java:4635)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at com.example.speedometer.MainActivity$2$1.run(MainActivity.java:154)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at java.lang.Thread.run(Thread.java:818)
MaggotSauceYumYum
  • 402
  • 1
  • 5
  • 23

3 Answers3

2

The Main/UI thread of android has a looper by default. So if you create an instance of Handler any where in Activity/Fragment/View where the method is run on UI thread it will use the default Looper and will never throw you an exception.

So its always better to create Handler on Main/UI threads to update UI.

Having said that the simplest fix for your solution is passing the Default Looper as the argument like this

 handler = new Handler(Looper.getMainLooper());

This will solve your issue as your trying to update the UI.

manjusg
  • 2,275
  • 1
  • 22
  • 31
0

I have seen that you would want to change UI inside that runnable posted to the handler. There is two points that you should be aware of:

  • All UI manipulation should be done in UI/Main thread not a background thread.

  • Handlers stick to the thread in which they've been created.

So, you should create your handler object in the Main/UI thread and then call it's method postDelayed everywhere you want. i.e. Instantiate your handler object before calling to time.schedule() as a final Handler handler and then use it inside that timer task.

Note: For calling a routine in a periodic manner, there is an even simpler and lighter approach discussed here.


EDIT #1

public void ten(View view) {
        // CHANGE #1
        final Handler handler = new Handler();

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            private Vibrator mVibrator;

            public void run() {
                mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                mVibrator.vibrate(1000 * 10);// 10 sec sprint

                // HANDLER
                // CHANGE #2 (Removed this line)
                Runnable runnable = new Runnable() {
                    public void run() {
                        // calculate result1
                        TextView theFact = (TextView) findViewById(R.id.txtCurrentSpeed);
                        String shareFact = theFact.getText().toString();
                        TextView theFact1 = (TextView) findViewById(R.id.result1);
                        theFact1.setText(String.valueOf(shareFact));
                        // calculate result1
                    }
                };
                handler.postDelayed(runnable, 3000);
                // HANDLER END //
            }
        }, 5000, 60 * 1000 * 3);// 3 minute break (+5s first run delay)
    }
Community
  • 1
  • 1
frogatto
  • 28,539
  • 11
  • 83
  • 129
0

Instead of doing a TimerTask, why not use an AlarmManager, if you're trying to perform a task every 3 seconds. Then you will avoid using a handler all together.

Kristy Welsh
  • 7,828
  • 12
  • 64
  • 106