代码之家  ›  专栏  ›  技术社区  ›  Amplify91

在Android活动中创建弹出窗口时出现问题

  •  51
  • Amplify91  · 技术社区  · 16 年前

    我试图创建一个弹出窗口,它只在应用程序第一次启动时出现。我希望它显示一些文本,并有一个按钮关闭弹出窗口。但是,我在让弹出窗口工作时遇到了麻烦。我尝试过两种不同的方法:

    首先,我有一个XML文件,它声明了名为popup.xml的弹出窗口布局(linearlayout中的一个textView),并将其添加到我的主活动的onCreate()中:

    PopupWindow pw = new PopupWindow(findViewById(R.id.popup), 100, 100, true);
        pw.showAtLocation(findViewById(R.id.main), Gravity.CENTER, 0, 0);
    

    其次,我对这段代码也做了同样的处理:

    final LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        PopupWindow pw = new PopupWindow(inflater.inflate(R.layout.popup, (ViewGroup) findViewById(R.layout.main) ), 100, 100, true);
        pw.showAtLocation(findViewById(R.id.main_page_layout), Gravity.CENTER, 0, 0);
    

    第一个引发NullPointerException,第二个引发BadTokenException,并说“无法添加窗口--令牌空值无效”

    我到底做错了什么?我是一个非常新手,所以请容忍我。

    13 回复  |  直到 7 年前
        1
  •  174
  •   kordzik    15 年前

    为避免BadTokenException,需要将弹出窗口的显示推迟到调用所有生命周期方法之后(显示-gt;活动窗口):

     findViewById(R.id.main_page_layout).post(new Runnable() {
       public void run() {
         pw.showAtLocation(findViewById(R.id.main_page_layout), Gravity.CENTER, 0, 0);
       }
    });
    
        2
  •  28
  •   Danylo Volokh    10 年前

    如果您连续启动两个活动,Kordzik提供的解决方案将不起作用:

    startActivity(ActivityWithPopup.class);
    startActivity(ActivityThatShouldBeAboveTheActivivtyWithPopup.class);
    

    如果在这种情况下以这种方式添加弹出窗口,您将获得相同的崩溃,因为在这种情况下,ActivityWithPopup不会附加到窗口。

    更普遍的溶解是 已连接到Window 和 从窗口分离 .

    而且也不需要延迟(runnable,100)。因为这100毫不能保证任何事情

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        Log.d(TAG, "onAttachedToWindow");
    
        showPopup();
    }
    
    @Override
    public void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        Log.d(TAG, "onDetachedFromWindow");
    
        popup.dismiss();
    }
    
        3
  •  17
  •   Johnny Five Jamol    7 年前

    这个公认的回答对我不起作用。我仍然收到BadTokenException。所以我只是从一个延迟的处理程序调用runnable,比如:

    new Handler().postDelayed(new Runnable() {
        public void run() {
            showPopup();
        }
    }, 100);
    
        4
  •  6
  •   bipin    8 年前

    使用类上下文,例如mainActivity.This而不是getApplicationContext()。

        5
  •  4
  •   TheMan    13 年前

    有两种情况会发生此异常。Kordzik提到了一个。这里还提到了其他情况: http://blackriver.to/2012/08/android-annoying-exception-unable-to-add-window-is-your-activity-running/

    一定要处理好这两个问题

        6
  •  3
  •   Community Mohan Dere    9 年前

    解决方案是将微调器模式设置为对话框,如下所示:

    android:spinnerMode="dialog"
    

    或

    Spinner(Context context, int mode)
    tnxs RamallahDroid
    

    See This.

        7
  •  1
  •   headuck    10 年前

    根据用例的不同,对于要显示消息的弹出类型,将弹出类型设置为“toast”类型,使用 setWindowLayoutType() 避免此问题,因为此类型的弹出窗口不依赖于基础活动。

    编辑:一个副作用:在api<=18的弹出窗口中没有交互,因为系统将删除可触摸/可聚焦事件。( http://www.jianshu.com/p/634cd056b90c )

    我最终使用的是type_phone(因为应用程序刚好有权限系统_alert_窗口,否则这也不会起作用)。

        8
  •  1
  •   Cheng    10 年前

    您可以检查rootview是否有令牌。您可以从活动XML、mrootView中定义父布局。

    if (mRootView != null && mRootView.getWindowToken() != null) {
        popupWindow.showAtLocation();
    }
    
        9
  •  0
  •   Asahi    16 年前

    检查那个 findViewById 返回某些内容-在构建布局之前,您可能过早地调用它

    此外,您可能还需要为正在获取的异常发布logcat输出

        10
  •  0
  •   Roman Nazarevych    11 年前

    您也可以尝试使用此检查:

      public void showPopupProgress (){
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                if (getWindow().getDecorView().getWindowVisibility() == View.GONE) {
                    showPopupProgress();
                    return;
                }
                popup.showAtLocation(.....);
            }
        });
    }
    
        11
  •  0
  •   YanXing Ou    10 年前

    如果在另一个弹出窗口中显示弹出窗口,请不要在第一个弹出窗口中使用该视图,请使用源站父视图。

    pop.showAtLocation(parentView, ... );
    
        12
  •  0
  •   Maria    8 年前

    我在上的AlertDialog中遇到了同样的问题(BadTokenException) dialog.show() . 我正在通过下面的一些例子进行警报对话。在我的例子中,这个问题的原因是一个字符串 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST)

    我把它取下来后,一切都开始工作了。

        13
  •  -1
  •   cipherz    15 年前

    您可以从 PW.显示位置 方法…