[Android 小记] PopupWindow中放置Spinner 点击直接闪退的问题分析


错误原因:android.view.WindowManager$BadTokenException: Unable to add window -- token android.view.ViewRootImpl$W@5ec06ba is not valid; is your activity running?

Spinner有个可以设置Item弹出的样式的属性:android:spinnerMode="dialog" 如果设置成“dropDown” (默认) 会直接闪退

“dialog”和“dropDown” 有什么不同的地方?

查看源码寻找spinnerMode 用到的地方,发现构造方法有个int mode的参数。

参看构造方法的最终实现

public Spinner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes, int mode,Theme popupTheme)

/** * 

* @param mode Constant describing how the user will select choices from * the spinner. 

* @see #MODE_DIALOG 

* @see #MODE_DROPDOWN 

*/

mode的默认值是MODE_THEME 即样式为MODE_DIALOG 。

[Android 小记] PopupWindow中放置Spinner 点击直接闪退的问题分析_第1张图片

总结:

    通过对以上源码的分析,发现SpinnerMode有两种dialogDialogPopup,当SpinnerMode为dialog时,Spinner内部选择用一个DialogPopup来显示下拉列表内容;当SpinnerMode为dropDown时,Spinner选择用一个DropdownPopup来显示下拉列表内容

    再次对比DialogPopupDropdownPopup的区别


[Android 小记] PopupWindow中放置Spinner 点击直接闪退的问题分析_第2张图片
[Android 小记] PopupWindow中放置Spinner 点击直接闪退的问题分析_第3张图片

发现,DialogPopup用的是dialog去显示item的,DropdownPopup用的是popwindow显示item。所以问题变成为在popwindow中嵌套使用dialog没有问题,而popwindow嵌套使用popwindow就会报错。关于PopupWindow、Dialog窗口添加机制的不同之处推荐阅读Android 窗口添加机制系列2-Dialog,PopupWindow,Toast。

总结如下:

PopupWindow

PopupWindow本身依附的WindowToken实际上是也是Activity所依附的WindowToken,这也就是说PopupWindow与Activity所使用的WindowToken是一致的。

PopupWindow内部不能再使用PopupWindow是因为它获取不到父PopupWindow的WindowToke,从这里我们也可以分析出,一个视图内部不能嵌套与之平级的视图。

Dialog

Dialog在初始化视图时,在获取到Activity的WindowToken后,会重新new一个Window,它与Activity分属于不同的Window。

所以就不会报出WindowManager 获取不到当前activity没有running的问题。

解决方案有以下方式:

1.直接将SpinnerMode修改为dialog。但是这样会变成在PopupWinow上弹出一个Dialog,影响美观

2.将PopupWindow替换为Dialog,dialog上使用PopupWindow
3.将PopupWindow换为Activity,可能不适用于就是只想弹窗显示

4.使用自定义组件实现类Spinner效果。比如点击显示一个layout,里面放置textview。

你可能感兴趣的:([Android 小记] PopupWindow中放置Spinner 点击直接闪退的问题分析)