FragmentPagerAdapter

288 阅读1分钟

ViewPager

会以当前 item 为中心,根据 offset 加载若干 Item,超出范围的 item 会调用 PagerAdapter#destroyItem() 进行销毁。主要逻辑在 ViewPager#populate() 中。

如果范围中某个 item 不存在,会调用 addNewItem() 进行添加:

ItemInfo addNewItem(int position, int index) {
    ItemInfo ii = new ItemInfo();
    ii.position = position;
    // 调用 instantiateItem
    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;
}

从 instantiateItem() 的调用可以看出为什么我们需要手动调用 addView()。因为 ViewPager 并不负责将返回结果添加到 ViewPager 中,而且该方法返回的是 Object。

FragmentPagerAdapter

保留 frg 实例,但 onCreatView 及以后方法会重新执行

  1. 并不会调用 Frg#onSaveInstanceState() 方法,所以类名中不带 state

原理主要看两个方法

public Object instantiateItem(@NonNull 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);
    // 先从 fm 中查找
    Fragment fragment = mFragmentManager.findFragmentByTag(name);
    if (fragment != null) {
        // 如果 frg 存在,就直接 attach。
        mCurTransaction.attach(fragment);
    } else {
        // 否则通过 getItem() 获取 frg 实例
        fragment = getItem(position);
        // 拿到实例后 add 进去
        mCurTransaction.add(container.getId(), fragment,
                makeFragmentName(container.getId(), itemId));
    }
    // ...
    return fragment;
}

@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
    Fragment fragment = (Fragment) object;

    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }
    // detach 掉。这里并没有 remove,所以 frg 的实例依旧存在
    mCurTransaction.detach(fragment);
}

FragmentStatePagerAdapter

不保留 frg 实例,但会保留 frg 的 state

主要还是上面两个方法,省略。