代码之家  ›  专栏  ›  技术社区  ›  Rajesh K

安卓看法WindowManager$BadTokenException创建对话框时出错

  •  1
  • Rajesh K  · 技术社区  · 8 年前

    我正在尝试从非活动类创建一个对话框。

    这是我的密码

      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
        }
    

    这就是我遇到的错误

    安卓看法WindowManager$BadTokenException:位于 安卓看法ViewRootImpl。setView(ViewRootImpl.java:574)位于 安卓看法WindowManagerGlobal。添加视图 (WindowManagerGlobal.java:282)位于 安卓看法WindowManagerImpl。addView(WindowManagerImpl.java:85)
    在android上。应用程序。对话显示(Dialog.java:298) 包名称和类 包名称和类位于 包名称和类 包名称和类位于 包名称和类。反压时 (java类:95)在android上。应用程序。活动onKeyUp (Activity.java:2465)在android上。看法关键事件。派遣 (KeyEvent.java:2646)在android上。应用程序。活动dispatchKeyEvent调度键事件 (Activity.java:2716)位于 安卓支持v7。内部的看法WindowCallbackWrapper。dispatchKeyEvent调度键事件 (WindowCallbackWrapper.java:50)位于 安卓支持v7。应用程序。AppCompatDelegateImplBase$AppCompatWindowCallbackBase。dispatchKeyEvent调度键事件 (appcompatedelegateimplbase.java:224)位于 com。安卓内部的政策实施。PhoneWindow$DecorView。dispatchKeyEvent调度键事件 (PhoneWindow.java:2280)位于 安卓看法ViewRootImpl$ViewPostImeInputStage。processKeyEvent进程键事件 (ViewRootImpl.java:4038)位于 安卓看法ViewRootImpl$ViewPostImeInputStage。onProcess公司 (ViewRootImpl.java:4000)位于 安卓看法ViewRootImpl$InputStage。交付(ViewRootImpl.java:3562) 在android上。看法ViewRootImpl$InputStage。OnDelivertonNext (ViewRootImpl.java:3615)位于 安卓看法ViewRootImpl$InputStage。转发(ViewRootImpl.java:3581) 在android上。看法ViewRootImpl$AsyncInputStage。向前地 (ViewRootImpl.java:3698)位于 安卓看法ViewRootImpl$InputStage。应用(ViewRootImpl.java:3589)
    在android上。看法ViewRootImpl$AsyncInputStage。申请 (ViewRootImpl.java:3755)位于 安卓看法ViewRootImpl$InputStage。交付(ViewRootImpl.java:3562) 在android上。看法ViewRootImpl$InputStage。OnDelivertonNext (ViewRootImpl.java:3615)位于 安卓看法ViewRootImpl$InputStage。转发(ViewRootImpl.java:3581) 在android上。看法ViewRootImpl$InputStage。应用(ViewRootImpl.java:3589) 在android上。看法ViewRootImpl$InputStage。传送 (ViewRootImpl.java:3562)位于 安卓看法ViewRootImpl$InputStage。OnDelivertonNext (ViewRootImpl.java:3615)位于 安卓看法ViewRootImpl$InputStage。转发(ViewRootImpl.java:3581) 在android上。看法ViewRootImpl$AsyncInputStage。向前地 (ViewRootImpl.java:3731)位于 安卓看法ViewRootImpl$IMInputStage。onFinishedInputEvent (ViewRootImpl.java:3892)位于 安卓看法inputmethod。InputMethodManager$PendingEvent。跑 (InputMethodManager.java:2208)位于 安卓看法inputmethod。InputMethodManager。invokeFinishedInputEventCallback (InputMethodManager.java:1849)位于 安卓看法inputmethod。InputMethodManager。finishedInputEvent完成 (InputMethodManager.java:1840)位于 安卓看法inputmethod。InputMethodManager$IMInputEventSender。onInputEventFinished (InputMethodManager.java:2185)位于 安卓看法InputEventSender。dispatchInputEventFinished调度输入事件已完成 (InputEventSender.java:141)位于 安卓操作系统。MessageQueue。nativePollOnce(本机方法)位于 安卓操作系统。MessageQueue。下一步(MessageQueue.java:143)位于 安卓操作系统。活套。循环(Looper.java:122) 安卓应用程序。ActivityThread。main(ActivityThread.java:5254)位于 JAVAlang.reflect。方法调用(本机方法) JAVAlang.reflect。方法调用(方法java:372) com。安卓内部的操作系统。ZygoteInit$MethodandArgscaler。跑 (ZygoteInit.java:902)位于com。安卓内部的操作系统。合子岩。主要的 (ZygoteInit.java:697)

    下面是用户的场景

    活动A-->打开活动B-->用户在活动B中按下后退按钮-->按下后退按钮后,侦听器将被发送到活动a-->然后调用显示的对话框。

    3 回复  |  直到 8 年前
        1
  •  1
  •   Barns    8 年前

    您在尝试构建 AlertDialog 在另一节课上,你通过了 对话框 这个 Context 您的 Activity 。由于 对话框 需要 WindowManager 从 活动 它有布局,而不是 上下文 .这是因为 Activit 扩展 上下文 。。。而不是相反。

    为了使代码正常工作,您需要提供 AlertDialog.Builder 访问 活动 。因此,请将代码更改为以下内容:

    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();
        }
    }
    

    现在您可以调用 对话框 来自 活动 在这种情况下 MainActivity 像这样:

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

    我还没有试过 Fragment ,所以我不知道从 碎片 或者您是否会继续使用某些设备。出于这些原因,我(和谷歌!)仍然强烈建议您使用 DialogFragment 相反,因为is是专为此场景设计的。看看谷歌文档:

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

        2
  •  1
  •   Barns    8 年前

    我通常更喜欢使用 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();
        }
    }
    

    它包含一个 Listener 以防万一您需要在 对话框片段 已完成。

    首先,您需要实现回调: implements AlertDialogFragment.AlertFinishedDialogListener{

    为了调用 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");
    }
    
        3
  •  1
  •   Khemraj Sharma    8 年前

    问题

    只能从活动上下文显示对话框。 除了 TYPE_SYSTEM_ALERT 或 TYPE_APPLICATION_OVERLAY ,如果您的应用程序未向用户显示紧急通知,则不建议这样做。

    解决方案

    如果您有可用的活动上下文,则可以从任何类显示对话框,如 service ,则, broadcast receiver ,甚至任何你想象的阶级。

    这是我的变通方法,可以像我说的那样显示来自任何类的对话框。

    下面是一个片段,我是如何显示来自任何类的对话框的。( 可以吗 更简单一点! )

    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
                }
            });
        }
    }
    

    现在,您将实现这一点。

    1、生成将在android清单应用程序标记中注册的应用程序类

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

    2、在此应用程序类中,您将持有live activity对象。这对于显示对话框更有用。

    应用程序上下文。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;
        }
    }
    

    再多走一步

    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);
        }
    }
    

    给你!!!