LeakCanary提示` policy.HwPhoneWindow$1.this$0`的泄漏分析

最新在華為手機(jī)GEM=703L android6.0發(fā)現(xiàn)的問(wèn)題百炬,在AsyncTask執(zhí)行ProgressDialog的顯示或隱藏褐隆,然后退出activity會(huì)發(fā)生泄漏。泄漏提示
GC ROOT com.android.internal.policy.HwPhoneWindow$1.this$0

開(kāi)始分析

首先上mat的分析圖

Paste_Image.png

其中提示了兩個(gè)未清除的引用剖踊,都指向了HwPhoneWindow庶弃,貌似其內(nèi)部類引用了它,這是什么東東?
憑我有限的小腦分析德澈,涉及Window類在我的app只有兩種:Activity歇攻,Dialog。Activity我已經(jīng)完美的解決了泄漏問(wèn)題梆造,那先從Dialog下手缴守。

在Dialog類中可以看到可以看到mWindow,mDecor

  final Window w = new PhoneWindow(mContext);
        mWindow = w;

...
mDecor = mWindow.getDecorView();

想到了什么,是不是跟Activity很像,原來(lái)Dialog自己擁有WIndow并維護(hù)屡穗,但是新建的時(shí)候使用Activity的上下文贴捡,在Activity銷毀的時(shí)候,Dialog不銷毀就會(huì)有泄漏風(fēng)險(xiǎn)村砂,而且Dialog的生命周期會(huì)跟Activity產(chǎn)生不同步烂斋。

嘗試1

原來(lái)寫法

 progressDialog = new ProgressDialog(Activity.this);
 progressDialog.setProgress(ProgressDialog.STYLE_SPINNER);
 progressDialog.setTitle("加載通訊錄中...");

并在Activity的onDestory執(zhí)行super之前銷毀

@Override
    protected void onDestroy() {
        if(progressDialog != null ){
            progressDialog.dismiss();
            progressDialog = null;
        }
        super.onDestroy();
    }

結(jié)果:
還是存在泄漏

嘗試2

修改原來(lái)的寫法,使用FragmentDialog改造箍镜,利用Fragment維護(hù)Dialog的生命周期
改造后:

public class ProgressFragmentDialog extends DialogFragment {
 @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder progressDialog = new AlertDialog.Builder(this.getActivity());
        progressDialog.setView(getActivity().getLayoutInflater().inflate(R.layout.dialog_progress,null));
        progressDialog.setCancelable(false);


        //取消返回鍵
        progressDialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
            @Override
            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {

                return true;
            }
        });
        AlertDialog dialog = progressDialog.create();
        dialog.setCanceledOnTouchOutside(false); //取消點(diǎn)擊外關(guān)閉

        return dialog;
    }
}

//顯示Dialog
 progressFragmentDialog = new ProgressFragmentDialog();
        progressFragmentDialog.show(this.getFragmentManager(),"ProgressFragmentDialog");

結(jié)果:

還是存在泄漏

what fuck! 分析到這源祈,我已經(jīng)黔驢技窮了,干脆不用Dialog色迂,自己實(shí)現(xiàn)彈出框

嘗試3

思路就是拿到根節(jié)點(diǎn)decorView,new一個(gè)View adddecorView上香缺,前提是在Activity的setContentView()之后執(zhí)行
上代碼

public class ProgressViewDialog {

    /**
     * 上下文,存儲(chǔ)activity信息
     */
   // private Context context;
    private ViewGroup decorView; //decorView
   // private ViewGroup activityRootView;//內(nèi)容區(qū)域的根視圖
    private ViewGroup dialogView;//我的根視圖


    /**
     * 構(gòu)造函數(shù)
     * @param context
     */
    public ProgressViewDialog(Context context)
    {
        //獲得一個(gè)xml布局加載器
        LayoutInflater layoutInflater = LayoutInflater.from(context);

        //獲得decorView
        decorView = (ViewGroup)((Activity)context).getWindow().getDecorView();
        //Log.d("decorView count", decorView.getChildCount()+"") ;
        //獲得內(nèi)容區(qū)域根視圖
        //activityRootView = (ViewGroup)decorView.findViewById(android.R.id.content);
        //Log.d("activityRootView count", activityRootView.getChildCount()+"") ;

        //獲得我的根視圖
        dialogView = (ViewGroup)layoutInflater.inflate(R.layout.dialog_progress,null);
        //Log.d("rootView count", rootView.getChildCount() + "") ;

        //屏蔽下層觸摸
        dialogView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("lessonOneActivity","點(diǎn)擊了本層");
            }
        });
        //屏幕返回鍵
        dialogView.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                return true;
            }
        });


    }
    public void show(){
        if(dialogView.getParent() == null){
            decorView.addView(dialogView);
            dialogView.setVisibility(View.VISIBLE);
        }
        else{
            //decorView.addView(rootView);
            dialogView.setVisibility(View.VISIBLE);
        }
    }

    public void dismiss(){
        dialogView.setVisibility(View.GONE);
    }

}

