简体   繁体   English

创建对话框时出现android.view.WindowManager $ BadTokenException错误

[英]android.view.WindowManager$BadTokenException error while creating dialog box

I am trying to create a Dialog Box from an Non activity Class. 我正在尝试从非活动类创建一个对话框。

This is my Code 这是我的代码

  public static void ShowDialogBox(final Context con, final Listener list) {
        AlertDialog.Builder dlgAlert = new AlertDialog.Builder(con);
        dlgAlert.setMessage("TEXT");
        dlgAlert.setTitle("TEXT");
        dlgAlert.setPositiveButton("TEXT"),
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {

                    }
                });
        dlgAlert.setCancelable(false);
        dlgAlert.create().show(); // THIS LINE GIVES ME AN ERROR
    }

This is the error which I am getting 这是我得到的错误

android.view.WindowManager$BadTokenException: at android.view.ViewRootImpl.setView (ViewRootImpl.java:574) at android.view.WindowManagerGlobal.addView (WindowManagerGlobal.java:282) at android.view.WindowManagerImpl.addView (WindowManagerImpl.java:85) android.view.WindowManager $ BadTokenException:在Android.view.WindowManagerImpl.addView(WindowManagerImpl.java)的android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:282)的android.view.ViewRootImpl.setView(ViewRootImpl.java:574) :85)
at android.app.Dialog.show (Dialog.java:298) at PACKAGE NAME AND CLASS PACKAGE NAME AND CLASS at PACKAGE NAME AND CLASS PACKAGE NAME AND CLASS at PACKAGE NAME AND CLASS.onBackPressed (Class.java:95) at android.app.Activity.onKeyUp (Activity.java:2465) at android.view.KeyEvent.dispatch (KeyEvent.java:2646) at android.app.Activity.dispatchKeyEvent (Activity.java:2716) at android.support.v7.internal.view.WindowCallbackWrapper.dispatchKeyEvent (WindowCallbackWrapper.java:50) at android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.dispatchKeyEvent (AppCompatDelegateImplBase.java:224) at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent (PhoneWindow.java:2280) at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent (ViewRootImpl.java:4038) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess (ViewRootImpl.java:4000) at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562) at android.view.ViewRootImpl$InputStage. 在android.app.Dialog.show(Dialog.java:298)在包装名称和类包装名称和类包装名称和类包装名称和类别在包装名称和CLASS.onBackPressed(Class.java:95)在android。 app.Activity.onKeyUp(Activity.java:2465)在android.view.KeyEvent.dispatch(KeyEvent.java:2646)的android.app.Activity.dispatchKeyEvent(Activity.java:2716)android.support.v7.internal .view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrapper.java:50)at android.support.v7.app.AppCompatDelegateImplBase $ AppCompatWindowCallbackBase.dispatchKeyEvent(AppCompatDelegateImplBase.java:224)at com.android.internal.policy.impl.PhoneWindow $ DecorView.dispatchKeyEvent (PhoneWindow.java:2280)android.view.ViewRootImpl $ ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:4038)android.view.ViewRootImpl $ ViewPostImeInputStage.onProcess(ViewRootImpl.java:4000)at android.view.ViewRootImpl $ InputStage。在android.view.ViewRootImpl $ InputStage中传递(ViewRootImpl.java:3562)。 onDeliverToNext (ViewRootImpl.java:3615) at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581) at android.view.ViewRootImpl$AsyncInputStage.forward (ViewRootImpl.java:3698) at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3589) onDeliverToNext(ViewRootImpl.java:3615)在android.view.ViewRootImpl $ InputStage.forward(ViewRootImpl.java:3581)android.view.ViewRootImpl $ AsyncInputStage.forward(ViewRootImpl.java:3698)at android.view.ViewRootImpl $ InputStage .apply(ViewRootImpl.java:3589)
at android.view.ViewRootImpl$AsyncInputStage.apply (ViewRootImpl.java:3755) at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562) at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:3615) at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581) at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3589) at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562) at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:3615) at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581) at android.view.ViewRootImpl$AsyncInputStage.forward (ViewRootImpl.java:3731) at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent (ViewRootImpl.java:3892) at android.view.inputmethod.InputMethodManager$PendingEvent.run (InputMethodManager.java:2208) at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback (InputMethodManager.java:1849) at android.view.inputmetho 在android.view.ViewRootImpl $ AsyncInputStage.apply(ViewRootImpl.java:3755)android.view.ViewRootImpl $ InputStage.deliver(ViewRootImpl.java:3562)at android.view.ViewRootImpl $ InputStage.onDeliverToNext(ViewRootImpl.java:3615) )android.view.ViewRootImpl $ InputStage.forward(ViewRootImpl.java:3581)android.view.ViewRootImpl $ InputStage.apply(ViewRootImpl.java:3589)at android.view.ViewRootImpl $ InputStage.deliver(ViewRootImpl.java: 3562)在android.view.ViewRootImpl $ InputStage.onDeliverToNext(ViewRootImpl.java:3615)android.view.ViewRootImpl $ InputStage.forward(ViewRootImpl.java:3581)at android.view.ViewRootImpl $ AsyncInputStage.forward(ViewRootImpl.java) :3731)在android.view.inputmethod.InputMethodManager $ PendingEvent.run(InputMethodManager.java:2208)android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback的android.view.ViewRootImpl $ ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:3892) InputMethodManager.java:1849)在android.view.inputmetho d.InputMethodManager.finishedInputEvent (InputMethodManager.java:1840) at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished (InputMethodManager.java:2185) at android.view.InputEventSender.dispatchInputEventFinished (InputEventSender.java:141) at android.os.MessageQueue.nativePollOnce (Native Method) at android.os.MessageQueue.next (MessageQueue.java:143) at android.os.Looper.loop (Looper.java:122) at android.app.ActivityThread.main (ActivityThread.java:5254) at java.lang.reflect.Method.invoke (Native Method) at java.lang.reflect.Method.invoke (Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:902) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:697) d.InputMethodManager.finishedInputEvent(InputMethodManager.java:1840)at android.view.inputmethod.InputMethodManager $ ImeInputEventSender.onInputEventFinished(InputMethodManager.java:2185)at android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:141)at android.os .MessageQueue.nativePollOnce(Native Method)在android.app.AessT.Thread.main上的android.os.MessageQueue.next(MessageQueue.java:143)android.app.Looper.loop(Looper.java:122)。(ActivityThread.java) :5254)at java.lang.reflect.Method.invoke(Native Method)at java.lang.reflect.Method.invoke(Method.java:372)at com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit) .java:902)在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:697)

