错误原因: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 。
总结:
通过对以上源码的分析,发现SpinnerMode有两种dialog和DialogPopup,当SpinnerMode为dialog时,Spinner内部选择用一个DialogPopup来显示下拉列表内容;当SpinnerMode为dropDown时,Spinner选择用一个DropdownPopup来显示下拉列表内容
再次对比DialogPopup与DropdownPopup的区别
发现,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。