Возврат к FragmentPagerAdapter -> фрагменты пусты

У меня есть фрагмент (я назову его pagerFragment), который добавлен в задний стек и виден. Он содержит viewPager с FragmentPagerAdapter. FragmentPagerAdapter содержит (скажем) два фрагмента: A и B.

Первое добавление фрагментов отлично работает.

Фрагмент A имеет кнопку, которая после нажатия добавляет фрагмент (C) в стопку.

Проблема в следующем: если я добавлю этот фрагмент (C), а затем щелкну назад, pagerAdapter будет пустым, и я не смогу увидеть какие-либо фрагменты внутри.

Если я использую хак и уничтожаю дочерние фрагменты (A и B) в pagerFragments onDestroyView(), это решает проблему, хотя я не хочу использовать этот хак.

Любые идеи, в чем может быть проблема?


person Amit Ishai    schedule 16.07.2013    source источник
comment
Возможный дубликат фрагмента в ViewPager с использованием FragmentPagerAdapter пусто при втором просмотре   -  person blahdiblah    schedule 17.06.2016


Ответы (5)


У меня такая же проблема. Решение для меня было простым:

в onCreateView у меня было:

// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(getActivity()
    .getSupportFragmentManager());

где SectionPageAdapter выглядит примерно так:

class SectionsPagerAdapter extends FragmentPagerAdapter {
...
}

после изменения getSupportFragmentManager на

mSectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager());

он начал работать! Надеюсь это поможет.

person Mike Mitterer    schedule 18.09.2013
comment
getChildFragmentManager() работает только с 17+ Android SDK. :( - person Sachin Shelke; 10.03.2014
comment
@SachinShelke тогда вам нужно использовать библиотеку поддержки. ;) developer.android.com/ ссылка/android/поддержка/v4/приложение/ - person Sufian; 05.06.2014
comment
@mike-mitterer, отличный ответ, ты потрясающий, большое спасибо - person Tom; 29.07.2014
comment
@Mike Mitterer: я попробовал это и получил сообщение «Нет представления для FragmentC», потому что в диспетчере дочерних фрагментов не существует макета кадра с этим идентификатором. диспетчер фрагментов, который распознает этот идентификатор, — это getSupportFragmentManager(), определенный в действии. - person HukeLau_DABA; 02.10.2014
comment
Боже мой, я потратил 3 часа на эту проблему. Это исправление сработало отлично. Я только что потерял несколько часов, которых больше никогда не увижу. фмл - person Laith Alnagem; 29.01.2015
comment
Кто-нибудь может объяснить, почему getSupportFragmentManager() не работает, а getChildFragmentManager() работает? Как nested просмотры нажимают назад? Есть ли у этого побочный эффект? - person aandis; 04.04.2015
comment
Потрясающий ответ! Но может кто-нибудь объяснить, зачем это нужно? - person Renan Ferreira; 07.07.2015
comment
Круто, дорогая, спасибо! - person Neo; 25.10.2015
comment
Спасибо, Майк, я потратил 4 часа, пытаясь решить это без понятия, и ты спас меня. Я тебя люблю. - person Highway62; 09.01.2016
comment
Большое тебе спасибо! Вы сэкономили мне много часов - person Nava; 14.06.2016
comment
Привет, Майк, любое решение для устройства ниже 17. потому что мое приложение min ver-16? - person Magesh Pandian; 22.05.2017
comment
Отличный ответ. Это должно быть в моих 5 основных причинах, по которым следует отказаться от фрагментов (по крайней мере, в новых кодовых базах). - person Eric Bachhuber; 12.06.2017
comment
Отлично! Это спасло мою двухдневную борьбу за 2 минуты. Спасибо, бро! - person Thunder Dragon; 07.06.2018

Похоже, вы используете вложенные фрагменты, поскольку ваш ViewPager находится внутри PagerFragment. Вы передали getChildFragmentManager() конструктору вашего FragmentPagerAdapter? Если нет, вы должны.

Я не думаю, что вам нужен FragmentStatePagerAdapter, но я бы попробовал, поскольку он обрабатывает сохранение и восстановление состояния фрагмента. Тот факт, что ваш хак onDestroyView() работает, заставляет меня думать, что вам может понадобиться FragmentStatePagerAdapter.

