8

Possible Duplicate:
Android Toast started from Service only displays once

I'm using Service Android defined in android.app.Service.

I call this Service (myService) from an Activity.

MyService is:

public class myService extends Service{

 public IBinder onBind(Intent intent){
    return null;
}

public void onCreate(){
    super.onCreate();
    TimerTask task = new TimerTask(){
        public void run(){
            Log.i("test","service running");
            checkDate();            
        }           
    };
    timer = new Timer();
    timer.schedule(task, 0, 20000);
}

 public void checkDate(){
    Toast toast = Toast.makeText(this, "SIMPLE MESSAGE!", Toast.LENGTH_LONG);
    toast.show();
}

}

The method checkDate() resides in the class myService.

The error produced is:

 09-19 15:41:35.267: E/AndroidRuntime(2026): FATAL EXCEPTION: Timer-0
 09-19 15:41:35.267: E/AndroidRuntime(2026): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
 09-19 15:41:35.267: E/AndroidRuntime(2026):    at android.os.Handler.<init>(Handler.java:121)
 09-19 15:41:35.267: E/AndroidRuntime(2026):    at android.widget.Toast$TN.<init>(Toast.java:310)
 09-19 15:41:35.267: E/AndroidRuntime(2026):    at android.widget.Toast.<init>(Toast.java:84)
 09-19 15:41:35.267: E/AndroidRuntime(2026):    at android.widget.Toast.makeText(Toast.java:226)
Community
  • 1
  • 1
GVillani82
  • 17,196
  • 30
  • 105
  • 172
  • Can you post the code you use to start this? Also is this an actual Android service or is it just a background thread? The issue is you cannot interact with the UI from a background thread. If you have a reference to the Activity context you can call runOnUIThread using that context. – Bobbake4 Sep 19 '12 at 15:52

2 Answers2

23

TimerTask runs in a separate thread. Toast.makeText() must be executed from a thread that has established a Handler/Looper. Basically this means you need to make the toast on a thread that has the standard Android message/event dispatcher running in it.

Easiest way to do this would be in your checkDate() method:

runOnUiThread(new Runnable() {
    public void run() {
        Toast toast = Toast.makeText(this, "SIMPLE MESSAGE!", Toast.LENGTH_LONG);
        toast.show();
    }
 });

EDIT: I'm an idiot, that's not right. You can't call runOnUiThread() from a Service context

You need to use a Handler for this. In your service:

private Handler handler;

in onCreate() of your service:

handler = new Handler();

in checkDate() method:

handler.post(new Runnable() {
    public void run() {
        Toast toast = Toast.makeText(myService.this, "SIMPLE MESSAGE!", Toast.LENGTH_LONG);
        toast.show();
    }
 });
David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • I tried this, but return this error: The method runOnUiThread(new Runnable(){}) is undefined for the type myService – GVillani82 Sep 19 '12 at 16:01
  • Sorry, I'm an idiot. I've edited my post accordingly. You need to use a Handler for this. – David Wasser Sep 19 '12 at 16:07
  • Ok. There is just another problem on "makeText" : The method makeText(Context, CharSequence, int) in the type Toast is not applicable for the arguments (new Runnable(){}, String, int) – GVillani82 Sep 19 '12 at 16:10
  • You need to specify `myService.this` as the first parameter of `makeText()`. I edited my answer again. – David Wasser Sep 19 '12 at 16:12
  • 1
    Sure. Glad it works. Sorry about the first answer. I wasn't thinking too clearly at the time. Gosh, sometimes being human has its downsides ;-) – David Wasser Sep 19 '12 at 16:34
  • +1 for accepted answer, thanks to showing another way to do it :) – Lucifer Sep 20 '12 at 02:00
  • I have a similar problem with dialog: I don't know how pass right context :( [link](http://stackoverflow.com/questions/12509942/error-calling-dialog-from-service-android) – GVillani82 Sep 20 '12 at 09:51
  • @Joseph82 for your dialog/context problem maybe you should open another question so as not to overload this question. – David Wasser Sep 20 '12 at 10:18
  • @Wasser You are right! In fact I just put link here for my new question :) [my_new_question](http://stackoverflow.com/questions/12509942/error-calling-dialog-from-service-android) – GVillani82 Sep 20 '12 at 10:26
4

You're calling it from a worker thread. You need to call Toast.makeText() (and most other functions dealing with the UI) from within the main thread. You could use a handler, for example.

You need to call Toast.makeText(...) from the UI thread:

activity.runOnUiThread(new Runnable() {
  public void run() {
    Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
  }
});
Lucifer
  • 29,392
  • 25
  • 90
  • 143