FragmentPagerAdapter getItem не вызывается

Я не могу повторно использовать фрагмент в FragmentPagerAdapter. Используя метод destroyItem(), он удаляет фрагмент, но по-прежнему не вызывает getItem() снова. Есть всего 2-3 изображения, поэтому я использую FragmentPagerAdapter вместо FragmentStatePagerAdapter..

public class ExamplePagerAdapter extends FragmentPagerAdapter {

    ArrayList < String > urls;
    int size = 0;
    public ExamplePagerAdapter(FragmentManager fm, ArrayList < String > res) {
        super(fm);
        urls = res;
        size = urls.size();
    }

    @Override
    public int getCount() {
        if (urls == null) {
            return 0;
        } else {
            return size;
        }

    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        FragmentManager manager = ((Fragment) object).getFragmentManager();
        FragmentTransaction trans = manager.beginTransaction();
        trans.remove((Fragment) object);
        trans.commit();
    }

    @Override
    public Fragment getItem(int position) {

        Fragment fragment = new FloorPlanFragment();
        Bundle b = new Bundle();
        b.putInt("p", position);
        b.putString("image", urls.get(position));
        Log.i("image", "" + urls.get(position));
        fragment.setArguments(b);
        return fragment;
    }
}

И в FragmentActivity,

pager.setAdapter(new ExamplePagerAdapter(getSupportFragmentManager(), res2)); 

person Kanika    schedule 25.09.2012    source источник
comment
Есть ли особая причина, по которой вы отменили destroyItem()? В этом нет необходимости.   -  person CommonsWare    schedule 25.09.2012
comment
для повторной инициализации используйте вызов FragmentStatePagerAdapter, когда вы переопределяете его super.destroyItem (контейнер, позиция, объект);   -  person faiziii    schedule 30.01.2015


Ответы (7)


ПОЦЕЛУЙ Ответ:

Простое использование FragmentStatePagerAdapter вместо FragmentPagerAdapter.

Я получил ответ. Сначала я решил удалить этот вопрос, так как делаю очень глупую ошибку, но этот ответ поможет тому, кто сталкивается с той же проблемой, что и вместо FragmentPagerAdapter используйте FragmentStatePagerAdapter.

Как отметил @BlackHatSamurai в комментарии:

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

person Kanika    schedule 25.09.2012
comment
Большое спасибо. Ваш ответ мне очень помог. - person Priya; 26.06.2013
comment
Ненавижу быть еще одним «я тоже!» сообщение, но да ›.‹ Спасибо, что не удалили вопрос. - person Paul Ruiz; 10.07.2013
comment
Мое предположение было бы чем-то вроде фрагментов, сбрасываемых в мусорную корзину для последующего использования при уничтожении, так что, когда создается новый пейджер, он заполняется переработанными фрагментами. Вероятно, это также можно исправить, не помещая какой-либо код, специфичный для контента, в вызов getItem (например, установка изображения на основе переменных пейджеров, массивов и т. Д.) - person Glenn.nz; 31.07.2013
comment
Причина, по которой это работает, заключается в том, что FragmentStatePagerAdapter уничтожает фрагменты, которые не используются. FragmentPagerAdapter — нет. - person BlackHatSamurai; 06.10.2013
comment
@ Блейн, спасибо, ты очистил мой разум. Кстати, спасибо братан, ты спас меня от большой проблемы. - person alicanbatur; 17.02.2014
comment
Просто для справки в будущем для тех, кто может найти это при поиске конкретной проблемы, с которой они столкнулись; прочитайте как FragmentPagerAdapter, так и FragmentStatePagerAdapter. Они ведут себя по-разному по какой-то причине, и для вашего конкретного использования может потребоваться одно вместо другого. - person Chris Stewart; 02.03.2014
comment
@najibputhawala Я использовал FragmentStatePagerAdapter, но все еще сталкиваюсь с той же проблемой. getItem() не вызывается - person sam_k; 17.06.2014
comment
Спасибо за ваш ответ. На самом деле все сделали глупую ошибку :D - person Olkunmustafa; 19.02.2015
comment
Спасибо, что поделились своим ответом, вы сэкономили мне много времени. +1 - person Corbella; 03.08.2015
comment
@Kanika, что такое ответ на поцелуй? - person Rohan Bhatia; 27.06.2017
comment
Спасибо, что поделились этим ответом, потратил почти 2 часа на отладку, пробуя разные вещи. - person Sam; 22.08.2017
comment
У меня есть эта проблема даже с вашим решением. - person Mahdi; 12.06.2019
comment
Спасибо за то, что поделился этим. - person developer; 02.10.2020

Использование FragmentStatePagerAdapter не полностью решило мою проблему, которая была аналогичной проблемой, когда onCreateView не вызывался для дочерних фрагментов в пейджере просмотра. На самом деле я вкладываю свой FragmentPagerAdapter в другой Fragment, поэтому FragmentManager был общим для всех них и, таким образом, сохранял экземпляры старых фрагментов. Исправление заключалось в том, чтобы вместо этого передать экземпляр getChildFragmentManager конструктору FragmentPagerAdapter в моем фрагменте хоста. Что-то типа...

FragmentPagerAdapter adapter = new FragmentPagerAdapter(getChildFragmentManager());

