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

123

Я не могу повторно использовать фрагмент в 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)); 
Каника
источник
3
Есть ли какая-то конкретная причина, по которой вы отказались destroyItem()? В этом нет необходимости.
CommonsWare
для повторной инициализации используйте FragmentStatePagerAdapter, также вызовите, когда вы переопределите его super.destroyItem (container, position, object);
faiziii

Ответы:

306

KISS Ответ:

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

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

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

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

Каника
источник
Большое спасибо. Ваш ответ мне очень помог.
Priya
1
Ненавижу быть другим «я тоже!» пост, но да>. <Спасибо, что не удалили вопрос.
Paul Ruiz
34
Причина, по которой это работает, заключается в том, что FragmentStatePagerAdapter уничтожает как неиспользуемые фрагменты. FragmentPagerAdapter этого не делает.
BlackHatSamurai
3
Просто на будущее для тех, кто может найти это при поиске конкретной проблемы, с которой они столкнулись; прочтите как FragmentPagerAdapter, так и FragmentStatePagerAdapter. Они ведут себя по-разному по какой-то причине, и ваше конкретное использование может потребовать одного вместо другого.
Крис Стюарт
2
@najibputhawala Я использовал FragmentStatePagerAdapter, но все еще сталкивался с той же проблемой. getItem () не
вызывается
168

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

FragmentPagerAdapter adapter = new FragmentPagerAdapter(getChildFragmentManager());

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

  • Однако имейте в виду, что для использования getChildFragmentManager()минимальная версия API должна быть как минимум 17 (4.2), так что это может помешать вам. Конечно, если вы используете фрагменты из библиотеки поддержки v4, все будет в порядке.
Jraco11
источник
25
Это правильный ответ. Проблема заключается в том, что фрагменты, вложенные в другие фрагменты, должны использовать getChildrenFragmentManager () вместо getFragmentManager ().
shihpeng
Большое спасибо, мне потребовалась целая вечность, чтобы найти этот ответ!
Шпонголоид
Я согласен с @shihpeng. Это должен быть правильный ответ.
Раймонд Луканта
Это было исправлением для меня. Большое спасибо за ответ
user3734429
Документация действительно должна указать это в процессе прохождения. Очень реально, что ViewPager будет загружен внутри фрагмента. Спасибо, что разместили этот ответ.
работает
7

Override long getItemId (int position)

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

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

long getItemId (int position)

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

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

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

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

Vedant
источник
Это был правильный ответ. Мне пришлось предоставить разные идентификаторы для фрагментов в getItemIdИ настроить, getItemPositionчтобы вернуть, POSITION_NONEЕСЛИ фрагмент должен быть удален. Для этого у меня есть флаг enum. После этого getItemбудет называться.
Мурат Карагёз,
Спасибо @ MuratKaragöz за +50 :)
vedant
5

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

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

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

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

Хорхе Касариего
источник
2

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

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

Мэдди
источник
2

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

pagerAdapter.instantiateItem(viewPager, TAB_POS)
В-гангстер
источник
0

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

Оливер Диксон
источник