窗体泄露 android.view.WindowLeaked: Activity XxxActivity has leaked window android.widget.PopupWindow$Po
来源:互联网 发布:股票交易系统测试软件 编辑:程序博客网 时间:2024/06/04 08:32
前言
搞项目的时候遇到一个Bug,当ListPopupWindow显示的时候,按返回键就会报标题类似的错误。但是在点击Toolbar的NavigationIcon时(设置了finish的点击事件),却不会报这个窗体溢出的Bug。
Why
首先来了解下这个错误产生的原因(呃,网上说的很清楚了,我就直接复制了):
Android的每一个Activity都有个WindowManager窗体管理器,同样,构建在某个Activity之上的对话框、PopupWindow也有相应的WindowManager窗体管理器。但是它们不能脱离Activity而单独存在着,因为需要Activity的Context,所以当某个Dialog或者某个PopupWindow正在显示的时候我们干掉了承载该Dialog(或PopupWindow)的Activity,就会抛WindowLeaked异常了,因为这个Dialog(或PopupWindow)的WindowManager已经没有谁可以附属了(Context)。
怎么解决
既然问题原因知道了,好的,我解决起来不是很简单么,在Activity的OnDestroy方法里,如果popupWindow显示的话,我让它dismiss掉不就好了。嗯,就是这样,简单!
@Override protected void onDestroy() { super.onDestroy(); if(mMerchantPopupWindow!=null&&mMerchantPopupWindow.isShowing()) mMerchantPopupWindow.dismiss(); mMerchantPopupWindow=null; }
But,我被打脸了,还是报这个异常。
那么好,我在onBackPressed方法中让popup消失总可以了吧,然而,还是不行,还是被打脸了。
How to 办?
怒,仔细分析下。现身吧,柯南。
1.为什么点击toolbar的icon时,不报这个错,同样是finish掉这个页面
搞起,搞起,搞事情,简直!
唔,原来ListPopupWindow里面默认是设置PopupWindow点击外面PopupWindow消失的。
mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch&& !mDropDownAlwaysVisible);
而这两个变量默认是false:
private booleanmDropDownAlwaysVisible=false;private booleanmForceIgnoreOutsideTouch=false;
原来如此,点击icon的时候,popup先dismiss了,然后页面finish掉不会报错。
2.为什么我设置了按返回键后,在页面销毁时让popup消失,却不行呢?
再次搞事情。既然将一个Activity组件的应用程序窗口视图对象与一个ViewRoot对象关联是通过该Activity组件所使用的窗口管理器(WindowManager)来执行的。调用所获得的本地窗口管理器wm(类型为LocalWindowManager)的成员函数addView来执行关联应用程序窗口视图对象和ViewRoot对象的操作。
那么我们就来找一找WindowManager。
找到了!
mWindowManager = mWindow.getWindowManager();
嗯,来看下Window类:
public WindowManager getWindowManager() { return mWindowManager;}mWindowManager=((WindowManagerImpl)wm).createLocalWindowManager(this);
嗯,再来找下WindowManagerImpl:
public final class WindowManagerImpl implements WindowManager { private final WindowManagerGlobalmGlobal=WindowManagerGlobal.getInstance(); public WindowManagerImplcreateLocalWindowManager(WindowparentWindow){ return new WindowManagerImpl(mDisplay,parentWindow);} @Override public void addView(Viewview,ViewGroup.LayoutParamsparams){ mGlobal.addView(view,params,mDisplay,mParentWindow);}
嗯,看起来WindowManagerGlobal的嫌疑很大啊,小伙子,搞事情啊!WindowManagerGlobal#performStop
final void performStop() { .... if(!mStopped) { ... if(mToken!=null&&mParent==null) { WindowManagerGlobal.getInstance().setStoppedState(mToken,true); } ... mInstrumentation.callActivityOnStop(this); ... }}
那么WindowManagerGlobal的setStoppedState又是啥呢?看这里。
public void setStoppedState(IBinder token, boolean stopped) { synchronized (mLock) { int count = mViews.size(); for (int i = 0; i < count; i++) { if (token == null || mParams.get(i).token == token) { ViewRootImpl root = mRoots.get(i); root.setWindowStopped(stopped); } } } }
再来看下ViewRootImpl的setWindowStoped方法:
void setWindowStopped(boolean stopped) { if (mStopped != stopped) { mStopped = stopped; if (!mStopped) { scheduleTraversals(); } } }
ViewRootImpl#mStopped 当Window状态为stoped时为true,代表Window不再活跃。
// Set to true if the owner of this window is in the stopped state, // so the window should no longer be active. boolean mStopped = false;
那么Activity#performStop方法啥时候调用的呢。再来看下前面的WindowManagerGlobal#performStop方法。
看到这句mInstrumentation.callActivityOnStop(this)没?
来看下Instrumentation#callActivityOnStop方法
public void callActivityOnStop(Activity activity) { activity.onStop(); }
也就是说,执行完Activity#performStop方法会调用Activity#OnStop方法。在OnStop之前,performStop()就执行了。
- 窗体泄露 android.view.WindowLeaked: Activity XxxActivity has leaked window android.widget.PopupWindow$Po
- android.view.WindowLeaked的解决办法 has leaked window android.widget.PopupWindow$PopupDecorView
- android.view.WindowLeaked: Activity com.xty.activity.ActivityMainPage has leaked window com.android.
- android.view.WindowLeaked: Activity com.xty.activity.ActivityMainPage has leaked window
- android.view.WindowLeaked: Activity com.android.browser.AddBookmarkPage has leaked window com.androi
- android.view.WindowLeaked: Activity has leaked window com.android.internal.p
- android.view.WindowLeaked: Activity com.gl.travel.CityChooseActivity has leaked window android.widge
- WindowManager: android.view.WindowLeaked: Activity has leaked window com.android.internal.policy.imp
- E/WindowManager: android.view.WindowLeaked: Activity com.xxx.xxx.xxx has leaked window com.android.i
- android.view.WindowLeaked: Activity cn.com.zte.uc.activites.shipTicket.OrderWrite1 has leaked window
- android.view.WindowLeaked:Activity has leaked window DecorView@9a11182[] that was originally added h
- WindowManager: android.view.WindowLeaked: Activity com.XXX.XXX.activity.XXXActivity has lea
- Android 报错android.view.WindowLeaked.....has leaked window com.android.internal.policy.
- android.view.WindowLeaked: Activity com.moreunion.zhenghao.ui.diary.DiaryDetailsActivity has leaked
- [Android开发-异常]xxxActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView
- 问题:Activity has leaked window android.widget.RelativeLayout@407cd588 that was originally added here
- [android窗体泄露]android.view.WindowLeaked的解决方案
- 关于android.view.WindowLeaked(窗体泄露)的解决方案
- 357. Count Numbers with Unique Digits
- 多线程控件讲解
- Servlet学习笔记二
- HTTP 协议入门
- 关于LayoutInflater的总结
- 窗体泄露 android.view.WindowLeaked: Activity XxxActivity has leaked window android.widget.PopupWindow$Po
- Java 数组转List
- 数据存储,实现用户登录界面及记住密码的实现。
- netfilter bug scheduling while atomic: swapper/0/0x10000100
- 2016 版 Laravel 系列入门教程(四)【最适合中国人的 Laravel 教程】
- Android Studio下开发JNI第一步
- 更新Cocoapods时
- 蓝桥杯 四平方和
- Eclipse的部分快捷键