Fragment系列总结(一)Fragment概念与生命周期
寫在前面
Fragment是Google在Android3.0新加的東西,它的功能和作用如同名字一樣,代表著一塊塊碎片,而這些碎片則可以靈活地嵌入到各Activity之中。
其他關于Fragment的介紹,相信大家看各種博客和書籍都了解得非常多了,所以在此介紹一些關于Fragment獨特的見解,在剛開始的時候,我對Fragment的理解也只停留在書籍介紹的部分,但是隨著開發經驗的積累,才真正明白Google工程師們的偉大...
Android整個框架其實是一個比較經典的MVC開發模型,拋開Model和View容易理解以外,雖然沒有iOS之中各種XXXController命名方法這么直觀,但是Activity其實一直都承擔著控制器的角色,如果按照一種十分完美的項目工程來說,Fragment的引入,能夠減輕臃腫的Activity業務控制代碼,對不同區域View的控制任務進行劃分,分別移到到不同的Fragment之中,而Activity原則上只需要管理這些Fragment以及極少的業務控制部分。這種開發方式不僅使得Android能夠解決屏幕碎片化的問題,也讓各部分的業務邏輯開發變得淺顯易懂。
總而言之:Fragment其實是承擔Acitivity中不同View區域邏輯的控制器,而Activity將通過FragmentManager對所有的Fragment進行統一管理。
Fragment基礎概念
Fragment的問世經過了很多年,而這些年Google的工程師們也一直在改進Fragment的代碼,目前的現狀就是除了SDK包中自帶的Fragment以外,還提供了存在于V4兼容包內的Fragment,一般情況下,大多數開發者們都會使用v4包下的Fragment,這幾乎成為主流。隨著包路徑所帶來的不同以外,Activity中的Fragment管理類的獲取方式也從getFragmentManager()變成了getSupportFragmentManager()。
靜態Fragment使用方法不談,動態Fragment的操作將會以事務(Transaction)的形式完成,代碼如下:
開發過程中往往會采用鏈的形式進行調用,詳情可以查看本文末尾提供的代碼。Activity對于Fragment的操作主要包括七種:add、remove、replace、attach、detach、show、hide。
add(int id,Fragment fragment,String tag)
向特定View區域添加一個Fragment,此方法接收三個參數,第一個是Activity中在xml定義的ViewGroup(一般是FrameLayout)的Id,第二個參數是需要添加的Fragment,第三個參數是為Fragment指定一個Tag標識,方便之后的查找。如果查看過add()的源碼就會發現,在成功添加后,Fragment還會將第一個參數作為自己的id來進行標識(非唯一),換言之,我們可以通過id和tag來尋找到該fragment。
remove(Fragment fragment)
移除Fragment
replace(int id,Fragment fragmentB)
這個方法等于先remove掉該id的fragment,然后再add一個fragmentB
show(Fragment fragment)和hide(Fragment fragment)
顯示/隱藏視圖
detach(Fragment fragment)和attach(Fragment fragment)
剝離/連接視圖 差別在下文講述
findFragmentById(int id)和findFragmentByTag(String tag)
這兩個方法類似于findViewById()的邏輯來對Activity管理的Fragment進行查找,采用依次遍歷的方式,將符合id或者tag字段的fragment進行返回。那么,問題來了:如果一個framelayout的id添加了很多個Fragment,怎么知道返回的是哪一個Fragment?運行demo試試唄。
好了,除此之外,也沒什么基礎概念需要提醒大家了。
Activity和Fragment的關系
開局一張圖送大家:
此圖蘊含著Activity和Fragment的關系,按照前文的思想,我們來假設一個場景:
臨近春節,一個叫activity的老板圈了一塊場子要開展銷會,他覺得如果整個場子都自己來管理的話有點混亂,于是他邀請了幾個商家分別叫fragmentA、fragmentB,fragmentC,分別劃分一塊地給他們經營,如何經營他管不著,他只需要通過fragmentmanager這個管家來管好這幾個叫fragment的商家就好了。
雖然情景有些僵硬,但是activity就是這樣將自己的責任和顯示區域交給fragment。而對于我們開發者來講,fragment所管理的顯示區域就應該通過oncreateView()和onViewCreated()這兩個方法來進行構造:
@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_a,container,false);return view;}@Overridepublic void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);Log.d(TAG, "onViewCreated: ");} 復制代碼onCreateView()一般用來初始化需要顯示的視圖,只需要將它進行返回就好,它不必被添加到所所傳入的container對象(add中所提供id的ViewGroup)中,其實如果被添加了,反而會報出View重復添加的錯誤。 onViewCreate()則被用來完成剩余的View初始化工作,會緊跟著被調用。
Fragment生命周期
按照慣例,我也先來上一張經典的生命周期圖:
如果按照正常的Framgent使用邏輯來看的話,Fragment將會按照上圖的順序進行執行,但是問題往往不止這么簡單,比如說,發生attach、hide、show等操作時,Fragment的生命周期該如何調用呢?
何為生命周期?我的理解是到了特定的時候(或特定的事件)去調用特定的方法,Activity的生命周期是由系統進行管理和調用的,但是Fragment的生命周期則是由托管的Activity進行統一的調用和管理。總之,Fragment依賴Activity,而Activity持有Fragment的引用和管理權限,一般來講,這種特殊身份都是由Activity所持有的內部FragmentManager對象而締造的(它的內部維護著持有各Fragment引用的列表)。《Android權威編程指南》一書中提到了一個很重要的概念:
在activity處于運行狀態時,添加fragment會發生什么呢?這種情況下,FragmentManager立 即驅趕fragment,調用一系列必要的生命周期方法,快速跟上activity的步伐(與activity的最新狀 態保持同步)。
或許在親自運行過demo后,能夠深有體會,不再贅述。
不同操作情況下的生命周期
之前看過很多博客,都有提到在不同transaction操作Fragment狀態 情況下,都會不同程度地對當前Fragment的生命周期產生影響,但是某些博主并沒有闡述清楚,而且憑借主觀臆測就下結論,極其容易給讀者們造成誤導,我在保證不出錯的情況下,還是建議大家能夠結合上傳的github源碼進行實際情況運行分析,親自得到結果,那么,在這一小節,我會展示Fragment生命周期變化的場景。
add()和remove()對應生命周期
如果進行add操作,將會完整地執行fragment生命周期的前半部分,如下:
@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.btn_fragmentA:mFragmentTransaction.add(R.id.fl_contrainer, mFragmentA).commit();break;case R.id.btn_fragmentB:mFragmentTransaction.add(R.id.fl_contrainer, mFragmentB).commit();break;case R.id.btn_fragmentC:mFragmentTransaction.add(R.id.fl_contrainer, mFragmentC).commit();break;}} 復制代碼在進行了add并commit事務過后,緊接著執行remove,會依次調用以下生命周期:
且每add不一樣的Fragment,這個Fragment也會按照自己定義的生命周期去執行,這并沒有什么難度,但是假設如果在FragmentA的oncreateView過程中去addFragmentB呢?直接看結果吧:
(相關代碼在demo中被注釋掉)如果你還記得我在上文小字中提到的“驅趕”一類的結論,你就會發現,這種奇葩的add情況,就是快速地初始化完Fragment,盡可能地趕上Activity地生命周期,是不是很奇妙? 當然,這里需要提醒的是,Fragment之中也會存在著相應的子Fragment管理類,獲取方法為getChildFragmentManager(),其余操作和Activity的Fragment管理類相同,切記。
replace()生命周期
既然是replace的操作,必然和兩個Fragment有關,demo中是FragmentA先被add,然后被FragmentB替換掉:
陪大家一起分析一下,從這個log可以看出兩個問題:
1.被替換的Fragment A將走完所有的生命周期,即被銷毀。
2.Fragment B的創建周期調用要早于FragmentA的銷毀周期調用。
首先,第一點,被替換的Fragment最終會被銷毀,第二點,為什么FragmentB的創建要早于FragmentA的銷毀呢?其實startActivity()也有類似的道理(先創建新Activity,再銷毀舊Activity),這是因為創建后再銷毀,可以避免出現視圖空白。
show()和hide()的生命周期
show和hide的前提是該Fragment已經被添加并且關聯,在此操作的基礎上,我們來研究它的生命周期變化:
hide:
show:
(字呢!!!!!) 我沒逗大家 = =,之所以沒有字,那是因為..... show和hide操作壓根就對Fragment生命周期沒影響!!!!!!!!!
show和hide操作壓根就對Fragment生命周期沒影響!!!!!!!!!
show和hide操作壓根就對Fragment生命周期沒影響!!!!!!!!!
重要的事情說三遍,over
detach和attach生命周期
detach會銷毀Fragment的視圖,但是并不會銷毀實例
同理,attach只是會恢復Fragment的視圖,并不會執行完整的create流程:
驚不驚喜,意不意外???
好了,基本的知識就介紹到這,更多的騷操作,可以自己查看代碼。
總結
Fragment的生命周期是關于Fragment最為重要的知識點之一,在實際的coding過程中,也極容易在這一塊內容翻跟頭,所以需要十分重視,本文先簡要地總結了一下Fragmnet所支持的基本操作,然后對各種操作下的生命周期變化情況進行了詳細的講解。
友情提示:運行github給出的代碼,點擊不同的按鈕可能會出現崩潰的情況,這是因為前置操作并未完成或者其他一些不允許的操作發生,建議大家自行查看崩潰日志,加深印象!
Github代碼
歡迎關注 我的博客
轉載于:https://juejin.im/post/5bacb9d3f265da0ae6774a16
總結
以上是生活随笔為你收集整理的Fragment系列总结(一)Fragment概念与生命周期的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android音乐播放器、多种架构综合应
- 下一篇: JavaCSV之写CSV文件