第四章 Fragment專題

weixin_34120274發表於2018-12-21

一、Fragment的第五大元件

1.Fragment的載入方式

  • 靜態載入
    直接在xml佈局中新增Fragment
<fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  • 動態載入
    Fragment的動態載入是由Fragment事務驅動,Fragment事務就是:對Fragment進行新增、移除、替換或執行其它動作,提交給Activity的每一個變化;
    新增:add() 、移除:remove()、替換:replace()、提交事務:commit()等方法
FragmentManager fragmentManager=getSupportFragmentManager();
fragmentManager.beginTransaction().add(new Fragment(), "TAG").commit();
fragmentManager.beginTransaction().remove(new Fragment()).commit();
// Fragment中巢狀Fragment
getChildFragmentManager().beginTransaction().remove(rescueChatFragment).commitAllowingStateLoss();

2.FragmentPagerAdapter與FragmentStatePagerAdapter

  • setOffScreenPageLimit(int limit)設定viewpager左右預載入頁
  • FragmentPagerAdapter:將每一個生成的Fragment儲存在記憶體中,limit外Fragment沒有銷燬,生命週期為onPause>onStop>onDestroyView,onCreateView->onStart->onResume,但Fragment的成員變數都沒有變,所以可以快取根View,避免重複inflate
  • FragmentStatePagerAdapter:對limit外的Fragment銷燬,生命週期為onPause->onStop->onDestoryView->onDestory->onDetach, onAttach->onCreate->onCreateView->onStart->onResume。

使用場景:對於需要快取在記憶體中的固定較少數量的靜態頁面使用FragmentPagerAdapter,如引導頁,Tab頁面;對於擁有大量頁面的情況應使用FragmentStatePagerAdapter避免佔用大量記憶體,如圖片預覽

二、Fragment的生命週期

1400737-b10457a64f402f13.png
1354170699_6619.png

三、Fragment的通訊方式

  • Fragment獲取它所在的Activity,通過getActivity()強制轉換呼叫Activity中的方法。
((HomeActivity) context).onStartProgress();
((HomeActivity) context).onStopProgressError();
  • Activity獲取它所包含的Fragment資訊
// Activity中
getSupportFragmentManager().beginTransaction().add(R.id.flSpotChat, spotChatFragment).commit()
// Fragment巢狀
getChildFragmentManager().beginTransaction().add(R.id.flRescueChat, rescueChatFragment).commitAllowingStateLoss();
  • Activity想Fragment中添傳遞資料
    setArguments(Bundle bundle)
  • Fragment中定義內部回撥介面,Activity中註冊
 public interface OnSosWhoCheckListener {
        /**
         * 3:為自己呼救 1.為其他人呼救
         *
         * @param sosWho
         */
        void onCheck(String sosWho);
    }

    private OnSosWhoCheckListener onSosWhoCheckListener;

    public SpotSosDialogFragment setOnSosWhoCheckListener(OnSosWhoCheckListener onSosWhoCheckListener) {
        this.onSosWhoCheckListener = onSosWhoCheckListener;
        return this;
    }
spotSosDialogFragment = new SpotSosDialogFragment()
                .setBundle(bundle)
                .setOnSosWhoCheckListener(sosWho -> {
                    SpotFragment.this.sosWho = sosWho;
                    SpotFragment.this.sosType = "1";
                }).setOnContractListener(contractors -> {
                    SpotFragment.this.contractors = contractors;
                    SpotFragment.this.sosType = "2";
                });

四、Fragment的切換方式

1.通過fragment中的事務 add(),replace(),remove()等操作
2.通過Fragment的hide(),show()來顯示
3.通過Fragment的detach()&attach()來分離Activity

區別:第一種方式是直接銷燬例項,建立和新增都有些影響效能,第二種是不銷燬例項和檢視,仍然佔用記憶體,第三種是不銷燬例項,但銷檢視,重新載入onCreateView。

五、Fragment的懶載入

1.ViewPager為什麼要懶載入,什麼情況適用

ViewPager的setOffScreenPageLimit()方法預設limit為1,既會預載入左右頁面,而為了節省流量,理想情況是當使用者切換到該介面時才會呼叫網路請求獲取資料。相關方法為setUserVisibleHint(),當前頁面為true,預載入頁面為false,只有Fragment從可見到不可見或者從不可見到可見時會呼叫,Fragment初次建立時setUserVisibleHint先於onCreateView()呼叫,所以可以由此判斷Fragment是否初始建立。
ViewPager首次顯示的頁面經過方法呼叫
->setUserVisibleHint(false)
->setUserVisibleHint(true)
->onCreateView()...,所以該頁面的資料載入放在onCreateView中;其它預載入頁面預載入時setUserVisibleHint(false)
->onCreateView()...,當選中該頁面顯示時呼叫setUserVisibleHint(true),所以預載入頁面資料載入放在setUserVisibleHint中。

2.注意事項

果想通過adapter.notifyDataSetChanged來重新整理頁面時,必須繼承FragmentStatePagerAdapter,因為FragmentPagerAdapter會快取Fragment,不會走getItem方法,同時將所要重新整理頁面的getItemPosition返回POSITION_NONE

相關文章