Mobile Development 18 min read

Solving Android Toast Restrictions and Crash Issues

To avoid crashes and missing messages caused by newer Android restrictions on Toast—such as disabled notifications, BadTokenException on pre‑8.0 devices, and token‑null errors on Android 7.1—developers intercept Toast.show with AspectJ, replace it with a custom MToast, handle exceptions, and ultimately migrate to a robust Snackbar‑based notification system.

Meituan Technology Team
Meituan Technology Team
Meituan Technology Team
Solving Android Toast Restrictions and Crash Issues

Toast is a basic notification widget on Android that developers use for quick user feedback. Because it is provided by the system and does not depend on a foreground UI, Google has added restrictions in newer Android versions that can break normal business logic.

Problems encountered :

When the user disables the app’s Show notifications switch, Toast no longer appears.

On Android 7.1.2 (API 25) and below, calling Toast.show() may throw BadTokenException, causing a crash.

Custom windows of type TYPE_TOAST also throw token null is not valid on Android 7.1.1/7.1.2.

Root cause analysis – Toast display is not performed directly by the Toast object. In Toast#show() the framework calls the remote INotificationManager service (NotificationManagerService, NMS) to enqueue the toast. NMS creates a token and passes a tn object back to the app. The app then asks WindowManager to add a window of type TYPE_TOAST using that token. If the notification permission is disabled, NMS rejects the request and the toast is never shown.

Key source snippets:

@Aspect
public class ToastAspect {
    @Pointcut("call(* android.widget.Toast+.show(..))")
    public void toastShow() {}

    @Around("toastShow()")
    public void toastShow(ProceedingJoinPoint point) {
        Toast toast = (Toast) point.getTarget();
        Context context = (Context) ReflectUtils.getValue(toast, "mContext");
        if (Build.VERSION.SDK_INT >= 19 && NotificationManagerCompat.from(context).areNotificationsEnabled()) {
            point.proceed(point.getArgs());
        } else {
            floatToastShow(toast, context);
        }
    }

    private static void floatToastShow(Toast toast, Context context) {
        // replace with custom MToast that does not rely on NMS
        new MToast(context)
            .setDuration(mDuration)
            .setView(mNextView)
            .setGravity(mGravity, mX, mY)
            .setMargin(mHorizontalMargin, mVerticalMargin)
            .show();
    }
}

This AspectJ hook intercepts every Toast.show() call and, when notifications are disabled, replaces the system toast with a custom MToast that creates its own window, bypassing the NMS check.

Handling BadTokenException – The exception is thrown later in the message queue, not at the call site. Android 8.0 catches it internally. For pre‑8.0 devices we introduced a custom ToastHandler that catches the exception in the same way, preventing the crash.

Token‑null issue – Starting with Android 7.1.1 the system requires a valid token for TYPE_TOAST. Our custom MToast cannot obtain this token, so the exception cannot be avoided by simply changing the window type. The only viable path is to stop using TYPE_TOAST altogether.

Alternative solutions explored :

Use WindowManager with overlay types ( TYPE_PHONE, TYPE_APPLICATION_OVERLAY) – requires high‑level permissions and many OEM quirks.

Show a Dialog / DialogFragment / PopupWindow – tightly coupled to an Activity and heavyweight for simple notifications.

Replace Toast with Snackbar – the officially recommended Material Design component, lightweight and flexible.

We chose the Snackbar route and built a custom implementation that supports:

Custom styles, animations, and layout extensions.

Passing a specific parent view, Dialog, or PopupWindow to avoid being covered.

Cross‑page display via a local broadcast mechanism encapsulated in SnackbarHelper.

// Example of broadcasting a message for cross‑page Snackbar
Intent intent = new Intent(ACTION_SHOW_SNACKBAR);
intent.putExtra(EXTRA_MESSAGE, "Operation completed");
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);

// In SnackbarHelper’s receiver
String msg = intent.getStringExtra(EXTRA_MESSAGE);
Snackbar.make(parentView, msg, Snackbar.LENGTH_LONG).show();

With this approach the notification appears even when the user has turned off the system notification switch, and the solution has been adopted widely across Meituan’s Android codebase.

Conclusion – By intercepting Toast calls with AspectJ, providing a custom MToast, handling system exceptions, and finally migrating to a robust Snackbar‑based implementation, we eliminated crashes related to Toast restrictions while preserving user experience.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Mobile DevelopmentAndroidaspectjCrashsnackbartoast
Meituan Technology Team
Written by

Meituan Technology Team

Over 10,000 engineers powering China’s leading lifestyle services e‑commerce platform. Supporting hundreds of millions of consumers, millions of merchants across 2,000+ industries. This is the public channel for the tech teams behind Meituan, Dianping, Meituan Waimai, Meituan Select, and related services.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.