Это также может быть связано с тем, как FragmentPagerAdapter добавляет фрагменты. FragmentPagerAdapter не добавляет фрагменты в стек. Представьте, если бы вы добавили более 10 страниц в свой ViewPager, и пользователь пролистал их. Пользователю нужно будет нанести ответный удар 11 раз, чтобы выйти из приложения.

Это также может быть связано с этим сообщением: Вложенные фрагменты и задний стек.

Также я не уверен, к чему вы добавляете фрагмент C. Вы добавляете его в тот же контейнер, что и ViewPager?

Ну, по крайней мере, у вас есть несколько вариантов для расследования. В таких ситуациях мне нравится отлаживать исходный код Android SDK и смотреть, что вызывает такое поведение. Я рекомендую взять исходный код AOSP и добавить frameworks/support и frameworks/base в качестве источников SDK. . Это единственный верный способ понять, что происходит, и избежать случайных изменений, пока все не заработает.

person Pierre-Antoine LaFayette    schedule 22.08.2013

Используйте getChildFragmentManager() вместо getSupportFragmentManager(). Это будет работать нормально.

person vijay rathore    schedule 15.12.2017

Я только что столкнулся с проблемой в нашем проекте. Основная причина заключается в том, как работает FragmentPagerAdapter:

FragmentPagerAdapter просто отсоединяет фрагмент, который ему в данный момент не нужен, из своего представления, но не удаляет его из своего FragmentManager. Когда он хочет снова отобразить фрагмент, он проверяет, содержит ли FragmentManager фрагмент, используя тег, созданный из идентификатора представления ViewPager и идентификатора, возвращаемого вызовом адаптера getItemId(position). Если он находит фрагмент, он просто планирует присоединение фрагмента к его представлению в рамках транзакции обновления FragmentManager. Только если он не находит Фрагмент таким образом, он создает новый, используя вызов адаптера getItem(position)!

Проблема с фрагментом, содержащим ViewPager с FragmentPagerAdapter, заключается в том, что содержимое FragmentManager никогда не очищается, когда содержащий фрагмент помещается в задний стек. Если содержащий фрагмент возвращается из заднего стека, он создает новое представление, но FragmentManager по-прежнему содержит фрагменты, которые были прикреплены к старому представлению, и присоединение существующего фрагмента больше не работает.

Самый простой способ избавиться от этой проблемы — избегать вложенных фрагментов. :)

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

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

public class MyPagerAdapter extends FragmentPagerAdapter {

private static int COUNT = ...;
private final FragmentManager fragmentManager;
private Fragment[] subFragments = new Fragment[COUNT];
private FragmentTransaction cleanupTransaction;

public MyPagerAdapter(FragmentManager fragmentManager) {
    super(fragmentManager);
    this.fragmentManager = fragmentManager;
}

@Override
public Fragment getItem(int position) {
    return getSubFragmentAtPosition(position);
}

@Override
public int getCount() {
    return COUNT;
}

@Override
public long getItemId(int position) {
    return getSubFragmentAtPosition(position).hashCode();
}

//The next three methods are needed to remove fragments no longer used from the fragment manager
@Override
public void startUpdate(ViewGroup container) {
    super.startUpdate(container);
    cleanupTransaction = fragmentManager.beginTransaction();
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    cleanupTransaction.remove((Fragment) object);
}

@Override
public void finishUpdate(ViewGroup container) {
    super.finishUpdate(container);
    cleanupTransaction.commit();
}

private Fragment getSubFragmentAtPosition(int position){
    if (subFragments[position] == null){
        subFragments[position] = ...;
    }
    return subFragments[position];
}

}

person Nantoka    schedule 21.11.2017

У меня была такая же проблема, просто два раза сразу поставил адаптер и все.

Пример кода:

private fun displayImg(photo1:String, photo2:String){
    val pager:ViewPager = v?.findViewById(R.id.ProductImgPager)!!
    val arr = ArrayList<String>()
    arr.add(photo1)
    arr.add(photo2)
    pager.adapter = AdapterImageView(fm, arr ,arr.size)
    pager.adapter = AdapterImageView(fm, arr ,arr.size)

}
person Biplob Das    schedule 19.03.2020