美文网首页
窗体泄露 android.view.WindowLeaked:

窗体泄露 android.view.WindowLeaked:

作者: 柳击歌 | 来源:发表于2017-03-31 18:13 被阅读0次

    前言

    搞项目的时候遇到一个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()就执行了。
    ## 完结撒花
    那么在onStop之前,就onPause了,让popupWindow没消失的消失好啦!以前没仔细注意这个问题,尴尬!

    相关文章

      网友评论

          本文标题:窗体泄露 android.view.WindowLeaked:

          本文链接:https://www.haomeiwen.com/subject/lfbvottx.html