參考:java
Fragment 就是一個 Activity 佈局的一部分,能夠把 Activity 的一部分佈局抽離出來到 Fragment 中,而且 Fragment 也能夠執行邏輯。就是把 Activity 複雜的內容抽離成幾個碎片,而後拼湊起來,在 Activity 佈局中,只須要引入各個不一樣的 Fragment 就能夠 了。android
好比咱們常見的佈局,底部導航,而後每一個模塊對應不一樣的 Fragment。其實也是徹底能夠不使用 Fragment 的,一個頁面中包含各個模塊的佈局,而後經過點擊導航來決定隱藏哪些模塊。這樣寫的話一個 Activity 中的代碼邏輯會很是多,全部模塊都融合到一個 Activity 中了,至關冗餘,耦合。若是用 Fragment 就靈活多了,Activity 只須要根據導航顯示對應的 Fragment 就能夠了。markdown
若是別的地方須要某一個模塊,直接拿出對應的 Fragment 就能夠了。若是都寫在 Activity 中那抽離出來就費勁了,也增長了不肯定性。ide
再好比一個例子:網易新聞 手機端 和平板端。oop
平板端是新聞的標題和詳情都在一個頁面中。手機是詳情在單獨的一個頁面。這樣咱們就能夠將 標題 和 詳情寫成兩個 Fragment。充分利用了。佈局
Fragment
spa
具體的 Fragment.net
FragmentManager
code
是管理 Fragment 的orm
FragmentTransaction
經過事務來進行添加 Fragment、隱藏、移除 等操做 Fragment 動做,事務保證了原子性
transaction.add()
向 Activity 中添加 Fragment,只是添加 Fragment,不影響以前 Fragment 的聲明週期,這一點和 Activity 不同,Activity 會由於新 Activity 而走生命週期。而 .add
不會。假如 FragmentA 已經在 Activity 中了,這個時候啓動了 FragmentB,A 的生命週期是不會有任何變化的,仍是處於 onResume
,並不會由於 B
處於 onResume
而有影響。
transaction.remove()
從 Activity 中移除一個 Fragment
。若是這個 Fragment 沒有被添加到回退棧中,則實例被銷燬。若是添加到回退棧了,會執行 onDestroyView
實例並不會被銷燬。
transaction.replace()
使用 Fragment 替換當前,至關於先移除以前的 Fragment(remove()) 而後再 add()
transaction.hide()
隱藏當前 Fragment。僅僅是設爲不可見。不會銷燬
transaction.show()
顯示以前隱藏的 Fragment
detach()
會將 view 從 UI 中移除。和 remove 不一樣的是,此時 Fragment的狀態依然由 FragmentManager 維護
attach()
重建 view 視圖,附加到UI上顯示
.addToBackStack()
是將事務放入回退棧,能夠認爲一個事務中能夠有多個 Fragment .addToBackStack()
作的是將這個事務放入回退棧。
相似於咱們每添加一個 Activity 都會默認放入回退棧中,若是想要 Fragment 放入回退棧中,那麼就須要藉助啓動 Fragment 的事務了,調用事務的 .addToBackStack()
方法。
默認狀況下,按下返回鍵的時候的操做是從回退棧中彈出一個事務。
按下返回鍵的時候,是從返回棧中彈出一個事務(Fragment)。顯示棧頂的事務(對應的 Fragment)
若是當前棧頂的Fragment 已經執行過 destroyView
了,則會從新執行生命週期(從 createView
開始)
若是任務棧中只有一個Fragment,則此時按下返回鍵,進行的操做是把這個 Fragment 銷燬。
在 Fragment A 中啓動另外一個 Fragment B 這個時候 .addToBackStack()
是將 A 加入棧中。
// 直接在 xml 中添加
<fragment android:id="@+id/fragment" android:layout_width="match_parent" android:layout_height="200dp" android:name="com.syd.good.feature.fragment.fragment.FragmentMy" />
複製代碼
在代碼中獲取的這個 Fragment
經過
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment);
複製代碼
注意靜態添加 Fragment
的生命週期
E/FragmentMy: onAttach
E/FragmentMy: onCreate
E/FragmentMy: onCreateView
E/FragmentMy: onViewCreated
E/FragmentStaticActivity: onCreate()
E/FragmentMy: onActivityCreated
E/FragmentMy: onStart
E/FragmentStaticActivity: onStart()
E/FragmentStaticActivity: onResume()
E/FragmentMy: onResume
// 中止
E/FragmentMy: onPause
E/FragmentStaticActivity: onPause()
E/FragmentMy: onStop
E/FragmentStaticActivity: onStop()
E/FragmentMy: onDestroyView
E/FragmentMy: onDestroy
E/FragmentMy: onDetach()
E/FragmentStaticActivity: onDestroy()
複製代碼
動態添加,通常都會選擇加載到 FrameLayout
佈局上,是由於 FrameLayout
佈局足夠簡單,能夠減小沒必要要的佈局加載。
Fragment 的佈局只是附着在 FrameLayout
上,做爲 FrameLayout
的 子 View ,並無取代 FrameLayout
<FrameLayout android:id="@+id/fl" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" />
複製代碼
getSupportFragmentManager().beginTransaction()
.add(R.id.fl, new FragmentOne())
.add(R.id.fl, new FragmentTwo())
.commit();
複製代碼
Fragment 不管是不是全屏仍是一半的,執行生命週期都同樣
執行結果:
E/FragmentOne: onAttach
E/FragmentOne: onCreate
E/FragmentTwo: onAttach()
E/FragmentTwo: onCreate()
E/FragmentOne: onCreateView
E/FragmentOne: onViewCreated
E/FragmentOne: onActivityCreated
E/FragmentOne: onStart
E/FragmentOne: onResume
E/FragmentTwo: onCreateView
E/FragmentTwo: onActivityCreated
E/FragmentTwo: onStart
E/FragmentTwo: onResume
複製代碼
返回
E/FragmentOne: onPause
E/FragmentTwo: onPause
E/FragmentOne: onStop
E/FragmentTwo: onStop
E/FragmentOne: onDestroyView
E/FragmentOne: onDestroy
E/FragmentOne: onDetach()
E/FragmentTwo: onDestroyView
E/FragmentTwo: onDestroy
E/FragmentTwo: onDetach()
複製代碼
onHiddenChanged()
和普通的生命週期沒有關係,只是調用 hidden
的時候會調用而已。
經過上面 .add
的方式添加 Fragment
只是將 Fragment 添加到指定的佈局中,以後再添加 Fragment 是互相不影響的,在佈局上看 FrameLayout
有兩個子View(FragmentOne、FragmentTwo) 相互重疊。
主 Activity 中一次啓動兩個 Fragment ,並將這個事務加入到回退棧中。
getSupportFragmentManager().beginTransaction()
.add(R.id.fl, new FragmentOne())
.add(R.id.fl, new FragmentTwo())
.addToBackStack(null)
.commit();
複製代碼
這個時候按下返回鍵的結果是,從回退棧中彈出這個事務,意味這銷燬這兩個 Fragment
執行結果
Fragment 從 Activity 中脫離,留下 Activity
E/FragmentOne: onAttach
E/FragmentOne: onCreate
E/FragmentTwo: onAttach()
E/FragmentTwo: onCreate()
E/FragmentOne: onCreateView
E/FragmentOne: onViewCreated
E/FragmentOne: onActivityCreated
E/FragmentOne: onStart
E/FragmentOne: onResume
E/FragmentTwo: onCreateView
E/FragmentTwo: onActivityCreated
E/FragmentTwo: onStart
E/FragmentTwo: onResume
// 按下返回鍵
E/FragmentTwo: onPause
E/FragmentTwo: onStop
E/FragmentTwo: onDestroyView
E/FragmentTwo: onDestroy
E/FragmentTwo: onDetach()
E/FragmentOne: onPause
E/FragmentOne: onStop
E/FragmentOne: onDestroyView
E/FragmentOne: onDestroy
E/FragmentOne: onDetach()
複製代碼
假如沒有 addToBackStack()
的時候,按下返回鍵,則直接退出 Activity 了。
在上面的基礎上,在啓動的 FragmentTwo 中添加方法
tvAdd.setOnClickListener((view1) -> {
Log.e("add", "add");
getFragmentManager().beginTransaction()
.add(R.id.fl, new FragmentThree())
.commit();
});
複製代碼
這個時候只是在 fl
中又添加了一個 FragmentThree
,而且這個事務沒有加入到回退棧中,這個時候按下返回鍵,結果是:
頁面沒有發生任何改變,可是上一次保存在回退棧的事務被彈出了
E/FragmentTwo: onPause
E/FragmentTwo: onStop
E/FragmentTwo: onDestroyView
E/FragmentTwo: onDestroy
E/FragmentTwo: onDetach()
E/FragmentOne: onPause
E/FragmentOne: onStop
E/FragmentOne: onDestroyView
E/FragmentOne: onDestroy
E/FragmentOne: onDetach()
複製代碼
這個時候再按下返回鍵
Activity 就會被銷燬。
在例子1的基礎上,在添加 FragmentTwo 中添加方法
tvAdd.setOnClickListener((view1) -> {
Log.e("add", "add");
getFragmentManager().beginTransaction()
.add(R.id.fl, new FragmentThree())
// 添加了將此事務入棧
.addToBackStack(null)
.commit();
});
複製代碼
這個時候再按下返回鍵,是將這個棧頂的事務退出,這個時候例子1 中的事務就處於棧頂了。頁面顯示的就是例子1中的頁面了。
再次按下返回鍵,是把例子1中的事務彈出,這個時候留下的就只有 Activity 了,再次按下返回鍵,彈出 Activity。
getFragmentManager.findFragmentByTag() 或者 findFragmentById()
獲取getActivity
獲取當前綁定的 Activity 實例Fragment 不該該直接操做其餘的 Fragment。應該由管理者 Activity 來進行。
採用接口回調的形式
凡是加入了回退棧 .addToBackStack(null)
以前加入的 Fragment 都不會被銷燬。
好比:
Activity A 中
getSupportFragmentManager().beginTransaction()
.add(R.id.fl, new FragmentOne())
.add(R.id.fl, new FragmentTwo())
.commit();
複製代碼
FragmentTwo 中
getSupportFragmentManager().beginTransaction()
.replace(R.id.fl, new FragmentThree())
.addToBackStack(null)
.commit();
複製代碼
請注意 Activity A 中是沒有 addToBackStack 的 ,即便這樣在 FragmentTweo
中 replace
後 FragmentOne
和 FragmentTwo
也不會被銷燬,而是走 onDestroyView()
方法。按下返回鍵後,恢復 FragmentOne
和 FragmentTwo
從 onCreateView
開始
若是沒有 .addToBackStack(null)
的話,那麼 FragmentOne
和 FragmentTwo
就會被銷燬了。而且按下返回鍵的時候,就銷燬掉 Activity 了。
頁面1 addTo
頁面2 沒有
E/FragmentThree: onAttach() E/FragmentThree: onCreate() E/FragmentTwo: onPause E/FragmentTwo: onStop E/FragmentTwo: onDestroyView E/FragmentOne: onPause E/FragmentOne: onStop E/FragmentOne: onDestroyView E/FragmentThree: onCreateView E/FragmentThree: onActivityCreated E/FragmentThree: onStart E/FragmentThree: onResume E/FragmentTwo: onDestroy E/FragmentTwo: onDetach() E/FragmentOne: onDestroy E/FragmentOne: onDetach()