ViewPager源码解析之FragmentPagerAdapter和FragmentStatePagerAdapter

本文深入解析ViewPager与Fragment的交互,重点分析FragmentPagerAdapter和FragmentStatePagerAdapter的工作原理,包括它们如何管理Fragment的生命周期,以及在滑动时如何通过instantiateItem()和destroyItem()调整Fragment状态。文章通过实例验证了Fragment在ViewPager中的生命周期变化,展示了不同适配器在缓存和销毁Fragment时的区别。
摘要由CSDN通过智能技术生成

从FragmentPagerAdapter说起

我们经常使用的是ViewPager和Fragment的配合。

在第一篇中我们提到了如果ViewPager使用了FragmentPagerAdapter,ViewPager添加View的时机是在onMeasure()的populate()中。

//ViewPager.java
@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        ...
        // Make sure we have created all fragments that we need to have shown.
        populate();
        ...
    }

populate()会调用到addNewItem()来初始化所有需要缓存的页面信息。用到了ViewPagerAdapter的instantiateItem()。

    //ViewPager.java    
    ItemInfo addNewItem(int position, int index) {
        ItemInfo ii = new ItemInfo();
        ii.position = position;
        ii.object = mAdapter.instantiateItem(this, position);
        ii.widthFactor = mAdapter.getPageWidth(position);
        if (index < 0 || index >= mItems.size()) {
            mItems.add(ii);
        } else {
            mItems.add(index, ii);
        }
        return ii;
    }

以FragmentPagerAdapter为例,我们看下它的instantiateItem()。主要做了这么几件事:

1.开启Transaction

2.获得Fragment并做相应动作(可能是recreate后再FragmentManager中恢复的,也可能是第一次添加)

3.设置MenuVisibility和UserVisibleHint

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

        final long itemId = getItemId(position);

        //2
        String name = makeFragmentName(container.getId(), itemId);
        Fragment fragment = mFragmentManager.findFragmentByTag(name);
        if (fragment != null) {
            ...
            mCurTransaction.attach(fragment);
        } else {
            fragment = getItem(position);
           ...
            mCurTransaction.add(container.getId(), fragment,
                    makeFragmentName(container.getId(), itemId));
        }
        //3
        if (fragment != mCurrentPrimaryItem) {
            fragment.setMenuVisibility(false);
            fragment.setUserVisibleHint(false);
        }

        return fragment;
    }

之后ViewPager会在populate()中调用finishUpdate()提交事务,然后Fragment就交给了对应的FragmentManager管理,与Activity的生命周期同步。

//ViewPager.java
void populate(int newCurrentItem) {
    ...
  mAdapter.finishUpdate(this);
    ...
}

//FragmentPagerAdapter.java
    @Override
    public void finishUpdate(ViewGroup container) {
        if (mCurTransaction != null) {
            mCurTransaction.commitAllowingStateLoss();
            mCurTransaction = null;
            mFragmentManager.executePendingTransactions();
        }
    }

我们知道在Fragment和Activity生命周期同步的时候,会把自身的View添加到一个Container中,而这个Container就是在ViewPager。

之后对应的FragmentManager管理着所有Fragment的状态,如果ViewPager显示出来了,那么此时所有Fragment的状态是Resumed。也就是说所有缓存的Fragment的状态是和Activity同步的,不管它有没有作为ViewPager的主显示。

而ViewPager的滑动会通过FragmentPagerAdapter的instantiateItem()和destroyItem()造成个别Fragment的生命周期发生改变。

验证

我进行了简单的生命周期的验证,一个ViewPager下设置了4个Fragment(编号为1234),配合ViewPagerAdapter,默认缓存页面信息是1个,开始时页面在第1个。下面直接把Log信息贴上来。

图1是初始化的时候,由于缓存了1个页面信息,所以1和2会走相应的生命周期。(这里实在没有想清楚1和2的生命周期会交替进行,希望懂的朋友指点一下)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值