非Activity类创建Dialog触发android.view.WindowManager$BadTokenException问题
WindowManager$BadTokenException When Showing Dialog from Non-Activity Class Hey there! Let's break down why you're hitting this frustrating exception and walk through how to fix it.
What's Causing the Error?
That BadTokenException almost always stems from one of two issues:
- You’re using a non-Activity Context (like
ApplicationContext) to create the dialog. Dialogs need to attach to an Activity’s window, and the app context doesn’t have its own window to bind to. - The target Activity (Activity A in your scenario) isn’t in an active state when you try to show the dialog. When you press back from Activity B, Activity A might be in the middle of lifecycle transitions (like restarting) or could even be marked as finishing.
Step-by-Step Fixes
1. Use a Valid Activity Context
First, make sure when you call ShowDialogBox, you pass Activity A’s instance (using this) instead of any other Context type. Never use getApplicationContext() here—dialogs rely on an Activity’s window to display properly.
2. Check Activity's Active State Before Showing the Dialog
Before triggering the dialog, verify that Activity A is still alive and not finishing. Add this check in Activity A where you call your dialog method:
if (!this.isFinishing() && !this.isDestroyed()) { YourNonActivityClass.ShowDialogBox(this, yourListenerInstance); }
3. Fix the Syntax Error in Your Dialog Code
Looking at your code, there’s a small syntax mistake in the setPositiveButton call that could cause unexpected behavior. Here’s the cleaned-up, corrected version:
public static void ShowDialogBox(final Context con, final Listener list) { // First confirm we're working with an Activity context if (!(con instanceof Activity)) { return; // Exit early if context isn't an Activity } final Activity activity = (Activity) con; // Ensure dialog runs on the main thread (UI operations can't run on background threads) activity.runOnUiThread(new Runnable() { @Override public void run() { AlertDialog.Builder dlgAlert = new AlertDialog.Builder(activity); dlgAlert.setMessage("TEXT"); dlgAlert.setTitle("TEXT"); dlgAlert.setPositiveButton("TEXT", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); // Trigger your listener callback here if needed if (list != null) { // list.onYourListenerMethod(); } } }); dlgAlert.setCancelable(false); AlertDialog dialog = dlgAlert.create(); // Double-check Activity state before showing to avoid exceptions if (!activity.isFinishing() && !activity.isDestroyed()) { dialog.show(); } } }); }
Key improvements here:
- Fixed the misplaced parenthesis in
setPositiveButton - Wrapped dialog creation in
runOnUiThreadto ensure it runs on the main thread (critical for UI operations) - Added checks to confirm the context is an Activity, and that the Activity is still active before showing the dialog
4. Verify Listener Callback Timing
Make sure your listener from Activity B triggers the dialog call after Activity A has resumed. If Activity A is still in onRestart or onStart when the callback hits, it might not be ready to display UI elements. You can post the dialog call to the Activity’s message queue to ensure it runs after the lifecycle is complete:
// In Activity A's listener callback activity.post(new Runnable() { @Override public void run() { if (!activity.isFinishing() && !activity.isDestroyed()) { YourNonActivityClass.ShowDialogBox(activity, yourListener); } } });
Final Notes
Always remember that dialogs are tightly coupled to an Activity’s lifecycle. Any time you show a dialog from outside an Activity, you need to guarantee that the target Activity is in a valid state to display UI.
内容的提问来源于stack exchange,提问作者Rajesh K