Here is the scenario of the user 这是用户的场景

Activity A -->Opens Activity B-->User presses Back button in Activity B--> On Back button pressed a listener is sent to Activity A --> And then the Dialog Box shown is called. 活动A - >打开活动B - >用户按下活动B中的后退按钮 - >返回按钮按下一个监听器被发送到活动A - >然后调用显示的对话框。

I generally prefer using DialogFragment instead of what you attempted in order to cut down on repetition. 我通常更喜欢使用DialogFragment代替您尝试的内容以减少重复。 Here is an example of a DialogFragment with a custom layout which I have called R.layout.fragment_alert_dialog : 这是一个带有自定义布局的DialogFragment示例,我将其命名为R.layout.fragment_alert_dialog

public class AlertDialogFragment extends DialogFragment {

    private static final String ARG_TITLE = "title";
    private static final String ARG_MESSAGE = "message";

    private String title;
    private String message;
    boolean endSuccess = false;

    private AlertFinishedDialogListener mListener;

    public AlertDialogFragment() {
    }

    public static AlertDialogFragment newInstance(String title, String message) {
        AlertDialogFragment fragment = new AlertDialogFragment();
        Bundle args = new Bundle();
        args.putString(ARG_TITLE, title);
        args.putString(ARG_MESSAGE, message);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            title = getArguments().getString(ARG_TITLE);
            message = getArguments().getString(ARG_MESSAGE);
        }
    }

    @Override
    public Dialog onCreateDialog(Bundle saveIntsanceState){

        final Context context = getActivity();

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

        LayoutInflater inflater = getActivity().getLayoutInflater();

        View rootView = inflater.inflate(R.layout.fragment_alert_dialog, null, false);
        final TextView titleView = (TextView)rootView.findViewById(R.id.tvTitle);
        final TextView messView = (TextView)rootView.findViewById(R.id.tvMessage);

        titleView.setText(title);
        messView.setText(message);

        builder.setView(rootView)
//                .setTitle(title)
                .setPositiveButton(R.string.ok_button_dialog_title, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                        endSuccess = true;
                        if(mListener == null) mListener = (AlertFinishedDialogListener) context;
                        mListener.onAlertFinishedDialog();
                    }
                });
        return builder.create();
    }


    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            if(mListener == null) mListener = (AlertFinishedDialogListener) context;
        }
        catch (Exception ex){
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    public interface AlertFinishedDialogListener {
        void onAlertFinishedDialog();
    }
}

