Fragment的Adapter分析及懶加載

Viewpager與fragment的組合在項目中使用的頻率過高,咱們對Viewpager的兩種的Adapter的處理方式略顯不足增強一下認識。緩存

先簡單看看Fragment的兩種Adapter的使用方式。
都是PagerAdapter的子類。 bash

1:FragmentStatePagerAdapter
2:FragmentPagerAdapter複製代碼

當Viewpager.setAdapter(),Viewpager與PagerAdapter創建雙向的聯繫。
1)Viewpager會擁有pagerAdapter的對象,能getAdapter獲取到當前的Adapter。
2)mAdapter.setViewPagerObserver(new PagerObserver),至此獲得adapter中的註冊測,能向Viewpager傳遞數據。這樣就算綁在一塊兒了。
ide


注意:調用pagerAdapter.notifDataSerChange()觸發時,ViewPager.dataSetChanged()也會被調用。該函數使用Adapter中的getitemposition()返回值來進行判斷。

一,PagerAdapter

這是咱們經常使用兩種Adapter的基類。這是一個abstract的,直接繼承他的話我麼須要重寫方法
1)getItemPosition();
//instantiateItem()的返回值將有此函數的返回值進行判斷,是否進行調用。函數

public static final int POSITION_UNCHANGED = -1;
     public static final int POSITION_NONE = -2;複製代碼

如若不重寫,默認返回POSITION_UNCHANGED,將不會調用Viewpager的observer.notifit()
所以,調用Adapter.notifyDataSetChanged()將不會出現什麼改變。
佈局


//後面這三個方法,直接照着官方文檔書寫就行!
2)instantiateItem();
3) getCount();
4) isViewFromObject();
5) destroyItem();

二,FragmentStatePagerAdapter

/**ui

  • FragmentStatePagerAdapter 和前面的 FragmentPagerAdapter 同樣,是繼承子 PagerAdapter。
  • 但和 FragmentPagerAdapter 不同的是,
  • 正如其類名中的 'State' 所代表的含義同樣,
  • 該 PagerAdapter 的實現將只保留當前頁面,
  • 當頁面離開視線後,就會被消除,釋放其資源;
  • 而在頁面須要顯示時,生成新的頁面(就像 ListView 的實現同樣)。
  • 這麼實現的好處就是當擁有大量的頁面時,沒必要在內存中佔用大量的內存。
    */
    重寫方法:
    1)getItem()
    生成須要的Fragment的對象。Fragment.setArgument()這種只會在新建Fragment時執行一次的傳遞參數放在這裏。
    2)instantiateItem()
    除非碰到FragmentManger恰好從Savedstate 中恢復了對應Fragment的狀況外,都將調用getItem()來生成新的對象。
    mFragmentManager.beginTransaction().add(container.getId(), fragment);
    3)destoryItem()
    將Fragment移除。
    mFragmentManager.beginTransaction().remove(fragment);

三,FragmentPagerAdapter

/**spa

  • 該類內的每個生成的 Fragment 都將保存在內存之中,
  • 所以適用於那些相對靜態的頁,數量也比較少的那種;
  • 若是須要處理有不少頁,而且數據動態性較大、佔用內存較多的狀況,
  • 應該使用FragmentStatePagerAdapter。
    */
    重寫方法
    1)getItem();
    只會在第一次初始化的時候地調用,每次都會查找一下是否有當前Fragment生成過。生成了就不調用getItem的方法。
    2)instantiateItem();
    判斷一下要生成的Fragment是否已經生成過了,若是生成了,調用mFragmentManager.beginTransaction().attch(fragment);
    若是沒有
    mFragmentManager.beginTransaction().add(container.getId(), fragment,makeFragmentName(container.getId(), itemId));

    3)destoryItem()
    mFragmentManager.beginTransaction().detach()。
    這裏並不會remove(),所以Fragment還在Fragmentmanager管理中,Fragment所佔用的資源不會釋放。

上訴兩個Adapter 對Fragment的生命週期的最大的不一樣 FragmentStatePagerAdapter是銷燬重走全部生命走起 onAttach - onDetach

FragmentPagerAdapter 是從onCreateView - onDestroyView 然而成員不銷燬,所以咱們有些會出現一些數據錯亂的時候。(這裏咱們能夠判斷當前的View是否已經加載過了)

if(rootView==null){  
       rootView=inflater.inflate(R.layout.tab_fragment, null);  
   }  
  //緩存的rootView須要判斷是否已經被加過parent, 若是有parent須要從parent刪除,要否則會發生這個rootview已經有parent的錯誤。  
   ViewGroup parent = (ViewGroup) rootView.getParent();  
   if (parent != null) {  
       parent.removeView(rootView);  
   }  複製代碼

四,生命週期的見解

這裏重點說明一下:setUserVisibleHint 調用 在全部生命週期以前執行。每次Adapter切換都會調用相應的Fragment的此方法。
思路也就來了。 實現的思路不少種,仔細看這個生命週期,總結規律,這個懶加載也就現實了。3d

`public abstract class LazzyFragment extends Fragment {
//判斷控件是否加載完畢
private boolean isCreateView = false;
//判斷是否已加載過數據
public boolean isLoadData = false;

/**
 * 返回layoutView
 * @param inflater
 * @param container
 * @return  初始化佈局文件
 */
public abstract View getView(LayoutInflater inflater, ViewGroup container);

/**
 * 初始化控件
 */
public abstract void initViews(View view);

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = getView(inflater, container);
    initViews(view);
    isCreateView = true;
    return view;
}


//注意,此方法再全部生命週期以前調用,不可操做控件
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser && isCreateView && !isLoadData) {
        loadData();
    }

}


/**
 * 加載數據
 */
public void loadData() {
    //若是沒有加載過就加載,不然就再也不加載了
    if (!isLoadData) {
        //加載數據操做
        isLoadData = true;
    }
}

// 第一次進入ViewPager的時候咱們須要直接加載,由於此時setUserVisibleHint 已經調用過了。
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    if (getUserVisibleHint())
        loadData();
}複製代碼

}`code

相關文章
相關標籤/搜索