16

I have a service. And there is a method called onServiceUpdate(). This method is similiar with onLocationChanged() in Google Maps API.

So i want to start CountDownTimer inside onServiceUpdate() method but showing error like this :

Can't create handler inside thread that has not called Looper.prepare()
    java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
            at android.os.Handler.<init>(Handler.java:200)
            at android.os.Handler.<init>(Handler.java:114)
            at android.os.CountDownTimer$1.<init>(CountDownTimer.java:114)
            at android.os.CountDownTimer.<init>(CountDownTimer.java:114)
            at skripsi.ubm.studenttracking.Service2$6.<init>(Service2.java:317)
            at skripsi.ubm.studenttracking.Service2.onServiceUpdate(Service2.java:317)

This is my code :

    @Override
    public void onServiceUpdate(ServiceState state)
    {
final float[] distance = new float[2];
        Location.distanceBetween(state.getGeoPoint().getLatitude(), state.getGeoPoint().getLongitude(), 6.130607787619352,106.81839518499267, distance);
        if (distance[0] > 25.0)
        {

                        CountDownTimer cdt5  = new CountDownTimer(total_onServiceUpdate,1000) {
                            @Override
                            public void onTick(long millisUntilFinished) {
                                total_onServiceUpdate = millisUntilFinished/1000;
                            }

                            @Override
                            public void onFinish() {
                                sendSMS();
                                stopSelf();
                            }
                        }.start();

        }
Leonard Febrianto
  • 964
  • 2
  • 12
  • 37

4 Answers4

30

the onServiceUpdate() is an aysnchronous task that runs and notifies you, hence its a background thread. all you need to do is call timer.start(); from the main Thread, the Service actually runs on the main Thread, it is intentService that doesn't so, your solution is along the ways of

new Handler(Looper.getMainLooper()).post(new Runnable() {           
        @Override
        public void run() {
            CountDownTimer cdt5  = new CountDownTimer(total_onServiceUpdate,1000) {
                        @Override
                        public void onTick(long millisUntilFinished) {
                            total_onServiceUpdate = millisUntilFinished/1000;
                        }

                        @Override
                        public void onFinish() {
                            sendSMS();
                            stopSelf();
                        }
                    }.start();
        }
    });

now you can continue sir. Always call codes the flirt with the Screen on the main Looper

Hope it helps

Elltz
  • 10,730
  • 4
  • 31
  • 59
  • Great help. One more question. I want to stopself() inside that handler but it didn't work. Could you help me ? – Leonard Febrianto Sep 01 '15 at 07:07
  • the service didnt stop? well try `TheNameOfYourService.this.stopSelf()` if it doesn't , try `stopService(new Intent(getApplicationContext(),TheNameOfYourService.class));` _they are different ways of killing the cat_ .if it still doesn't introduce me to your service a little. @LeonardFebrianto and also let me know if your quest was solved by comment and upvote or tick.. Thanks – Elltz Sep 01 '15 at 07:44
  • Is it bad if I create a new handler after one loop has finished. Lets say after every 10s I create a new handler and once that Is finished I create a new one. – Richard Nov 02 '18 at 17:38
  • @kataroty i do not understand your question, you mean in a loop or _loop_ here means the `Looper`? – Elltz Nov 05 '18 at 00:21
  • @Elltz Sorry for writing the question badly. But what I meant was creating new `Looper` on every iteration of the `loop`. How bad for performance is that? – Richard Nov 05 '18 at 08:13
1

Android :

Try This before calling a Handler

if (Looper.MyLooper() == null) { Looper.Prepare(); }

Amit gupta
  • 107
  • 1
  • 3
0

I think the problem is that in your sendSMS() you are trying to do something which requires UIThread (like updating a view). Try this:

Handler mHandler = new Handler() {
 public void handleMessage(Message msg){
    sendSMS();
}};

Modify the onFinish method to

@Override
public void onFinish() {
    mHandler.sendEmptyMessage(0);
    stopSelf();
}
Ungureanu Liviu
  • 4,034
  • 4
  • 37
  • 42
  • Error throws after `cdt.start()`. Its not perform any actions in `onFinish()` method. I think the problem might be with changing the value of `millisInFuture` in every `onTick` – Lau Aug 31 '15 at 08:35
0

You cannot update a activity gui from a service via a handler because the handler has to be created in the gui thread.

instead you have to send a broadcast from your service and implement a local broadcast-receiver in the activity that gets this broadcast

k3b
  • 14,517
  • 7
  • 53
  • 85