窗體泄露 android.view.WindowLeaked: Activity XxxActivity has leaked window android.widget.PopupWindow...

前言

搞項目的時候遇到一個Bug纳本,當(dāng)ListPopupWindow顯示的時候开镣,按返回鍵就會報標(biāo)題類似的錯誤。但是在點(diǎn)擊Toolbar的NavigationIcon時(設(shè)置了finish的點(diǎn)擊事件)郊艘,卻不會報這個窗體溢出的Bug谐鼎。

Why

首先來了解下這個錯誤產(chǎn)生的原因(呃,網(wǎng)上說的很清楚了段只,我就直接復(fù)制了):

Android的每一個Activity都有個WindowManager窗體管理器腮猖,同樣,構(gòu)建在某個Activity之上的對話框赞枕、PopupWindow也有相應(yīng)的WindowManager窗體管理器澈缺。但是它們不能脫離Activity而單獨(dú)存在著,因為需要Activity的Context炕婶,所以當(dāng)某個Dialog或者某個PopupWindow正在顯示的時候我們干掉了承載該Dialog(或PopupWindow)的Activity姐赡,就會拋WindowLeaked異常了,因為這個Dialog(或PopupWindow)的WindowManager已經(jīng)沒有誰可以附屬了(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 辦?

怒费什,仔細(xì)分析下〖鼗郑現(xiàn)身吧手素,柯南。
1.為什么點(diǎn)擊toolbar的icon時瘩蚪,不報這個錯泉懦,同樣是finish掉這個頁面
搞起,搞起疹瘦,搞事情崩哩,簡直!
唔言沐,原來ListPopupWindow里面默認(rèn)是設(shè)置PopupWindow點(diǎn)擊外面PopupWindow消失的邓嘹。

mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch&& !mDropDownAlwaysVisible);

而這兩個變量默認(rèn)是false:

private booleanmDropDownAlwaysVisible=false;
private booleanmForceIgnoreOutsideTouch=false;

原來如此,點(diǎn)擊icon的時候险胰,popup先dismiss了汹押,然后頁面finish掉不會報錯。
2.為什么我設(shè)置了按返回鍵后起便,在頁面銷毀時讓popup消失棚贾,卻不行呢?
再次搞事情榆综。既然將一個Activity組件的應(yīng)用程序窗口視圖對象與一個ViewRoot對象關(guān)聯(lián)是通過該Activity組件所使用的窗口管理器(WindowManager)來執(zhí)行的妙痹。調(diào)用所獲得的本地窗口管理器wm(類型為LocalWindowManager)的成員函數(shù)addView來執(zhí)行關(guān)聯(lián)應(yīng)用程序窗口視圖對象和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 當(dāng)Window狀態(tài)為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方法啥時候調(diào)用的呢拿霉。再來看下前面的WindowManagerGlobal#performStop方法。
看到這句mInstrumentation.callActivityOnStop(this)沒咱扣?
來看下Instrumentation#callActivityOnStop方法

public void callActivityOnStop(Activity activity) {
        activity.onStop();
    }

也就是說绽淘,執(zhí)行完Activity#performStop方法會調(diào)用Activity#OnStop方法。在OnStop之前闹伪,performStop()就執(zhí)行了沪铭。

完結(jié)撒花

那么在onStop之前壮池,onPause時候,讓popupWindow沒消失的消失好啦杀怠!以前沒仔細(xì)注意這個問題椰憋,尷尬!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赔退,一起剝皮案震驚了整個濱河市橙依,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌离钝,老刑警劉巖票编,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異卵渴,居然都是意外死亡慧域,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門浪读,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昔榴,“玉大人,你說我怎么就攤上這事碘橘』ザ” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵痘拆,是天一觀的道長仰禽。 經(jīng)常有香客問我,道長纺蛆,這世上最難降的妖魔是什么吐葵? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮桥氏,結(jié)果婚禮上温峭,老公的妹妹穿的比我還像新娘。我一直安慰自己字支,他們只是感情好凤藏,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著堕伪,像睡著了一般揖庄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上欠雌,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天抠艾,我揣著相機(jī)與錄音,去河邊找鬼桨昙。 笑死检号,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蛙酪。 我是一名探鬼主播齐苛,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼桂塞!你這毒婦竟也來了凹蜂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤阁危,失蹤者是張志新(化名)和其女友劉穎玛痊,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狂打,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡擂煞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了趴乡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片对省。...
    茶點(diǎn)故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖晾捏,靈堂內(nèi)的尸體忽然破棺而出蒿涎,到底是詐尸還是另有隱情,我是刑警寧澤惦辛,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布劳秋,位于F島的核電站,受9級特大地震影響胖齐,放射性物質(zhì)發(fā)生泄漏玻淑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一市怎、第九天 我趴在偏房一處隱蔽的房頂上張望岁忘。 院中可真熱鬧,春花似錦区匠、人聲如沸干像。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽麻汰。三九已至,卻和暖如春戚篙,著一層夾襖步出監(jiān)牢的瞬間五鲫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工岔擂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留位喂,地道東北人浪耘。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像塑崖,于是被迫代替她去往敵國和親七冲。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容