還是發(fā)現(xiàn)了上個(gè)泄漏問(wèn)題歇僧,分析到這里图张,我已經(jīng)沒(méi)轍了,然后換臺(tái)手機(jī)诈悍,魅族mx3,神奇的事情發(fā)生了祸轮,竟然沒(méi)有泄漏了。黑人問(wèn)號(hào)臉侥钳。

總結(jié)

繼續(xù)查資料适袜,發(fā)現(xiàn)很多人給出了討論或者解決方案,傾向于Android輸入法的漏洞舷夺,在15<=API<=23中都存在苦酱。
知乎用戶十三太飽給出的解釋是:
**
InputMethodManager的相關(guān)對(duì)象(mServedView等)沒(méi)有傳遞下去的話,通過(guò)工具的檢測(cè)的確會(huì)發(fā)現(xiàn)前一個(gè)Activity出現(xiàn)內(nèi)存泄漏给猾。但是實(shí)際上疫萤,InputMethodManager對(duì)象并不是完全歸前一個(gè)Activity持有,只是暫時(shí)性的指向了它敢伸,InputMethodManager的對(duì)象是被整個(gè)APP循環(huán)的使用扯饶。另外,InputMethodManager是通過(guò)單例實(shí)現(xiàn)的池颈,不會(huì)造成內(nèi)存的疊加尾序,所以個(gè)人覺(jué)得InputMethodManager并不會(huì)造成實(shí)質(zhì)的內(nèi)存泄漏。
**
個(gè)人選擇不再解決饶辙,下面列一些blog供大家研究蹲诀,有什么問(wèn)題可以隨時(shí)討論,以上弃揽。

Android InputMethodManager 導(dǎo)致的內(nèi)存泄露及解決方案
Leakcanary部分泄露警報(bào)無(wú)需修復(fù)

待研究參考資料:

Android非UI線程使用View.post()方法一處潛在的內(nèi)存泄漏

注意事項(xiàng):

  1. Dialog銷毀一定要在activity銷毀之前
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子矿微,更是在濱河造成了極大的恐慌痕慢,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涌矢,死亡現(xiàn)場(chǎng)離奇詭異掖举,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)娜庇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門塔次,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吓肋,“玉大人掂名,你說(shuō)我怎么就攤上這事∨锉冢” “怎么了匕得?”我有些...
    開(kāi)封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵继榆,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我汁掠,道長(zhǎng)略吨,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任考阱,我火速辦了婚禮翠忠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘乞榨。我一直安慰自己秽之,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布姜凄。 她就那樣靜靜地躺著政溃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪态秧。 梳的紋絲不亂的頭發(fā)上董虱,一...
    開(kāi)封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音申鱼,去河邊找鬼愤诱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛捐友,可吹牛的內(nèi)容都是我干的淫半。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼匣砖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼科吭!你這毒婦竟也來(lái)了昏滴?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤对人,失蹤者是張志新(化名)和其女友劉穎谣殊,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體牺弄,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡姻几,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了势告。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛇捌。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖咱台,靈堂內(nèi)的尸體忽然破棺而出络拌,到底是詐尸還是另有隱情,我是刑警寧澤吵护,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布盒音,位于F島的核電站,受9級(jí)特大地震影響馅而,放射性物質(zhì)發(fā)生泄漏祥诽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一瓮恭、第九天 我趴在偏房一處隱蔽的房頂上張望雄坪。 院中可真熱鬧,春花似錦屯蹦、人聲如沸维哈。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)阔挠。三九已至,卻和暖如春脑蠕,著一層夾襖步出監(jiān)牢的瞬間购撼,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工谴仙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留迂求,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓晃跺,卻偏偏與公主長(zhǎng)得像揩局,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子掀虎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,099評(píng)論 25 707
  • 介紹自己負(fù)責(zé)的部分凌盯,如何實(shí)現(xiàn)的付枫。 自定義view viewGroup activity的啟動(dòng)流程 事件傳遞及滑動(dòng)沖...
    東經(jīng)315度閱讀 1,208評(píng)論 1 4
  • 一、概述 Activity 作為與用戶交互的一個(gè)窗口十气,是使用非常頻繁的一個(gè)基本組件励背。Android系統(tǒng)是通過(guò)Act...
    三也視界閱讀 2,234評(píng)論 3 11
  • 七年是一個(gè)輪回 早先的細(xì)胞都已作廢 閑來(lái)身上不再爬滿怨懟 可依舊沒(méi)有把握 若再見(jiàn)你是否可以 自持不流淚 有時(shí)愿你我...
    Serena_02fc閱讀 293評(píng)論 0 0
  • 【賤】多年不見(jiàn)之人春霍,偶爾電話呼來(lái)砸西,甚是歡欣;仰望的領(lǐng)導(dǎo)不經(jīng)意看了你一眼址儒,就想入非非芹枷;陪伴多年的夫妻,一切視而不見(jiàn)莲趣,...
    繭破閱讀 502評(píng)論 8 11