Fragment 的源码实现 (完结)

Fragment  实际上 是 把 View  封装了一下,  Fragment 中 onCreatedView 返回的 View   最终 会被 添加到  Fragment被添加到 FragmentMananger 的时候 对应 container 容器中. 最后一部分 为梳理的 Fragment 和 Activity 之间的关联.


下面 主要 是 根据 我们 平时 使用 Fragment 的方式 梳理一下 Fragment 对应的源码实现:

-------------------------------------------------------------------------------------------------------

1. 如果想要使用 Fragment, 首先要获取到 FragmentManangerImpl 这个对象.


第一步:



第二步: mFragments 初始化的地方为: FragmentManangerImpl 使用的为 默认构造函数.



2.  使用 Fragment 的时候 是以  事务的方式 对 修改进行提交的, 通过  beginTransaction() 来 获取到  FragmentTransaction 对象.


第一步: 实际 使用 beginTransaction() 方法 获取到 的是一个 BackStackRecord 对象, 



第二步: BackStackRecord 类 是 FragmentTransaction 的子类, 且实现了 Runnable 接口





3. 如果 我们想 向 Activity中 添加一个展示的 Fragment, 则 是 通过 BackStackRecord 提供的 add 和 replace 方法 来进行添加或者删除 Fragment:  但 实际上 我们 在 一个 BackStackRecord 上执行 add 或 replace 只是 在 BackStackRecord 中对应的 Op 链条中 添加 一个 Op 对象,  Op 对象 的实例变量中 保留了 操作的 类型  和 本次操作 对应的 Fragment.


第一步:


第二步:




第三步:  doAddOp 的实现是 往 BackStackRecord 对应的 Op 链中 增加一个 Op 对象. fragment 的 mContainerId 和 mFragmentId 的值 为 传入的 containerViewId 这个值.





第四步:  把 上一步 封装好的 Op 对象, 添加到 BackStackRecord 对应的 Op 对象 链条中.





4.  当我们 完成 add 和 replace 的操作 之后, 我们 可以使用 BackStackRecord 中的 commit 进行 事务的提交.


第一步:


第二步: BackStackRecord 被执行 commit 之后,会把 自己 放入到 FragmentMananger 对应的队列中去.




第三步:  首先会 把 BackStackRecord 作为 Runnable 的对象 放入到 mPendingActions 这个队列中, 然后 把 mExecCommit 放入到 mActivity.mHandler 对应的 looper 中,





第四步:  其中 mExecCommit 对应的实现为:




第五步:  在 execPendingActions 中实际上是 遍历 mPendingActions 中的 所有 BackStackRecord 对象, 然后 作为 Runnable 对象 来 执行 BackStackRecord 中 对应的 run 方法:




5.  在 BackStackRecord 中 对应的 run 方法的实现为:


第一步:  如果 要被 替换的 Fragment 和 参数传入的 Fragment 相同, 则不会 调用 mMananger 的 addFragment 方法. 

   如果 要被 替换的Fragment 和 参数传入的 Fragment 不同, 则把 老的 Fragment 添加到 op 的 removed 这个 数组中, 然后删除 老的 Fragment , 然后 调用 mMananger 的 addFragment 把 新的 Fragment 添加 到 FragmentMananger 中.


第二步: moveToStateNow : 这个参数 决定是否 立即把 Fragment 的 mState 同步 成  FragmentMananger 对应的 state.


第三步 :把 Fragment 标记为 active 状态:




6.  Fragmet 的 状态 切换:


第一步 : 在 FragmentMananger 中 调用 moveToState (Fragment f) , 这个时候实际上 是 调用 moveToState(f, mCurState [ 当前FragmentMananger 对应的状态, 0 , 0 , false).



第二步: 





第三步 : . 在 switch 对应的段落中, 则 根据 Fragment 本身的 mState 来选择 switch 的入口, 然后 开始执行.




第四步:  注意 这里的 switch 是没有 break 语句的, 因此 当 根据 Fragment 的 mState 进入到 switch 的某个分支 之后, 则会继续执行:




第五步: 




第六步:  如果 Fragment 的 mState 大于 FragmentMananger 中 mCurState , 则 说明 当前 Activity 在走 衰减的 周期:


第七步 : 当 FragmentMananger 的 状态 为 小于 ACTIVITY_CREATED 的时候 则 销毁 Fragment 对应的 视图 View :




第 八 步:  当 FragmentMananger 的 状态 为 小于 CREATED的时候, 则 才会 去调用 Fragment 对应的  onDestroy 方法.





9.  小总结 :


Fragment 设计的经典之处是 在 moveToState 这个地方, 这里 使用了 不带 break 的 switch 语句.  switch 的 判断变量 为 Fragment 中的 mState 这个状态的值, 最终值 为 moveToState 中传入的 mNewState(这个值实际上是 FragmentMananger 的 State),  所以 不管 传进来的 Fragement 是 什么 状态, 都会被 转成 和 FragmentMananger 保持一致的状态.

10.  Fragment 与 Activity 生命周期直接的关系为:


Activity 在 回调方法中 会 通过 FragmentMananger 提供的 movetToState 来修改 FragmentMananger 对应的状态 ,以便和 Activity和  FragmentManager 的状态保持一致, 


---------------------------------------------------------------------------------

第一步 :. moveToState 做了两件事情,  

第一件: 把 FragmentMananger 当前的状态设置为了 newState,
第二件: 遍历 mActive 中的所有 Fragment, 然后把 Fragment的状态扭转成 newState.



第二步.  moveToState 被调用的位置为: 



第三步:. 而 dispatchCreate 被调用的位置为:





第四步. Fragment 对应的其他状态的执行:


dispatchCreate 是在 : Activity 的  onCreate 方法中执行的.

dispatchActivityCreated 是在 :  Activity 执行完 onCreate 方法之后 执行的.

dispatchStart 和 dispatchResume 方法 是在 : Activity 执行完 onStart 和 onResume 之后 执行的 ( 一 一对应).

dispatchPause (Fragment.STARTED) , dispatchStop(Fragment.STOPPED) 以及 dispatchDestroy (Fragment.INITIALIZING) 是在 : Activity 对应的回调方法之前 完成的.


图1:

图2:

图3:
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容