Android M ClassCastException:FrameLayout$LayoutParams 无法转换为 WindowManager$LayoutParams

Posted

技术标签:

【中文标题】Android M ClassCastException:FrameLayout$LayoutParams 无法转换为 WindowManager$LayoutParams【英文标题】:Android M ClassCastException: FrameLayout$LayoutParams cannot be cast to WindowManager$LayoutParams 【发布时间】:2016-07-05 17:33:23 【问题描述】:

这段代码似乎在 android api 16 - 22 中有效,但在 api 23 中无效。我只是想显示一个带有选项的弹出窗口,并使弹出窗口下方的背景变暗:

                WindowPopUp windowPopUp =
                        new WindowPopUp(mContext, mPlaces.get(position), position, fromSearch);
                windowPopUp.showAtLocation(v, Gravity.CENTER, 0, 0);
                View parent = (View) windowPopUp.getContentView().getParent();
                //dim the window in the background
                WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
                WindowManager.LayoutParams p = (WindowManager.LayoutParams) parent.getLayoutParams();
                p.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND;
                p.dimAmount = 0.4f;
                wm.updateViewLayout(parent, p);

运行此代码会导致错误:

                03-18 21:55:19.674 8814-8814/? E/AndroidRuntime: FATAL EXCEPTION: main
                                             Process: com.myapp, PID: 8814
                                             java.lang.ClassCastException: android.widget.FrameLayout$LayoutParams cannot be cast to android.view.WindowManager$LayoutParams
                                                 at com.bemyapp.adapter.OuterPlaceAdapter$5.onLongClick(OuterPlaceAdapter.java:400)
                                                 at android.view.View.performLongClick(View.java:5237)
                                                 at android.view.View$CheckForLongPress.run(View.java:21121)
                                                 at android.os.Handler.handleCallback(Handler.java:739)
                                                 at android.os.Handler.dispatchMessage(Handler.java:95)
                                                 at android.os.Looper.loop(Looper.java:148)
                                                 at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                 at java.lang.reflect.Method.invoke(Native Method)
                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

出了什么问题?

据我所知,WindowManager.LayoutParams 扩展了ViewGroup.LayoutParams,当我调用parent.getLayoutParams() 时,它返回一个ViewGroup.LayoutParams,所以不应该有classCastException

【问题讨论】:

【参考方案1】:

只需再添加一个 .getParent() 即可访问容器。

 if (android.os.Build.VERSION.SDK_INT > 22) 
            container = (View) pwindow.getContentView().getParent().getParent();
        else
            container = (View) pwindow.getContentView().getParent();
        

【讨论】:

【参考方案2】:

有一个类转换异常。您正在将 ViewGroup.LayoutParams 转换为 WindowManager.LayoutParams。如果返回的实际对象是ViewGroup.LayoutParams 的不同子对象的实例(例如FrameLayout.LayoutParams),则强制转换是非法的。在这种情况下,名为 parent 的视图并不直接在窗口中,而是在 FrameLayout 中。所以调用getLayoutParams 会返回FrameLayout.LayoutParams,而不是WindowsManager.LayoutParams

如果它在 22 而不是 23 中工作,则很可能他们改变了在 23 中弹出窗口的完成方式。依赖父弹出窗口直接位于窗口内绝不是一个安全的假设,您的代码总是有风险被操作系统更新破坏。

【讨论】:

添加了一个编辑。基本上,您依赖于他们更改的实现细节。 这是一个可怕的消息。我想我必须将所有弹出窗口更改为 DialogActivity。如果这是真的,弹出窗口不是一个好的设计理念。 也许不适合您的用例,尽管它适用于其他人。您也有可能通过在视图层次结构中向上走直到您点击一个窗口来获得您想要的东西(他们可能刚刚添加了一个框架来处理单个窗口中的多个弹出窗口)。但是他们可能只是更改了它,以便主窗口和弹出窗口都在一个框架中,在这种情况下,这将不起作用。 我在弹出窗口中遇到了类似的问题。你想出解决方案了吗?

以上是关于Android M ClassCastException:FrameLayout$LayoutParams 无法转换为 WindowManager$LayoutParams的主要内容,如果未能解决你的问题,请参考以下文章

android l和android m的区别

android M拨号盘开源之旅--- 初窥M拨号盘

android m预览版SDK下载地址 android m预览版SDK下载网址

低于 M 的 android 版本的 Android 运行时权限?

Android 6(M) 权限问题(创建目录不起作用)

Android : M 与 N 的权限管理