Fragment全解析系列(二):正確的使用姿勢

Fragment系列文章:
1、Fragment全解析系列(一):那些年踩過的坑
2、Fragment全解析系列(二):正確的使用姿勢
3、Fragment之我的解決方案:Fragmentation

本篇主要介紹一些Fragment使用技巧。


Fragment是可以讓你的app縱享絲滑的設計,如果你的app想在現在基礎上性能大幅度提高,并且占用內存降低,同樣的界面Activity占用內存比Fragment要多,響應速度Fragment比Activty在中低端手機上快了很多,甚至能達到好幾倍!如果你的app當前或以后有移植平板等平臺時,可以讓你節省大量時間和精力。


簡陋的目錄
1、一些使用建議
2、add(), show(), hide(), replace()的那點事
3、關于FragmentManager你需要知道的
4、使用FragmentPagerAdapter+ViewPager的注意事項
5、是使用單Activity+多Fragment的架構,還是多模塊Activity+多Fragment的架構?


作為一個穩定的app,從后臺且回到前臺,一定會在任何情況都能恢復到離開前的頁面,并且保證數據的完整性。

如果你沒看過本系列的第一篇,為了方便后面文章的介紹,先規定一個“術語”,安卓app有一種特殊情況,就是 app運行在后臺的時候,系統資源緊張的時候導致把app的資源全部回收(殺死app的進程),這時把app再從后臺返回到前臺時,app會重啟。這種情況下文簡稱為:“內存重啟”。(屏幕旋轉等配置變化也會造成當前Activity重啟,本質與“內存重啟”類似)
<h1 id="1"> 1、一些使用建議 </h1>

1、對Fragment傳遞數據,建議使用setArguments(Bundle args),而后在onCreate中使用getArguments()取出,在 “內存重啟”前,系統會幫你保存數據,不會造成數據的丟失。和Activity的Intent恢復機制類似。

2、使用newInstance(參數) 創建Fragment對象,優點是調用者只需要關系傳遞的哪些數據,而無需關心傳遞數據的Key是什么。

3、如果你需要在Fragment中用到宿主Activity對象,建議在你的基類Fragment定義一個Activity的全局變量,在onAttach中初始化,這不是最好的解決辦法,但這可以有效避免一些意外Crash。詳細原因參考第一篇的“getActivity()空指針”部分。

protected Activity mActivity;
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    this.mActivity = activity;
}

<h1 id="2">2、add(), show(), hide(), replace()的那點事</h1>
1、區別
show()hide()最終是讓Fragment的View setVisibility(true還是false),不會調用生命周期;

replace()的話會銷毀視圖,即調用onDestoryView、onCreateView等一系列生命周期;

add()replace()不要在同一個階級的FragmentManager里混搭使用。

2、使用場景
如果你有一個很高的概率會再次使用當前的Fragment,建議使用show()hide(),可以提高性能。

在我使用Fragment過程中,大部分情況下都是用show()hide(),而不是replace()

注意:如果你的app有大量圖片,這時更好的方式可能是replace,配合你的圖片框架在Fragment視圖銷毀時,回收其圖片所占的內存。

3、onHiddenChanged的回調時機
當使用add()+show(),hide()跳轉新的Fragment時,舊的Fragment回調onHiddenChanged(),不會回調onStop()等生命周期方法,而新的Fragment在創建時是不會回調onHiddenChanged(),這點要切記。

4、Fragment重疊問題
使用show()hide()帶來的一個問題就是,如果你不做任何額外處理,在“內存重啟”后,Fragment會重疊;(該BUG在support-v4 24.0.0+以上 官方已修復)

有些小伙伴可能就是為了避免Fragment重疊問題,而選擇使用replace(),但是使用show()hide()時,重疊問題很簡單解決的:

<h1 id="3">3、關于FragmentManager你需要知道的</h1>
FragmentManager棧視圖:
(1)每個Fragment以及宿主Activity(繼承自FragmentActivity)都會在創建時,初始化一個FragmentManager對象,處理好Fragment嵌套問題的關鍵,就是理清這些不同階級的棧視圖。

下面給出一個簡要的關系圖

棧關系圖.png

(2)對于宿主Activity,getSupportFragmentManager()獲取的FragmentActivity的FragmentManager對象;

對于Fragment,getFragmentManager()是獲取的是父Fragment(如果沒有,則是FragmentActivity)的FragmentManager對象,而getChildFragmentManager()是獲取自己的FragmentManager對象。

<h1 id="4">4、使用FragmentPagerAdapter+ViewPager的注意事項</h1>

  • 使用FragmentPagerAdapter+ViewPager時,切換回上一個Fragment頁面時(已經初始化完畢),不會回調任何生命周期方法以及onHiddenChanged(),只有setUserVisibleHint(boolean isVisibleToUser)會被回調,所以如果你想進行一些懶加載,需要在這里處理。

  • 在給ViewPager綁定FragmentPagerAdapter時,
    new FragmentPagerAdapter(fragmentManager)的FragmentManager,一定要保證正確,如果ViewPager是Activity內的控件,則傳遞getSupportFragmentManager(),如果是Fragment的控件中,則應該傳遞getChildFragmentManager()。只要記住ViewPager內的Fragments是當前組件的子Fragment這個原則即可。

  • 你不需要考慮在“內存重啟”的情況下,去恢復的Fragments的問題,因為FragmentPagerAdapter已經幫我們處理啦。

<h1 id="5">5、是使用單Activity+多Fragment的架構,還是多模塊Activity+多Fragment的架構?</h1>
單Activity+多Fragment:
一個app僅有一個Activity,界面皆是Frament,Activity作為app容器使用。

優點:性能高,速度最快。參考:新版知乎 、google系app

缺點:邏輯比較復雜,尤其當Fragment之間聯動較多或者嵌套較深時,比較復雜。

多模塊Activity+多Fragment:
一個模塊用一個Activity,比如
1、登錄注冊流程:
LoginActivity + 登錄Fragment + 注冊Fragment + 填寫信息Fragment + 忘記密碼Fragment
2、或者常見的數據展示流程:
DataActivity + 數據列表Fragment + 數據詳情Fragment + ...

優點:速度快,相比較單Activity+多Fragment,更易維護。

我的觀點:
權衡利弊,我認為多模塊Activity+多Fragment是最合適的架構,開發起來不是很復雜,app的性能又很高效。

當然。Fragment只是官方提供的靈活組件,請優先遵從你的項目設計!真的特別復雜的界面,或者單個Activity就可以完成一個流程的界面,使用Activity可能是更好的方案。

最后

如果你讀完了第一篇和這篇文章,那么我相信你使用多模塊Activity+多Fragment的架構所遇到的坑,大部分都應該能找到解決辦法。

但是如果流程較為復雜,比如Fragment A需要啟動一個新的Fragment B并且關閉當前A,或者A啟動B,B在獲取數據后,想在返回到A時把數據交給A(類似Activity的startActivityForResult),又或者你保證在Fragment轉場動畫的情況下,使用pop(tag\id)從棧內退出多個Fragment,或者你甚至想Fragment有一個類似Activity的SingleTask啟動模式,那么你可以參考下一篇,我的解決方案庫,Fragmentation。它甚至提供了一個讓你在開發時,可以隨時查看所有階級的棧視圖的UI界面。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內容