fragment+viewpager+FragmentPagerAdapter使用随记

首先给个别人写的比较好用的封装,可实现懒加载并且保证数据只加载一次。

public abstract class BasePageFragment extends Fragment {

    protected boolean isViewInitiated;
    protected boolean isVisibleToUser;
    protected boolean isDataInitiated;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        isViewInitiated = true;
        prepareFetchData();
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        this.isVisibleToUser = isVisibleToUser;
        prepareFetchData();
    }

    public abstract void fetchData();

    public boolean prepareFetchData() {
        return prepareFetchData(false);
    }

    public boolean prepareFetchData(boolean forceUpdate) {
        /**
         * 当前UI可见,并且fragment已经初始化完毕,如果网络数据未加载,那么请求数据,或者需要强制刷新页面,那么也去请求数据,
         * Fragment只刷新一次,这个问题只要手动调用prepareFetchData(),传true即可强制刷新了
         */
        if (isVisibleToUser && isViewInitiated && (!isDataInitiated || forceUpdate)) {
            fetchData();
            isDataInitiated = true;
            return true;
        }
        return false;
    }
}

而今天主要讨论的是一个有趣的点,那就是FragmentPagerAdapter在做销毁处理时的特点(因为我在使用这个基类的时候发现我每次在多个滑动页情况下,返回过来我的页面数据还能存在,可是不应该被销毁了吗?)。我们知道普通的adapter在做销毁的时候会把整个view销毁掉(前提是你在destroyItem中做了处理),当然FragmentPagerAdapter也做了销毁处理,不过这里要注意的是,它销毁的仅仅只是当前的view而已,注意“而已”!!!看源码

@Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
        if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
                + " v=" + ((Fragment)object).getView());
        mCurTransaction.detach((Fragment)object);
    }

注意这里的最后一行代码的detach方法,那么它做了什么呢?继续源码

/**
     * Detach the given fragment from the UI.  This is the same state as
     * when it is put on the back stack: the fragment is removed from
     * the UI, however its state is still being actively managed by the
     * fragment manager.  When going into this state its view hierarchy
     * is destroyed.
     *
     * @param fragment The fragment to be detached.
     *
     * @return Returns the same FragmentTransaction instance.
     */
    public abstract FragmentTransaction detach(Fragment fragment);

看注释我们注意这句话:

however its state is still being actively managed by the fragment manager

它的意思是这个fragment在管理器中始终处于活跃状态,也就是说里面定义的变量什么的都还是存在的,并不会被销毁。所以当你下次回来的时候这些变量依然可以被使用,所以变量的初始化(比如从网络拉取的数据)应该放在封装类的抽象方法中做,这样第二次回来的时候以前的数据是可以被重用。


------------------------------------------------分割线------------------------------------------------------

再来详细说说FragmentPagerAdapter这个类的一些特点吧,这里主要探究的是它的生成特点(销毁的上面说过了)看源码:

@Override
    public Object instantiateItem(ViewGroup container, int position) {
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }

        final long itemId = getItemId(position);

        // Do we already have this fragment?
        String name = makeFragmentName(container.getId(), itemId);
        Fragment fragment = mFragmentManager.findFragmentByTag(name);
        if (fragment != null) {
            if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
            mCurTransaction.attach(fragment);
        } else {
            fragment = getItem(position);
            if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
            mCurTransaction.add(container.getId(), fragment,
                    makeFragmentName(container.getId(), itemId));
        }
        if (fragment != mCurrentPrimaryItem) {
            fragment.setMenuVisibility(false);
            fragment.setUserVisibleHint(false);
        }

        return fragment;
    }
这里我们看到

第3行代码,首先判断mCurTransaction是否为空。

第7行代码,获取当前的id号,接下来构造name,这个name主要作为一个tag标记丢给FragmentManager使用。

第11行代码,通过findFragmentByTag(name)获取fragment并判断是否为空。

第14行代码,如果不为空则直接通过attach(与detach方法对应)方法绘制fragment展现到屏幕上。

第16行代码,如果为空,则调用getItem方法,注意这个方法就是我们在继承FragmentPagerAdapter方法是重写的那个重要方法。然后通过add方法把这个fragment放到fragment管理器中,这里我们可以思考一个点,这个fragment管理器是通过构造函数传进来的,那么我们在外部是否也可以获取到这个fragment呢?

好了,关键代码分析完了,从代码可以看出来,其实这些frgment本身已经达到了很好的重用效果,而它们在滑动过程中的创建销毁其实只是针对view进行的,从这一点看,很多人在外部利用一个list来维护fragment的做法并不可取,因为源码通过fragment管理器已经做到了很好的管理。如果你不信,可以在if判断中打断点试一试,只有第一次创建的时候会进入else进而调用getItem方法,之后,都直接进入if语句执行。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值