It incorporates a Listener just in case you need to be notified when the DialogFragment is completed. 它包含一个Listener ,以防您在DialogFragment完成时需要得到通知。

First you need to implement the callback: implements AlertDialogFragment.AlertFinishedDialogListener{ 首先,您需要实现回调: implements AlertDialogFragment.AlertFinishedDialogListener{

In order to call the AlertDialogFragment you do this from your Activity (also Fragment if necessary). 为了调用AlertDialogFragment您可以从Activity (也可以是Fragment如果需要)执行此操作。

private void startAlertDialogFragment(String title, String mess){
    AlertDialogFragment alert = AlertDialogFragment.newInstance(title, mess);
    alert.show(getFragmentManager(), "alertDialogFragment132");
}

@Override
public void onAlertFinishedDialog() {
    Log.e(TAG, "onAlertFinishedDialog");
}

Problem 问题

You can show dialogs from activity context only. 您只能从活动上下文显示对话框。 except TYPE_SYSTEM_ALERT or TYPE_APPLICATION_OVERLAY , which is not recommended if your app does not show emergency notifications to user. TYPE_SYSTEM_ALERTTYPE_APPLICATION_OVERLAY外 ,如果您的应用未向用户显示紧急通知,则不建议使用此类型。

Solution

If you have activity context available then you can show dialog from any class like service , broadcast receiver , or even any class you imagine. 如果您有活动上下文,那么您可以显示任何类的对话框,如servicebroadcast receiver ,甚至您想象的任何类。

Here is my workaround that can show dialog from any class like i said. 这是我的解决方法,可以显示任何类的对话,就像我说的那样。

Here is a snippet what i do to show dialog from any class. 这是一个片段,我用来显示任何类的对话框。 ( Could it be more simpler! ) 它会更简单!

import android.app.Dialog;
import android.content.DialogInterface;

public class SampleClass {
    void anyMethod() {
        Dialog dialog = ApplicationContext.getInstance().showDialog("title", "yourMessage", "Cancel", "Ok", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO: handle button 1 clicked 
            }
        }, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO: handle button 2 clicked
            }
        });
    }
}

Now you will implement to make this work. 现在你将实现这项工作。

1. make application class which you will register in android manifest application tag 1.制作你将在android manifest应用程序标签中注册的应用程序类

  <application
    android:name=".ApplicationContext"
    ...
    >
      ...
  </application>

2. In this application class you will hold live activity object. 2.在此应用程序类中,您将保存实时活动对象。 that will further useful for showing dialog. 这将对显示对话框更有用。

ApplicationContext.java ApplicationContext.java

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Application;
import android.content.DialogInterface;


public class ApplicationContext extends Application {
    private static ApplicationContext mInstance;
    private Activity liveActivity;

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }

    @Override
    public void onTerminate() {
        super.onTerminate();
        mInstance = null;
    }

    public static synchronized ApplicationContext getInstance() {
        return mInstance;
    }

    public Activity getLiveActivity() {
        return liveActivity;
    }

    public void setLiveActivity(Activity liveActivity) {
        this.liveActivity = liveActivity;
    }

    /*
     * Show Dialog with Title, Message, Button1, Button2 with Button1 and Button2 Listener
     */
    public AlertDialog showDialog(String title, String msg,
                                  String btn1, String btn2,
                                  DialogInterface.OnClickListener listener1,
                                  DialogInterface.OnClickListener listener2) {
        if (liveActivity == null) return null;
        AlertDialog.Builder builder = new AlertDialog.Builder(liveActivity)
                .setTitle(title)
                .setMessage(msg)
                .setCancelable(false)
                .setPositiveButton(btn1, listener1);
        if (btn2 != null)
            builder.setNegativeButton(btn2, listener2);

        AlertDialog alert = builder.create();
        alert.show();
        return alert;
    }
}

