接著上一篇的博客遺留的問題,我查了許多資料,看了許多源碼,終于經(jīng)過三天的努力理解了這個問題。
現(xiàn)在先闡述一下問題,再同一個FragmentTransaction事務中,將一個已經(jīng)存在的frag1通過remove()掉,再add()這個frag1后,再commit()提交事務,無法顯示該fragment。(強調(diào)一下:是在同一個事務中)
問題產(chǎn)生原因:
有人可能會想,為啥要這么做,可能是因為我比較無聊,比較較真,我當時本來hide()后再show()就可以顯示,但是由于不小心將hide()寫成了remove()就引發(fā)了接下來一系列問題,我考慮的是既然remove()掉就再add()不就能顯示了嗎?這時候就出現(xiàn)了這個問題。
解決問題過程:
1.出現(xiàn)了上面的問題我第一個想法是是不是由于Fragment被remove后被銷毀了,導致再add(),由于Fragment是null所以不能顯示。
但是經(jīng)過調(diào)試,我發(fā)現(xiàn)remove后指向Fragment的變量并不是null,這個時候我就糾結(jié)了,不是被銷毀了嗎,怎么不為null,所以我開始懷疑是不是沒有被銷毀。
但是,經(jīng)過調(diào)試,我對Fragment重寫了所有生命周期的方法,并且通過Tag進行顯示下面是顯示的圖片
可以看出,remove后Fragment確實執(zhí)行了onDetach,也就是說這個Fragment的生命周期已經(jīng)結(jié)束了,但是調(diào)試結(jié)果是這個Fragment確實不是為空,我就上論壇提問,幾位大神的回答讓我明白了這些
沒錯,就像他們回答的一樣,remove只是將和Activity解綁了,
可以看到解綁后,這個Fragment的mActivity為null。所以這個想法就是錯的。
2.第一個想法是錯的,我就繼續(xù)改,發(fā)現(xiàn)如果,frag1remove()再add()確實不顯示,但是,如果從另一個frag2跳轉(zhuǎn)到frag1,同樣是執(zhí)行的add()方法,這樣就顯示了,這我就更糾結(jié)了,同樣的frag1,并沒有操作修改他,同樣的add()方法,怎么一個能顯示,一個不能顯示了哪?!
從這里想,我就開始找不同,也就是找變的因素,首先我對生命周期的方法進行了調(diào)試發(fā)現(xiàn)frag1在兩次add()后都執(zhí)行了
而第二種能顯示的frag1也同樣執(zhí)行到了onResume,所以這樣這期間Frag1并沒有什么區(qū)別,但是無數(shù)次斷點調(diào)試,無意間我發(fā)現(xiàn)了一個巨大的區(qū)別,那就是在調(diào)用
onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) 這個方法時,第一種不顯示的情況container是null,而第二種container為FrameLayout。
找到不顯示的根本原因了!container為空當然無法顯示了
3.基于第二步找到問題原因就開始想問題出現(xiàn)的原因,同樣是transaction.add(R.id.content, f1);指定了父容器為啥一個container為null一個不是null哪?!,查閱了很多資料,看了Fragment的源碼還有FragmentTransaction的源碼,都沒有找到原因,網(wǎng)上這塊也沒有發(fā)現(xiàn)有相關解釋,終于我找到了一篇有關的解釋:http://www.cnblogs.com/ttylinux/p/3775491.html
雖然這篇講的和我這個沒有太大關系,但是他的解釋讓我有了一定思路,尤其是對官方關于該方法的解釋 讓我有了一定想法,我去查詢這塊的源碼,官方對oncreateview()的解釋是這樣的
/**
* Called to have the fragment instantiate its user interface view.
* This is optional, and non-graphical fragments can return null (which
* is the default implementation). This will be called between
* {@link #onCreate(Bundle)} and {@link #onActivityCreated(Bundle)}.
*
* <p>If you return a View from here, you will later be called in
* {@link #onDestroyView} when the view is being released.
*
* @param inflater The LayoutInflater object that can be used to inflate
* any views in the fragment,
* @param container If non-null, this is the parent view that the fragment's
* UI should be attached to. The fragment should not add the view itself,
* but this can be used to generate the LayoutParams of the view.
* @param savedInstanceState If non-null, this fragment is being re-constructed
* from a previous saved state as given here.
*
* @return Return the View for the fragment's UI, or null.
*/
我讀了很多遍,發(fā)現(xiàn)了一個地方The fragment should not add the view itself 意思是該fragment不應該添加視圖本身,這個翻譯雖然讓人困惑,但是總能感覺出點什么,fragment不能加自身,我一開始只有frag1,remove后再add()frag1是不是添加自身?
而我如果frag1remove后再add確實不顯示,但是再add()frag2,然后再把frag2hide()再把remove掉的frag1 add()就顯示了(這句話有點繞口,但是是關鍵思路),確實兩次調(diào)用的oncreateview()時一個是從frag1remove后在add()frag1,一個是從frag2再add()frag1這不就印證了官方的話:The fragment should not add the view itself。
為了證實我的想法,我在同一個事務中,這是界面只有frag1,我remove掉后再add()一個一開始已經(jīng)初始化好的frag2(frag2這是第一次被add),
這樣從frag1add一個frag2,如果正確就能顯示吧,結(jié)果是:正確?。。?!
總結(jié):
雖然這個問題其實很無聊,很蛋疼,沒有什么意義,但也算一種解決問題的思路吧,一種思想吧,總的來說就是不能從frag1->frag1,要從fragn->fragm(n!=m)
還有,看源碼有點意思。。。。。。
如有錯誤希望大家能夠指出,這只是我自己的分析,不知道是不是有道理