Отображение фрагментов с данными в ViewPager при повороте экрана - PullRequest
0 голосов
/ 17 октября 2018

Итак, в моем MainActivity OnCreate я создаю 3 фрагмента, каждый из которых заполнен разными данными.Затем я добавляю эти фрагменты в свой ViewPagerAdapter.

    ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
    MealsFragment exploreFragment = null;
    MealsFragment favoriteFragment = null;
    MealsFragment localFragment = null;

    //if there is no saved instance, create fragments with passed data as args and add them to the viewpageradapter
    if(savedInstanceState == null){
        exploreFragment = fetchExploreMealsDataAndCreateFragment();
        favoriteFragment = fetchFavoriteMealsDataAndCreateFragment();
        localFragment = fetchLocalMealsDataAndCreateFragment();
    }

    //add fragments to the adapter
    viewPagerAdapter.addFragment(exploreFragment, "EXPLORE");
    viewPagerAdapter.addFragment(favoriteFragment, "FAVORITES");
    viewPagerAdapter.addFragment(localFragment, "LOCAL");

    //set adapter to the viewpager and link it with the different tabs
    mviewPager.setAdapter(viewPagerAdapter);
    mtabLayout.setupWithViewPager(mviewPager);

3 различных метода выборки получают данные из API или БД, поэтому я не хочу вызывать эти методы каждый раз, когда поворачиваю экран и идучерез мой жизненный цикл.Вот почему я в первую очередь проверяю, является ли saveInstanceState нулевым.Но что происходит сейчас, так это то, что если мой saveInstanceState не равен NULL, фрагменты будут иметь значение NULL, поскольку я инициализировал их таким образом.

Видимо, это не проблема, поскольку при повороте экрана фрагменты остаются неизменными.Мне было интересно, что здесь происходит за кулисами, так как я не думаю, что это правильный способ справиться с моей ситуацией.Любые предложения по улучшению также приветствуются.

Заранее спасибо!

РЕДАКТИРОВАТЬ:

Забыл упомянуть, что ViewPagerAdapter является моей собственной реализацией FragmentPageAdapter

public class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> fragmentList = new ArrayList<>();
private final List<String> fragmentTitleList = new ArrayList<>();

public ViewPagerAdapter(FragmentManager fm) {
    super(fm);
}

@Override
public Fragment getItem(int i) {
    return fragmentList.get(i);
}

@Override
public int getCount() {
    return fragmentList.size();
}

@Nullable
@Override
public CharSequence getPageTitle(int position) {
    return fragmentTitleList.get(position);
}

public void addFragment(Fragment fragment, String title){
    fragmentList.add(fragment);
    fragmentTitleList.add(title);
}

}

1 Ответ

0 голосов
/ 17 октября 2018

Мне было интересно, что здесь происходит за кулисами

Хорошо, так что это будет связано с поиском источника для 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);

Преимущество этогоТаким образом, вы вызываете только методы «выборки и создания» по требованию, но при этом имеете возможность вызывать их после изменения конфигурации в ситуациях, когда они не были загружены до изменения конфигурации.

...