Just one more step 再多一步

3. You will extend all your activity by this base activity class (You can edit your base activity if you already have one.) 3.您将通过此基本活动类扩展您的所有活动(如果已有基本活动,则可以编辑基本活动。)

import android.support.v7.app.AppCompatActivity;

public class BaseActivity extends AppCompatActivity {
    @Override
    protected void onResume() {
        super.onResume();
        ApplicationContext.getInstance().setLiveActivity(this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        ApplicationContext.getInstance().setLiveActivity(null);
    }
}

Here you go !!! 干得好 !!!

The issue you are having with the attempt to build your AlertDialog in a separate class is you are passing the AlertDialog the Context of your Activity . 你与尝试建立你遇到的问题AlertDialog在一个单独的类是要传递AlertDialogContext您的Activity You get the error because the AlertDialog requires the WindowManager from the Activity which has the layout--not the Context . 您得到错误,因为AlertDialog需要来自具有布局的ActivityWindowManager ,而不是Context This is because Activit extends Context ... not the other way around. 这是因为Activit扩展了Context ......而不是相反。

In order to make your code work you need to provide the AlertDialog.Builder access to the Activity . 为了使您的代码工作,您需要提供AlertDialog.Builder访问Activity So change your code to something like this: 所以将代码更改为以下内容:

public class TestDialog {

    private static final String TAG = TestDialog.class.getSimpleName();

    Activity mActivity;

    public TestDialog(Activity activity){
        mActivity = activity;
    }


    public void showDialog(){
        AlertDialog.Builder b = new AlertDialog.Builder(mActivity);
        b.setTitle("Title");
        b.setMessage("message");
        b.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Log.e(TAG, "showDialog : onClick");
            }
        });
        b.create().show();
    }
}

Now you can call the AlertDialog from an Activity lets say in this case MainActivity like this: 现在你可以从一个Activity调用AlertDialog ,在这种情况下可以说MainActivity如下:

TestDialog testDialog = new TestDialog(MainActivity.this);
testDialog.showDialog();

I have not tried this from a Fragment , so I do not know whether this works from a Fragment or whether you will continue to have issues with certain devices. 我没有从Fragment尝试这个,所以我不知道这是否可以从Fragment或者您是否会继续遇到某些设备的问题。 For those reasons, I (and Google!) still strongly suggest that you use the DialogFragment instead, because is has been especially designed for this scenario. 出于这些原因,我(和Google!)仍然强烈建议您使用DialogFragment ,因为它是专为此方案设计的。 Take a look at the Google Docs.: 看看Google文档:

https://developer.android.com/guide/topics/ui/dialogs https://developer.android.com/guide/topics/ui/dialogs

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 具有活动的简单对话框错误-android.view.WindowManager $ BadTokenException - Simple dialog error with activity - android.view.WindowManager$BadTokenException 显示PopOver时出现android.view.WindowManager $ BadTokenException - android.view.WindowManager$BadTokenException while showing PopOver Logcat 错误和应用程序不断崩溃与 android.view.WindowManager$BadTokenException? - Logcat error and app keeps crashing with android.view.WindowManager$BadTokenException? android.view.WindowManager$BadTokenException[如何修复] - android.view.WindowManager$BadTokenException[How To Fix] android.view.WindowManager $ BadTokenException:无法在自定义对话框打开时添加窗口 - android.view.WindowManager$BadTokenException: Unable to add window on custom Dialog opening Java android android.view.WindowManager $ BadTokenException:无法添加窗口 - Java android android.view.WindowManager$BadTokenException: Unable to add window react-native:android.view.WindowManager $ BadTokenException - react-native: android.view.WindowManager$BadTokenException 错误:android.view.WindowManager$BadTokenException:无法添加 window — 令牌 null 无效; 您的活动正在运行吗? - ERROR: android.view.WindowManager$BadTokenException: Unable to add window — token null is not valid; is your activity running? android.view.WindowManager $ BadTokenException:无法添加窗口 - 令牌null无效 - android.view.WindowManager$BadTokenException: Unable to add window — token null is not valid android.view.WindowManager $ BadTokenException:无法添加窗口,您的活动正在运行吗? - android.view.WindowManager$BadTokenException: Unable to add window, is your activity running?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM