IntentService won't show Toast
Asked Answered
A

4

29

This IntentService I created will show Toasts in onStartCommand() and in onDestroy(), but not in onHandleIntent(). Am I missing something about the limitations of an IntentService?

public class MyService extends IntentService {

private static final String TAG = "MyService";

public MyService(){
    super("MyService");
}

@Override
protected void onHandleIntent(Intent intent) {
    cycle();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); //This happens!
    return super.onStartCommand(intent,flags,startId);
}

@Override
public void onCreate() {
    super.onCreate();

}

@Override
public void onDestroy() {
    Toast.makeText(this, "service stopping", Toast.LENGTH_SHORT).show(); //This happens!
    super.onDestroy();
}

private void cycle(){
      Toast.makeText(this, "cycle done", Toast.LENGTH_SHORT).show();  //This DOESN'T happen!
      Log.d(TAG,"cycle completed"); //This happens!
}
}
Amathist answered 18/3, 2011 at 1:1 Comment(1)
possible duplicate of create toast from IntentServicePerlaperle
M
19

onHandleIntent() is called from a background thread (that is what IntentService is all about), so you shouldn't do UI from there.

Mutate answered 18/3, 2011 at 1:26 Comment(1)
That was it, thanks! I created a handler field in onStartCommand() and posted the Toast to the handler and it worked.Amathist
P
69

The accepted answer is not correct.

Here is how you can show toast from onHandleIntent():

Create a DisplayToast class:

public class DisplayToast implements Runnable {
    private final Context mContext;
    String mText;

    public DisplayToast(Context mContext, String text){
        this.mContext = mContext;
        mText = text;
    }

    public void run(){
        Toast.makeText(mContext, mText, Toast.LENGTH_SHORT).show();
    }
}

Instantiate a Handler in your service's constructor and call the post method with a DisplayToast object inside.

public class MyService extends IntentService {
Handler mHandler;

public MyService(){
    super("MyService");
    mHandler = new Handler();
}

@Override
protected void onHandleIntent(Intent intent) {
    mHandler.post(new DisplayToast(this, "Hello World!"));

}
}
Perlaperle answered 19/12, 2013 at 19:36 Comment(6)
Damn that's clever. I wish there was a tip bot on stack overflow so I could give you dogecoin for an excellent answer.Brainsick
IIRC, this is similar to how I solved the problem. The accepted answer is correct, and your answer provides the details of how to get around it (submit it to a handler so it is called on the correct thread.Amathist
Won't this handler bind to the current thread as opposed to the main thread?Infrequency
Dianne Hackborne didn't say that it was not possible, just said that you should not do UI from a background thread. Passing around context objects is a heavy thing to do, and can lead to leaks. The accepted answer is the best answer, whereas this answer is a workaround.Balsaminaceous
Why if I move the initialization of the mHandler to onHandleIntent method this code does not work? Why is it have to be declared in the constructor?Selfexecuting
@RezaBigdeli Because default constructor in Handler means connect to current thread. onHandleIntent() runs on bg thread, handler should be initialized in other method. It could onCreate(), for example. See also answer below by Mannaz.Research
L
25

You should start the Toast on the main thread:

new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
        }
});

This is because otherwise the thread of the IntentService quits before the toast can be send out, causing a IllegalStateException:

java.lang.IllegalStateException: Handler (android.os.Handler) {12345678} sending message to a Handler on a dead thread

Laina answered 3/2, 2015 at 22:12 Comment(0)
M
19

onHandleIntent() is called from a background thread (that is what IntentService is all about), so you shouldn't do UI from there.

Mutate answered 18/3, 2011 at 1:26 Comment(1)
That was it, thanks! I created a handler field in onStartCommand() and posted the Toast to the handler and it worked.Amathist
K
3

Another option is RxJava, e.g.:

private void showToast(final String text) {
    Observable.just(text)
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG).show();
            }
        });
}

Caveat: I'm new to Android.

Kagoshima answered 13/1, 2015 at 14:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.