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

相关文章
相关标签/搜索