Fragment重影(重疊)白屏等問題原理解析,以及解決方案

前言

絕大部分的app首頁架構均為Tab + Fragment,當程序發(fā)生異常自動恢復孤澎,或者app長時間處于后臺恢復后届氢,F(xiàn)ragment出現(xiàn)重影(重疊)等問題。當然部分不顧及頁面層級的小伙伴覆旭,每個Fragment的view都設置了背景退子,可能就察覺不出來,但是并不代表沒有型将。然后很多Fragment里面又還有Fragment的使用不當甚至會出現(xiàn)白屏的現(xiàn)象寂祥。

1 重影(重疊)

1.1 觸發(fā)原因

Activity在非正常退出(點返回等屬于正常退出)會調用 onSaveInstanceState 方法來保存數據,其中就包括視圖層(View Hierarchy),當該Activity在此被重建時茶敏,會調用onRestoreInstanceState方法壤靶,之前被實例化過的 Fragment 依然會出現(xiàn)在 Activity 中,然后按照正常生命流程走惊搏,在onCreate中FragmentTransaction相當于又再次 add 了 fragment 進去的贮乳,hide()和show()方法對之前保存的fragment已經失效了。綜上這些因素導致了多個Fragment重疊在一起

1.2 如何調試

  • 當你不確定你的app是否存在該問題時恬惯,先檢查fragment是否有背景向拆,如果有,先刪掉
  • 手機的 “設置” - “開發(fā)者選項” - 打開”不保留活動”(主要用于模擬Activity被及時回收)
  • 把 app 切換到后臺酪耳,再重新打開浓恳,通過點按不同的 tab 來切換 Fragment,打開其他頁面在回來碗暗,在切換tab
  • 如果有重影颈将,請接著看下面的解決方案,如果沒有言疗,恭喜你晴圾,你的代碼太完美了,希望你能提供更優(yōu)質的解決方案

1.3 解決方案

1.3.1 在onCreate方法判斷 savedInstanceState 參數是否為null (不推薦)

如果savedInstanceState不為null噪奄,說明該Activity有保存的實例死姚,在add fragment 時添加標簽,具體看源碼
selectedFragment方法 其中XXX.getClass().getSimpleName()為Tag 為演示才這樣寫的

private void selectedFragment(int position) {
        mPosition = position;
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        hideFragment(transaction);
        switch (position) {
            case 0:
                if (fragment1 == null) {
                    fragment1 = new Fragment1();
                    transaction.add(R.id.fl_content, fragment1,fragment1.getClass().getSimpleName());
                } else {
                    transaction.show(fragment1);
                }
                break;
            case 1:
                if (fragment2 == null) {
                    fragment2 = new Fragment2();
                    transaction.add(R.id.fl_content, fragment2,fragment2.getClass().getSimpleName());
                } else {
                    transaction.show(fragment2);
                }
                break;
            case 2:
                if (fragment3 == null) {
                    fragment3 = new Fragment3();
                    transaction.add(R.id.fl_content, fragment3,fragment3.getClass().getSimpleName());
                } else {
                    transaction.show(fragment3);
                }
                break;
            case 3:
                if (fragment4 == null) {
                    fragment4 = new Fragment4();
                    transaction.add(R.id.fl_content, fragment4,fragment4.getClass().getSimpleName());
                } else {
                    transaction.show(fragment4);
                }
                break;
            default:
        }
        transaction.commitAllowingStateLoss();
    }

onCreate方法代碼

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.initData(savedInstanceState);
    //不為null,說明是死而復活勤篮,移除已經存在的fragment
    if (savedInstanceState != null) {
        FragmentTransaction mTransaction = getSupportFragmentManager().beginTransaction();
        mTransaction.remove(mManager.findFragmentByTag(Fragment4.class.getSimpleName()));
        mTransaction.remove(mManager.findFragmentByTag(Fragment3.class.getSimpleName()));
        mTransaction.remove(mManager.findFragmentByTag(Fragment2.class.getSimpleName()));
        mTransaction.remove(mManager.findFragmentByTag(Fragment1.class.getSimpleName()));
        mTransaction.commitAllowingStateLoss();
    }
 
    selectedFragment(mPosition);
    ......
}
1.3.2 重寫onSaveInstanceState onRestoreInstanceState 方法 (推薦)

無需為Fragment 添加Tag 保持最開始的實現(xiàn)邏輯不動 源碼

    **
     * 原理  去除Super 切斷原有恢復邏輯 保存位置
     * @param outState
     */
    @SuppressLint("MissingSuperCall")
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        /* 記錄當前的position */
        outState.putInt("position", mPosition);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        mPosition = savedInstanceState.getInt("position");
        selectedFragment(mPosition);
    }

2 白屏

2.1 觸發(fā)原因

當Fragment里面嵌套Fragment時都毒,沒有使用getChildFragmentManager(),在Activity恢復后無法獲取FragmentManager內的Fragment,從而出現(xiàn)白屏碰缔。

2.1 解決方案

Fragment嵌套Fragment時,使用getChildFragmentManager()獲取事務

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末账劲,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌涤垫,老刑警劉巖姑尺,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蝠猬,居然都是意外死亡切蟋,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門榆芦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柄粹,“玉大人,你說我怎么就攤上這事匆绣∽び遥” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵崎淳,是天一觀的道長堪夭。 經常有香客問我,道長拣凹,這世上最難降的妖魔是什么森爽? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮嚣镜,結果婚禮上爬迟,老公的妹妹穿的比我還像新娘。我一直安慰自己菊匿,他們只是感情好付呕,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著跌捆,像睡著了一般徽职。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上佩厚,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天活箕,我揣著相機與錄音,去河邊找鬼可款。 笑死,一個胖子當著我的面吹牛克蚂,可吹牛的內容都是我干的闺鲸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼埃叭,長吁一口氣:“原來是場噩夢啊……” “哼摸恍!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤立镶,失蹤者是張志新(化名)和其女友劉穎壁袄,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體媚媒,經...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡嗜逻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了缭召。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片栈顷。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖嵌巷,靈堂內的尸體忽然破棺而出萄凤,到底是詐尸還是另有隱情,我是刑警寧澤搪哪,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布靡努,位于F島的核電站,受9級特大地震影響晓折,放射性物質發(fā)生泄漏惑朦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一已维、第九天 我趴在偏房一處隱蔽的房頂上張望行嗤。 院中可真熱鬧,春花似錦垛耳、人聲如沸栅屏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽栈雳。三九已至,卻和暖如春缔莲,著一層夾襖步出監(jiān)牢的瞬間哥纫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工痴奏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蛀骇,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓读拆,卻偏偏與公主長得像擅憔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子檐晕,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容