Android之FragmentManager add機(jī)制的變遷

起因

最近在把項(xiàng)目support庫從23.1.1升級至23.4.0時(shí),突然發(fā)現(xiàn)有些地方會莫名的找不到"已經(jīng)"add的fragment,從而導(dǎo)致了空指針引用異常。郁悶的我就仔細(xì)對比了23.1.1和23.4.0源碼闸天,發(fā)現(xiàn)原來是google悄悄地把FragmentManager add()機(jī)制更改了犬绒,真是坑爹-檩禾,-挂签。

探究

如下是一段很平常的代碼:


//In Activity.java
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    getSupportFragmentManager()
        .beginTransaction()
        .add(android.R.id.content, fragmentA, fragmentA.TAG)
        .add(android.R.id.content, fragmentB, fragmentB.TAG)
        .commit();
    }

//In FragmentA.java
     @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
            mFragmentB =(FragmentB)getFragmentManager()
                   .findFragmentByTag(FragmentB.TAG);
        mFragmentB.performSomeAction();
       ... ...
    }

在23.1.1之前FragmentManager的add機(jī)制:

//STEP0: 記錄已經(jīng)添加和有效的fragment集合
    ArrayList<Fragment> mAdded;
    ArrayList<Fragment> mActive;
    ... ...
    public void run() {
    ... ...
//STEP1: 根據(jù)之前的add順序,從mHead中取出fragment并依次放入lastInFragments中盼产,為之后的transition做準(zhǔn)備饵婆。
    calculateFragments(firstOutFragments,lastInFragments);

//STEP2: 再根據(jù)lastInFragments集合統(tǒng)計(jì)出fragments的過渡狀態(tài)(因?yàn)閮Hadd操作,所以firstOutFragments為空)
    state=beginTransition(firstOutFragments,lastInFragments, false);
    ... ...
//STEP3:依次將mHead鏈表中的fragment加入至mAdded和mActive中戏售,但不會更改fragment的狀態(tài)(即不會觸發(fā)fragment的初始化操作)侨核。
    while (op != null) {
            int enterAnim = state != null ? 0 : op.enterAnim;
            int exitAnim = state != null ? 0 : op.exitAnim;
            switch (op.cmd) {
                case OP_ADD: {
                    Fragment f = op.fragment;
                    f.mNextAnim = enterAnim;
                    mManager.addFragment(f, false);
                } break;
                ... ...
            }
    }
    
//STEP4: 最后更新mActive集合中所有fragment的狀態(tài)(對于add操作而言即是觸發(fā)了fragment的初始化操作)
    mManager.moveToState(mManager.mCurState
                            , transition, transitionStyle, true);
    ... ...
}

而在23.4.0版本的support庫中,它初始化fragment的時(shí)機(jī)發(fā)生了變化蜈项,主要變化是在上述的STEP1中芹关。
在23.4.0的STEP1中,除了根據(jù)之前的add順序紧卒,從mHead中取出fragment并依次放入lastInFragments中侥衬,為之后的transition做準(zhǔn)備。并且將新add的fragment放入mActive中跑芳,同時(shí)更新fragment的狀態(tài)(即觸發(fā)了fragment的初始化操作)轴总。

// 23.1.1版本:
    private void setLastIn(SparseArray<Fragment> fragments, Fragment fragment) {
        if (fragment != null) {
            int containerId = fragment.mContainerId;
            if (containerId != 0) {
                fragments.put(containerId, fragment);
            }
        }
    }
    
// 23.4.0版本:
    private void setLastIn(... , Fragment fragment) {
        if (fragment != null) {
             ... ...
            if (fragment.mState < Fragment.CREATED 
                    && mManager.mCurState >= Fragment.CREATED) {
                mManager.makeActive(fragment);
                mManager.moveToState(fragment, Fragment.CREATED, 0, 0, false);
            }
        }
    }

因?yàn)橛|發(fā)fragment初始化時(shí)機(jī)發(fā)生了改變,所以當(dāng)FragmentB在FragmentA之后add博个,此時(shí)在FragmentA的onCreate方法中通過findFragmentByTag找FragmentB時(shí)怀樟,必然找到的為空(即mAdded和mActive兩個(gè)集合中都無法找到),因?yàn)榇藭r(shí)FragmentB根本還未來得及被添加至mAdded或mActive集合中盆佣。

    public Fragment findFragmentByTag(String tag) {
        if (mAdded != null && tag != null) {
            // First look through added fragments.
            for (int i=mAdded.size()-1; i>=0; i--) {
                Fragment f = mAdded.get(i);
                if (f != null && tag.equals(f.mTag)) {
                    return f;
                }
            }
        }
        if (mActive != null && tag != null) {
            // Now for any known fragment.
            for (int i=mActive.size()-1; i>=0; i--) {
                Fragment f = mActive.get(i);
                if (f != null && tag.equals(f.mTag)) {
                    return f;
                }
            }
        }
        return null;
     }

結(jié)語

所以謹(jǐn)記往堡,如果兩個(gè)fragment之間有調(diào)用關(guān)系的話,添加他們時(shí)一定要優(yōu)先add被調(diào)用的fragment(即例子中的FragmentB)共耍,以方support庫升級后引起空指針異常虑灰。


歡迎查看 個(gè)人博客.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市痹兜,隨后出現(xiàn)的幾起案子穆咐,更是在濱河造成了極大的恐慌,老刑警劉巖字旭,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件对湃,死亡現(xiàn)場離奇詭異,居然都是意外死亡遗淳,警方通過查閱死者的電腦和手機(jī)拍柒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來屈暗,“玉大人拆讯,你說我怎么就攤上這事剧包。” “怎么了往果?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長一铅。 經(jīng)常有香客問我陕贮,道長,這世上最難降的妖魔是什么潘飘? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任肮之,我火速辦了婚禮,結(jié)果婚禮上卜录,老公的妹妹穿的比我還像新娘戈擒。我一直安慰自己,他們只是感情好艰毒,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布筐高。 她就那樣靜靜地躺著,像睡著了一般丑瞧。 火紅的嫁衣襯著肌膚如雪柑土。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天绊汹,我揣著相機(jī)與錄音稽屏,去河邊找鬼。 笑死西乖,一個(gè)胖子當(dāng)著我的面吹牛狐榔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播获雕,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼薄腻,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了典鸡?” 一聲冷哼從身側(cè)響起被廓,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎萝玷,沒想到半個(gè)月后嫁乘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡球碉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年蜓斧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片睁冬。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡挎春,死狀恐怖看疙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情直奋,我是刑警寧澤能庆,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站脚线,受9級特大地震影響搁胆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜邮绿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一渠旁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧船逮,春花似錦顾腊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至冠骄,卻和暖如春伪煤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背凛辣。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工抱既, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人扁誓。 一個(gè)月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓防泵,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蝗敢。 傳聞我的和親對象是個(gè)殘疾皇子捷泞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353

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