最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網 會員登陸 & 注冊

Fragment事務管理源碼分析

2021-09-17 21:24 作者:房頂上的鋁皮水塔  | 我要投稿

一個簡單的FragmentTranscation事務相關的源碼分析和面試題的回答~

FragmentActivity#getSupportFragmentManager

通過FragmentManager獲取FragmentTransaction對象,實際上返回的是BackStackRecord這個類。FragmentTransaction是一個抽象類


FragmentTransaction#add

我們通常使用這樣的形式向指定的ViewGroup中添加Fragment:

包括很多的不同的add方法的重載,這些方法都會最終調用Fragment#doAddOp:

Fragment#doAddOp:

這一個方法主要是給Fragment設置相關的參數,主要做了三件事情:

公平 公平 還是tmd公平!
  1. tag

  2. ?containerViewid

  3. fragmentId

最后將Fragment和opCmd(在這里就是OP_ADD)封裝成一個Op對象。


FragmentTransaction#addOp

然后就存放到了一個ArrayList中:

FragmentTransaction#replace remove hide detach attach

這些方法以及它的重載方法都是調用了doAddOp,但是cmdOp會使用不同的枚舉:

具體的看看源代碼就行~


FragmentTransaction#commit

FragmentTransaction 自身并沒有實現commit,真正的實現方法在BackStackRecord中。我們常用的commit和commitAllowingStateLoss都會調用commitInternal方法:

只不過commit中allowingStateLoss=false,commitAllowingStateLoss中為true。


在方法的尾部會調用FragmentManager#enqueueAction。這里傳遞的參數是this,所以BackStackRecord從FragmentTransaction中繼承的Op集合也會被傳過去。

FragmentManager#enqueueAction

Fragment狀態(tài)的保存是在Activity#onSaveInstanceState時進行的,調用FragmentManager#saveAllState保存,并且設置mStateSaved為true。而istStateSaved會檢查mStateSaved || mStopped;是否等于true,如果等于true就回拋出異常。

所以我們應該盡量避免在onStart、onResume中commit,因為這寫方法可能會被反復調用。

這里參考了這篇文章:cnblogs.com/kissazi2/p/4181093.html

所以,如果是commitAllowingStateLoss,FragmentManager在commit的時候就不會去檢查是否會發(fā)生stateLoss,但是這樣會帶來不好的用戶體驗??紤]下面兩種情形:

  1. Activity由于發(fā)生了旋轉,Activity調用onSaveInstanceState恢復之前的狀態(tài),但是此時commit在onSavedInstanceState之后調用,本來想更新新的內容,但是卻恢復成了原來的內容,這個時候由于onSavedState=true,就回拋出異常。

  2. Activity被回收了,mStopped=true,這個時候commit修改Activity的內容也是無效的。

所以我們不應該假設Activity不會發(fā)生stateLoss而調用FragmentTransaction#commitAllowingStateLoss。


回到我們原本的方法,enqueueAction也加了同步鎖機制,然后將當前的Action(BackStackRecord)添加到mPendingActions中,然后調用scheduleCommit:

FragmentManager#scheduleCommit

這個方法中會對加入到pendingActions中的操作進行同步鎖定,然后通過Activity的Handler發(fā)送出去:

在mExecCommit這個Runnable中實際上就回最終調用到我們BackStackManager#executeOps方法,在這個方法中會根據之前每一個Op實例設置的cmd執(zhí)行對應的FragmentManager的操作。所以commit的流程如圖所示:

zoingjie?

總結:

1. commit和commitAllowingStateLoss

這兩個方法都會調用commitInternal,前者不允許stateLoss,后者允許。在Activity#onSavedInstanceState中會設置FragmentManager的mSavedState=true,如果我們在這個方法之后commit會拋出異常;同時我們也不應該在Activity Stop之后commit。

2.?commit 是異步的

我們在commit的時候最終會將操作添加到FragmentManager中的隊列中,最后通過Handler發(fā)送給主線程執(zhí)行。所以多一個transaction.commit的時候不能保證這個動作立刻執(zhí)行。而且transaction的動作,比如remove add replace都是在commit執(zhí)行時才會發(fā)生。如果想要立刻執(zhí)行事務

1. 可以使用commitNow()【commitNow不會將事務添加到回退棧中】。而且不可以和回退棧一起使用,以下的代碼會報錯。

因為:

而在commitNow中會調用:

2. 可以使用FragmentManager.executePending

但是Android SDK的注釋中也指出,使用這種方式會導致一些副作用,因為這種操作會執(zhí)行所有待執(zhí)行的任務。

3. 重建Fragment

當Activity意外銷毀時,會保存當前Fragment的狀態(tài)和Arguments。在這篇文章

https://juejin.cn/post/6984605769245130788#heading-24?中指出一點需要注意的問題,FragmentManager#restoreAllState方法會調用反射調用Fragment的無參構造方法恢復Fragment。所以盡量使用默認無參構造方法,而且獲取參數的同時,使用arguments。


不過這點我在androidx的代碼中看起來和文章中并不一樣,可能只是我沒看到.....?

但是還是可以注意一下~

4. 如何獲取FragmentManager?

在Activity中使用getSupportFragmentManager,在Fragment中使用getChildFragmentManager。這個變量在Fragment初始化的同時也會被初始化。

5. 不要使用startActivityForResult,應該使用Activity Results API

https://segmentfault.com/a/1190000037601888

6. Fragment的回退棧

所以實際上并不是Fragment加入了回退棧,而是Fragment的事務進入了回退棧。如果當Fragment進入了回退棧,返回的時候會回滾事務。

Fragment事務管理源碼分析的評論 (共 條)

分享到微博請遵守國家法律
沐川县| 桃江县| 织金县| 兴隆县| 宁南县| 沁阳市| 赤城县| 改则县| 聊城市| 法库县| 济源市| 尚义县| 姜堰市| 德令哈市| 肃南| 苍溪县| 梅河口市| 塔城市| 神农架林区| 雷山县| 清远市| 化德县| 蒲江县| 河间市| 禹州市| 宿州市| 德江县| 平陆县| 临颍县| 略阳县| 锡林浩特市| 枣强县| 溧水县| 建始县| 福州市| 甘南县| 清流县| 望江县| 克拉玛依市| 诸暨市| 都匀市|