在Android活动中创buildpopup窗口的问题

我正在尝试创build一个只在应用程序第一次启动时出现的popup窗口。 我希望它显示一些文本,并有一个buttonclosurespopup窗口。 但是,我正在麻烦PopupWindow甚至工作。 我尝试了两种不同的方法:

首先,我有一个XML文件,它声明了名为popup.xml的popup窗口的布局(在一个linearlayout中的一个textview),我在主Activity的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,并说“无法添加窗口 – 标记null无效”

我在做什么错了? 我非常新手,请耐心等待。

为了避免BadTokenException,您需要延迟显示popup窗口,直到调用所有生命周期方法( – > activity window is displayed)之后:

  findViewById(R.id.main_page_layout).post(new Runnable() { public void run() { pw.showAtLocation(findViewById(R.id.main_page_layout), Gravity.CENTER, 0, 0); } }); 

Kordzik提供的解决scheme如果连续启动2个活动将不起作用:

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

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

更通用的解决scheme是onAttachedToWindowonDetachedFromWindow

而且也不需要postDelayed(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(); } 

我发现接受的答案不适合我。 我仍然收到错误的令牌错误..所以我只是从一个处理程序的延迟这样的叫runnable ..

 new Handler().postDelayed(new Runnable() { public void run() { showPopup(); } }, 100); 

发生此exception时有两种情况。 一个是由kordzik提到的。 其他情况在这里提到: http : //blackriver.to/2012/08/android-annoying-exception-unable-to-add-window-is-your-activity-running/

确保你处理他们两个

解决方法是将微调模式设置为对话框如下:

 android:spinnerMode="dialog" 

要么

 Spinner(Context context, int mode) tnxs RamallahDroid 

看到这个。

根据用例,对于显示消息的popup窗口types,使用setWindowLayoutType()将popup窗口types设置为TYPE_TOAST可避免此问题,因为此types的popup窗口不依赖于基础活动。

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

我最终使用TYPE_PHONE(因为应用程序恰好有权限SYSTEM_ALERT_WINDOW,否则这将不会工作)。

检查findViewById返回的东西 – 你可能会调用它太早,在布局之前

你也可能想发布logcat输出,以获得例外

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

  public void showPopupProgress (){ new Handler().post(new Runnable() { @Override public void run() { if (getWindow().getDecorView().getWindowVisibility() == View.GONE) { showPopupProgress(); return; } popup.showAtLocation(.....); } }); } 

你可以检查rootview是否有令牌。 您可以从您的活动xml,mRootView中获取定义的父级布局

 if (mRootView != null && mRootView.getWindowToken() != null) { popupWindow.showAtLocation(); } 

如果在另一个PopupWindow中显示PopupWindow,请不要在第一个POP中使用视图,请使用原始父视图。

 pop.showAtLocation(parentView, ... ); 

您可以从pw.showAtLocation方法中指定y偏移来考虑状态栏…