Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does it matter where the Toast is made in Android if the context is the same?

I have a legacy IntentService that attempts to use Toast messages to display error messages.1 I'd like the messages to be displayed, and have added code to get them on the correct thread. The simplest change would be to pass in the constructed Toast object and then display it on the UI thread. However, the Toast only displays if I make it in the posted runnable, not if I pass in a pre-made Toast.

This works:

@Override
protected void onHandleIntent(Intent intent) {
    showToast("Error", Toast.LENGTH_LONG);
}

private void showToast(final String msg, final int duration) {
    new Handler(getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            // Make and show the toast in the posted runnable
            Toast.makeText(getApplicationContext(), msg, duration).show();
        }
    });
}

This doesn't work:

@Override
protected void onHandleIntent(Intent intent) {
    // Make the toast here
    Toast myToast = Toast.makeText(getApplicationContext(), "Error", Toast.LENGTH_LONG);
    showToast(myToast);
}

private void showToast(final Toast toast) {
    new Handler(getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            // Show the toast here
            toast.show();
        }
    });
}

In both cases, the context is the application context, and I didn't see anything in the source that would cause one version to work, but the other not. Instead the latter has the same problems as if the Toast was shown directly in the IntentService: "Handler (android.os.Handler) {...} sending message to a Handler on a dead thread", Toast not disappearing, etc.

Why does the Toast have to be made on the main thread instead of just shown there?

1. Legacy = I don't think displaying error messages in Toasts is great UI, and I don't think services displaying messages to users directly is a good idea, but that's the code I was handed and I'd like to make it this little bit better.

like image 213
blahdiblah Avatar asked Mar 05 '14 01:03

blahdiblah


People also ask

Why does toast need context?

A context is the current state of the application/object. The toast function must have a context to know where it has to show the toast.

What is context in toast in android?

For toasts, which are short-lived, you can usually use whatever context you want. Typically, you would use the activity context, but application context is fine as well.

How do you change the position of a toast message?

Positioning your Toast A standard toast notification appears near the bottom of the screen, centered horizontally. You can change this position with the setGravity(int, int, int) method. This accepts three parameters: a Gravity constant, an x-position offset, and a y-position offset.

How do you avoid a toast if there's one toast already being shown?

Starting from Android Build. VERSION_CODES#R, apps targeting API level Build. VERSION_CODES#R or higher that are in the background will not have custom toast views displayed. If you want to avoid Toast overlapping, you could save the time the last Toast was shown using System.


1 Answers

In the second code that you've posted, the Toast is created in the background thread which has a looper and handler set up (that is the point of IntentService).

The toast uses the current thread's looper to create a handler, but once the IntentService is finished processing the work in onHandleIntent it stops itself (if there aren't other intents to process) - destroying the thread that your Toast's handler is relying on.

line 327: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/widget/Toast.java

Making the toast in the runnable works because at that point, the current thread is the UI thread.

like image 191
FunkTheMonk Avatar answered Sep 26 '22 15:09

FunkTheMonk