Метод getChildFragmentManager() доступен через фрагмент, и это сработало для меня, потому что он возвращает частный FragmentManager для этого фрагмента специально для ситуаций, в которых необходимы вложенные фрагменты. Я надеюсь, что это поможет кому-то, у кого может быть такая же проблема, как у меня!!

  • Однако имейте в виду, что для использования getChildFragmentManager() ваша минимальная версия API должна быть не ниже 17 (4.2), так что это может поставить вас в тупик. Конечно, если вы используете фрагменты из библиотеки поддержки v4, все должно быть в порядке.
person Jraco11    schedule 16.04.2015
comment
Это правильный ответ. Проблема связана с тем, что фрагменты, вложенные в другие фрагменты, должны использовать getChildrenFragmentManager() вместо getFragmentManager(). - person shihpeng; 05.08.2015
comment
Большое спасибо, мне потребовалась целая вечность, чтобы найти этот ответ! - person Shpongoloid; 13.08.2015
comment
Я согласен с @shihpeng. Это должен быть правильный ответ. - person Raymond Lukanta; 29.09.2015
comment
Это было исправлением для меня. Большое спасибо за отправку ответа - person user3734429; 30.09.2015
comment
Документы действительно должны называть это в пошаговом руководстве. Вполне реально, что ViewPager будет загружен внутри фрагмента. Спасибо за публикацию этого ответа. - person worked; 11.11.2015
comment
Отличное объяснение. Это именно то, что случилось со мной. Спасибо! - person Kim Montano; 11.12.2015
comment
Здорово! Вы спасаете мою жизнь! - person BurtK; 13.07.2016
comment
Большое спасибо за этот ответ, я действительно не знал, что еще делать, но это исправило: D, спасибо, спасибо: D - person Stephy Samaniego; 30.11.2016
comment
В моем случае мне пришлось использовать оба решения - person Yoann Hercouet; 23.05.2017
comment
У меня был пейджер просмотра внутри пейджера просмотра, и это было именно то, что меня беспокоило. Спасибо! - person box; 24.08.2017
comment
Большое спасибо за объяснение. - person Brajendra Pandey; 13.07.2018
comment
Это удерживало меня больше суток, я люблю тебя. - person Nathan F.; 27.11.2018
comment
Это правильно объясненный ответ. Респект и большое спасибо - person Sachchidanand; 08.05.2019
comment
В том же случае с вложенным фрагментом у меня все еще есть проблема. В моем случае мои последние элементы (например, 9,10) getItem не вызываются! это очень странно. - person Mahdi; 12.06.2019
comment
у меня не работает, потому что это: adapter = new MyAdapter(ChildFragmentManager); вызовет: Ошибка CS1503 Аргумент 1: невозможно преобразовать из «Android.App.FragmentManager» в «Android.Support.V4.App.FragmentManager» - person Altivo; 27.08.2020

Переопределить long getItemId (int position)

FragmentPagerAdapter кэширует фрагменты, которые создает с помощью getItem. Я столкнулся с той же проблемой - даже после вызова notifyDataSetChanged() getItem не вызывался.

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

long getItemId (int position)

Возвращает уникальный идентификатор элемента в заданной позиции.

Реализация по умолчанию возвращает заданную позицию. Подклассы должны переопределять этот метод, если позиции элементов могут измениться.

Просто укажите уникальный идентификатор для каждого фрагмента, и все готово.

Использовать FragementStatePagerAdapter или возвращать POSITION_NONE в int getItemPosition (Object object) неправильно. Никакого кеширования вы не получите.

person vedant    schedule 16.02.2018
comment
Это был правильный ответ. Мне пришлось указать разные идентификаторы для фрагментов в getItemId И настроить getItemPosition, чтобы вернуть POSITION_NONE, ЕСЛИ фрагмент должен быть удален. У меня есть флаг перечисления для этого. После этого будет вызван getItem. - person Murat Karagöz; 17.01.2020
comment
Спасибо @MuratKaragöz за +50 :) - person vedant; 20.01.2020

Я сделал то, что написали @kanika и @Jraco11, но проблема осталась.

Итак, после множества изменений я нашел тот, который у меня работал, и добавил в свой FragmentPagerAdapter следующий код:

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

Согласно тому, что я прочитал, getItemPosition используется для уведомления ViewPager о том, следует ли обновлять элемент, и для предотвращения обновлений, если элементы в видимых позициях не изменились. .

person Jorge Casariego    schedule 28.04.2016

Есть два разных сценария: 1.) У вас один и тот же макет для каждого пейджера: в этом случае будет лучше, если вы расширите свой пользовательский адаптер с помощью PagerAdapter и вернете один макет.

2.) У вас есть разные макеты для каждого пейджера: в этом случае будет лучше, если вы расширите свой собственный адаптер с помощью FragmentStatePagerAdapter и вернете разные фрагменты для каждого пейджера.

person Maddy    schedule 21.01.2015

метод getItem() используется только для создания новых элементов. После их создания этот метод вызываться не будет. Если вам нужно получить элемент, который является валютой, используемой адаптером, используйте этот метод:

pagerAdapter.instantiateItem(viewPager, TAB_POS)
person B-GangsteR    schedule 30.10.2018

Я обнаружил, что установка прослушивателя на вкладке-макете остановила вызов этого, вероятно, потому, что у них есть место только для одного слушателя на tabLayout.setOnTabSelectedListener вместо массива слушателей.

person Oliver Dixon    schedule 04.02.2016