Мне было интересно, что здесь происходит за кулисами
Хорошо, так что это будет связано с поиском источника для FragmentPagerAdapter
.Важна реализация метода instantiateItem()
... хотя на самом деле это только его часть.
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int 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));
}
[...]
}
По сути, метод getItem()
из вашего ViewPagerAdapter
вызывается только один раз для каждой позиции.в течение всего срока действия (даже при изменениях конфигурации).Каждый раз, кроме первого, объект Fragment
извлекается непосредственно из FragmentManager
в отличие от адаптера.
Так что да, для всех воссозданий вашей Деятельности ваш адаптер содержит List<Fragment>
это просто null
, null
, null
... но это не важно, потому что к этому списку снова нет доступа.
HOWEVER
Приведенные выше утверждения предполагают, что каждый фрагмент в вашем адаптере был создан и добавлен к FragmentManager
до изменения вашей конфигурации, и это не обязательно гарантировано.
По умолчанию ограничение на количество страниц за пределами экрана для ViewPager
составляет 1
.Это означает, что ваша третья страница (ваша localFragment
) не обязательно добавляется к ViewPager
и, следовательно, FragmentManager
при первом запуске.Если вы перейдете на следующую страницу хотя бы один раз, это произойдет, но это не обязательно так.
Или, возможно, вы вручную установили ограничение для экранных страниц равным 2
, и в этом случаевсе страницы / фрагменты будут добавлены немедленно.
Вероятно, лучшее, что нужно сделать, это изменить то, как вы используете FragmentPagerAdapter
в целом.Я бы поместил это в ваш Activity
как внутренний класс:
private class ExampleAdapter extends FragmentPagerAdapter {
public ExampleAdapter() {
super(getSupportFragmentManager());
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0: return fetchExploreMealsDataAndCreateFragment();
case 1: return fetchFavoriteMealsDataAndCreateFragment();
case 2: return fetchLocalMealsDataAndCreateFragment();
default: throw new IllegalArgumentException("unexpected position: " + position);
}
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0: return "EXPLORE";
case 1: return "FAVORITES";
case 2: return "LOCAL";
default: throw new IllegalArgumentException("unexpected position: " + position);
}
}
@Override
public int getCount() {
return 3;
}
}
И тогда ваш onCreate()
может быть изменен на:
FragmentPagerAdapter viewPagerAdapter = new ExampleAdapter();
mviewPager.setAdapter(viewPagerAdapter);
mtabLayout.setupWithViewPager(mviewPager);
Преимущество этогоТаким образом, вы вызываете только методы «выборки и создания» по требованию, но при этом имеете возможность вызывать их после изменения конфигурации в ситуациях, когда они не были загружены до изменения конфигурации.