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 及以后方法会重新执行
- 并不会调用 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
主要还是上面两个方法,省略。