Замените фрагмент в Viewpager (notifyDataSetChanged не работает)

Моя MainActivity содержит viewPager.

В MainActivity.java я установил адаптер для viewpager. Адаптер расширяет FragmentStatePagerAdapter. Фрагмент, который я хочу заменить, — это cameraFragment. Поэтому, когда пользователь нажимает кнопку переключения камеры, я хочу теперь показать фрагмент камеры, на этот раз с включенной фронтальной камерой.

Нажав кнопку переключения камеры, я удаляю фрагмент из массива фрагментов, которые я передал пользовательскому адаптеру. Я добавляю новый фрагмент и вызываю notifydatasetchanged. Однако это не приводит к добавлению нового фрагмента. Как добиться динамической замены фрагментов в пейджере просмотра, который поддерживается моим настраиваемым адаптером пейджера состояния фрагмента? Код :

mainPageFragments = new ArrayList<>();
mainPageFragments.add(new ResultsFragment_());
mainPageFragments.add(DemoCameraFragment_.newInstance(false));
pagerAdapter = new MainViewPagerAdapter(getSupportFragmentManager(),mainPageFragments);

Чтобы заменить фрагмент: при получении соответствующего события я делаю,

mainPageFragments.remove(1);
    if (event.getCameraState().equals(CameraSwitchButton.CameraTypeEnum.BACK)) {
        mainPageFragments.add(DemoCameraFragment.newInstance(false));
    } else {
        mainPageFragments.add(DemoCameraFragment.newInstance(true));

    }
    // Not Working...
    pagerAdapter.notifyDataSetChanged();

Код адаптера:

public class MainViewPagerAdapter extends FragmentStatePagerAdapter {

ArrayList<Fragment> fragmentsArray;

public MainViewPagerAdapter(FragmentManager fm, ArrayList<Fragment> fragmentsArray) {
    super(fm);
    this.fragmentsArray = fragmentsArray;
}

@Override
public Fragment getItem(int position) {
    return fragmentsArray.get(position);
}

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

@Override
public int getItemPosition(Object object) {
    return super.getItemPosition(object);
}
}

comment
опубликуйте код, что вы сделали   -  person Mano    schedule 30.06.2015
comment
@Мано. Любые мысли о том, как обновить/заменить фрагмент? Явно что-то упускаю. Я не хочу сбрасывать адаптер. Это кажется дорогостоящей операцией (если количество страниц/фрагментов увеличивается. Кроме того, мне нужно заменить только один фрагмент, поэтому повторное создание каждого другого не имеет никакого смысла.   -  person Rohan    schedule 30.06.2015
comment
Пожалуйста, опубликуйте также код для MainViewPagerAdapter.   -  person Okas    schedule 30.06.2015
comment
@Окас. Обновил его с помощью MainViewPagerAdapter.   -  person Rohan    schedule 30.06.2015


Ответы (2)


Ваш MainViewPagerAdapter.getItemPosition является причиной вашей проблемы.

Реализация по умолчанию всегда возвращает POSITION_UNCHANGED. Чтобы пейджер удалил ваш фрагмент, вы должны вернуть PagerAdapter.POSITION_NONE для удаленных фрагментов.

Кроме того, ваш текущий дизайн противоречит идее FragmentStatePagerAdapter. Из документации FragmentStatePagerAdapter: "Эта версия пейджера более полезен, когда имеется большое количество страниц, работает больше как представление списка.Когда страницы не видны пользователю, весь их фрагмент может быть уничтожен, сохраняя только сохраненное состояние этого фрагмента.Это позволяет пейджеру хранить на гораздо меньший объем памяти, связанный с каждой посещенной страницей, по сравнению с FragmentPagerAdapter за счет потенциально больших накладных расходов при переключении между страницами».

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

person Okas    schedule 30.06.2015
comment
Даже если бы я реализовал адаптер таким образом, как мне заменить фрагмент? Я уже читал о реализации getItemPosition по умолчанию. Причина, по которой я выбрал FragmentStatePageAdapter, заключается в том, что есть большая вероятность, что количество страниц в viewpager увеличится. Я до сих пор не могу понять, что мне делать в методе getItemPosition, чтобы решить мою проблему. Спасибо. - person Rohan; 30.06.2015
comment
Вы должны отдельно отслеживать, какие фрагменты вы хотите сохранить, а какие удалить. Затем, когда что-то изменится, вы должны вызвать notifyDataSetChanged(). Затем Pager вызовет метод getItemPosition вашего адаптера. Вы должны вернуть POSITION_NONE для тех, кого хотите удалить, а затем пейджер удалит их за вас. - person Okas; 30.06.2015
comment
Спасибо @Окас. Я внес изменения на основе вашего сообщения и разместил ответ ниже. - person Rohan; 30.06.2015

Благодаря @Okas. Я внес следующее изменение в getItemPosition в моем подклассе FragmentStatePagerAdapter.

@Override
 public int getItemPosition(Object object) {
    if (object instanceof DemoCameraFragment_)
        return POSITION_NONE;
    return super.getItemPosition(object);
}

Я добавил журналы в OnCreate обоих моих фрагментов, чтобы подтвердить, воссоздаются они или нет. По моему требованию воссоздается только второй фрагмент.

person Rohan    schedule 30.06.2015